net: core: Add a UID field to struct sock.
authorLorenzo Colitti <lorenzo@google.com>
Thu, 3 Nov 2016 17:23:41 +0000 (02:23 +0900)
committerAmit Pundir <amit.pundir@linaro.org>
Mon, 2 Jan 2017 08:36:41 +0000 (14:06 +0530)
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.

Bug: 16355602
Change-Id: Idbc3e9a0cec91c4c6e01916b967b6237645ebe59
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sock.h
net/core/sock.c
net/socket.c

index 8f77df63a8f46670d8ff9be2be3b62d4e76032f8..62c9e2268d635d1341133df6f0cfe0c4c8978a02 100644 (file)
@@ -446,6 +446,7 @@ struct sock {
        void                    *sk_security;
 #endif
        __u32                   sk_mark;
+       kuid_t                  sk_uid;
 #ifdef CONFIG_CGROUP_NET_CLASSID
        u32                     sk_classid;
 #endif
@@ -1692,6 +1693,7 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
        sk->sk_wq = parent->wq;
        parent->sk = sk;
        sk_set_socket(sk, parent);
+       sk->sk_uid = SOCK_INODE(parent)->i_uid;
        security_sock_graft(sk, parent);
        write_unlock_bh(&sk->sk_callback_lock);
 }
@@ -1699,6 +1701,11 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
 kuid_t sock_i_uid(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)
 {
        u32 v = prandom_u32();
index f4c0917e66b5f8cad1cec9a7b93e84b67cfe1006..f367df38c264532a582b8135becd858b4368c03d 100644 (file)
@@ -2384,8 +2384,11 @@ void sock_init_data(struct socket *sock, struct sock *sk)
                sk->sk_type     =       sock->type;
                sk->sk_wq       =       sock->wq;
                sock->sk        =       sk;
-       } else
+               sk->sk_uid      =       SOCK_INODE(sock)->i_uid;
+       } else {
                sk->sk_wq       =       NULL;
+               sk->sk_uid      =       make_kuid(sock_net(sk)->user_ns, 0);
+       }
 
        rwlock_init(&sk->sk_callback_lock);
        lockdep_set_class_and_name(&sk->sk_callback_lock,
index 0090225eeb1e973418bc391fde9eff971c784379..66d984ac29917200ac65258a220eee1b5201c3d3 100644 (file)
@@ -520,9 +520,23 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
        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 = {
        .getxattr = sockfs_getxattr,
        .listxattr = sockfs_listxattr,
+       .setattr = sockfs_setattr,
 };
 
 /**