aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2016-11-03 13:23:41 -0400
committerDavid S. Miller <davem@davemloft.net>2016-11-04 14:45:22 -0400
commit86741ec25462e4c8cdce6df2f41ead05568c7d5e (patch)
treef6eb304465cbe0fc8309fe6593de0ab996756fda
parent0d53072aa42b3cdc340a0d483febd14f2d68da52 (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.h7
-rw-r--r--net/core/sock.c5
-rw-r--r--net/socket.c14
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)
1671kuid_t sock_i_uid(struct sock *sk); 1673kuid_t sock_i_uid(struct sock *sk);
1672unsigned long sock_i_ino(struct sock *sk); 1674unsigned long sock_i_ino(struct sock *sk);
1673 1675
1676static 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
1674static inline u32 net_tx_rndhash(void) 1681static 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
521int 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
521static const struct inode_operations sockfs_inode_ops = { 534static 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/**