Navigation Menu

Skip to content

Commit

Permalink
net: core: Add a UID field to struct sock.
Browse files Browse the repository at this point in the history
Protocol sockets (struct sock) don't have UIDs, but most of the
time, they map 1:1 to userspace sockets (struct socket) which do.

Various operations such as the iptables xt_owner match need
access to the "UID of a socket", and do so by following the
backpointer to the struct socket. This involves taking
sk_callback_lock and doesn't work when there is no socket
because userspace has already called close().

Simplify this by adding a sk_uid field to struct sock whose value
matches the UID of the corresponding struct socket. The semantics
are as follows:

1. Whenever sk_socket is non-null: sk_uid is the same as the UID
   in sk_socket, i.e., matches the return value of sock_i_uid.
   Specifically, the UID is set when userspace calls socket(),
   fchown(), or accept().
2. When sk_socket is NULL, sk_uid is defined as follows:
   - For a socket that no longer has a sk_socket because
     userspace has called close(): the previous UID.
   - For a cloned socket (e.g., an incoming connection that is
     established but on which userspace has not yet called
     accept): the UID of the socket it was cloned from.
   - For a socket that has never had an sk_socket: UID 0 inside
     the user namespace corresponding to the network namespace
     the socket belongs to.

Kernel sockets created by sock_create_kern are a special case
of #1 and sk_uid is the user that created them. For kernel
sockets created at network namespace creation time, such as the
per-processor ICMP and TCP sockets, this is the user that created
the network namespace.

Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
lcolitti authored and davem330 committed Nov 4, 2016
1 parent 0d53072 commit 86741ec
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 1 deletion.
7 changes: 7 additions & 0 deletions include/net/sock.h
Expand Up @@ -419,6 +419,7 @@ struct sock {
u32 sk_max_ack_backlog; u32 sk_max_ack_backlog;
__u32 sk_priority; __u32 sk_priority;
__u32 sk_mark; __u32 sk_mark;
kuid_t sk_uid;
struct pid *sk_peer_pid; struct pid *sk_peer_pid;
const struct cred *sk_peer_cred; const struct cred *sk_peer_cred;
long sk_rcvtimeo; long sk_rcvtimeo;
Expand Down Expand Up @@ -1664,13 +1665,19 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
sk->sk_wq = parent->wq; sk->sk_wq = parent->wq;
parent->sk = sk; parent->sk = sk;
sk_set_socket(sk, parent); sk_set_socket(sk, parent);
sk->sk_uid = SOCK_INODE(parent)->i_uid;
security_sock_graft(sk, parent); security_sock_graft(sk, parent);
write_unlock_bh(&sk->sk_callback_lock); write_unlock_bh(&sk->sk_callback_lock);
} }


kuid_t sock_i_uid(struct sock *sk); kuid_t sock_i_uid(struct sock *sk);
unsigned long sock_i_ino(struct sock *sk); unsigned long sock_i_ino(struct sock *sk);


static inline kuid_t sock_net_uid(const struct net *net, const struct sock *sk)
{
return sk ? sk->sk_uid : make_kuid(net->user_ns, 0);
}

static inline u32 net_tx_rndhash(void) static inline u32 net_tx_rndhash(void)
{ {
u32 v = prandom_u32(); u32 v = prandom_u32();
Expand Down
5 changes: 4 additions & 1 deletion net/core/sock.c
Expand Up @@ -2460,8 +2460,11 @@ void sock_init_data(struct socket *sock, struct sock *sk)
sk->sk_type = sock->type; sk->sk_type = sock->type;
sk->sk_wq = sock->wq; sk->sk_wq = sock->wq;
sock->sk = sk; sock->sk = sk;
} else sk->sk_uid = SOCK_INODE(sock)->i_uid;
} else {
sk->sk_wq = NULL; sk->sk_wq = NULL;
sk->sk_uid = make_kuid(sock_net(sk)->user_ns, 0);
}


rwlock_init(&sk->sk_callback_lock); rwlock_init(&sk->sk_callback_lock);
lockdep_set_class_and_name(&sk->sk_callback_lock, lockdep_set_class_and_name(&sk->sk_callback_lock,
Expand Down
14 changes: 14 additions & 0 deletions net/socket.c
Expand Up @@ -518,8 +518,22 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
return used; return used;
} }


int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
int err = simple_setattr(dentry, iattr);

if (!err) {
struct socket *sock = SOCKET_I(d_inode(dentry));

sock->sk->sk_uid = iattr->ia_uid;
}

return err;
}

static const struct inode_operations sockfs_inode_ops = { static const struct inode_operations sockfs_inode_ops = {
.listxattr = sockfs_listxattr, .listxattr = sockfs_listxattr,
.setattr = sockfs_setattr,
}; };


/** /**
Expand Down

0 comments on commit 86741ec

Please sign in to comment.