diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2016-11-03 13:23:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-04 14:45:22 -0400 |
commit | 86741ec25462e4c8cdce6df2f41ead05568c7d5e (patch) | |
tree | f6eb304465cbe0fc8309fe6593de0ab996756fda | |
parent | 0d53072aa42b3cdc340a0d483febd14f2d68da52 (diff) |
net: core: Add a UID field to struct sock.
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>
-rw-r--r-- | include/net/sock.h | 7 | ||||
-rw-r--r-- | net/core/sock.c | 5 | ||||
-rw-r--r-- | net/socket.c | 14 |
3 files changed, 25 insertions, 1 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index 93331a1492db..cf617ee16723 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -419,6 +419,7 @@ struct sock { | |||
419 | u32 sk_max_ack_backlog; | 419 | u32 sk_max_ack_backlog; |
420 | __u32 sk_priority; | 420 | __u32 sk_priority; |
421 | __u32 sk_mark; | 421 | __u32 sk_mark; |
422 | kuid_t sk_uid; | ||
422 | struct pid *sk_peer_pid; | 423 | struct pid *sk_peer_pid; |
423 | const struct cred *sk_peer_cred; | 424 | const struct cred *sk_peer_cred; |
424 | long sk_rcvtimeo; | 425 | long sk_rcvtimeo; |
@@ -1664,6 +1665,7 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) | |||
1664 | sk->sk_wq = parent->wq; | 1665 | sk->sk_wq = parent->wq; |
1665 | parent->sk = sk; | 1666 | parent->sk = sk; |
1666 | sk_set_socket(sk, parent); | 1667 | sk_set_socket(sk, parent); |
1668 | sk->sk_uid = SOCK_INODE(parent)->i_uid; | ||
1667 | security_sock_graft(sk, parent); | 1669 | security_sock_graft(sk, parent); |
1668 | write_unlock_bh(&sk->sk_callback_lock); | 1670 | write_unlock_bh(&sk->sk_callback_lock); |
1669 | } | 1671 | } |
@@ -1671,6 +1673,11 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) | |||
1671 | kuid_t sock_i_uid(struct sock *sk); | 1673 | kuid_t sock_i_uid(struct sock *sk); |
1672 | unsigned long sock_i_ino(struct sock *sk); | 1674 | unsigned long sock_i_ino(struct sock *sk); |
1673 | 1675 | ||
1676 | static inline kuid_t sock_net_uid(const struct net *net, const struct sock *sk) | ||
1677 | { | ||
1678 | return sk ? sk->sk_uid : make_kuid(net->user_ns, 0); | ||
1679 | } | ||
1680 | |||
1674 | static inline u32 net_tx_rndhash(void) | 1681 | static inline u32 net_tx_rndhash(void) |
1675 | { | 1682 | { |
1676 | u32 v = prandom_u32(); | 1683 | u32 v = prandom_u32(); |
diff --git a/net/core/sock.c b/net/core/sock.c index d8e4532e89e7..40dbc13453f9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -2460,8 +2460,11 @@ void sock_init_data(struct socket *sock, struct sock *sk) | |||
2460 | sk->sk_type = sock->type; | 2460 | sk->sk_type = sock->type; |
2461 | sk->sk_wq = sock->wq; | 2461 | sk->sk_wq = sock->wq; |
2462 | sock->sk = sk; | 2462 | sock->sk = sk; |
2463 | } else | 2463 | sk->sk_uid = SOCK_INODE(sock)->i_uid; |
2464 | } else { | ||
2464 | sk->sk_wq = NULL; | 2465 | sk->sk_wq = NULL; |
2466 | sk->sk_uid = make_kuid(sock_net(sk)->user_ns, 0); | ||
2467 | } | ||
2465 | 2468 | ||
2466 | rwlock_init(&sk->sk_callback_lock); | 2469 | rwlock_init(&sk->sk_callback_lock); |
2467 | lockdep_set_class_and_name(&sk->sk_callback_lock, | 2470 | lockdep_set_class_and_name(&sk->sk_callback_lock, |
diff --git a/net/socket.c b/net/socket.c index 970a7ea3fc4a..4ce33c35e606 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -518,8 +518,22 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, | |||
518 | return used; | 518 | return used; |
519 | } | 519 | } |
520 | 520 | ||
521 | int sockfs_setattr(struct dentry *dentry, struct iattr *iattr) | ||
522 | { | ||
523 | int err = simple_setattr(dentry, iattr); | ||
524 | |||
525 | if (!err) { | ||
526 | struct socket *sock = SOCKET_I(d_inode(dentry)); | ||
527 | |||
528 | sock->sk->sk_uid = iattr->ia_uid; | ||
529 | } | ||
530 | |||
531 | return err; | ||
532 | } | ||
533 | |||
521 | static const struct inode_operations sockfs_inode_ops = { | 534 | static const struct inode_operations sockfs_inode_ops = { |
522 | .listxattr = sockfs_listxattr, | 535 | .listxattr = sockfs_listxattr, |
536 | .setattr = sockfs_setattr, | ||
523 | }; | 537 | }; |
524 | 538 | ||
525 | /** | 539 | /** |