forked from mirrors/linux
		
	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>
			
			
This commit is contained in:
		
							parent
							
								
									0d53072aa4
								
							
						
					
					
						commit
						86741ec254
					
				
					 3 changed files with 25 additions and 1 deletions
				
			
		|  | @ -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; | ||||||
|  | @ -1664,6 +1665,7 @@ 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); | ||||||
| } | } | ||||||
|  | @ -1671,6 +1673,11 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) | ||||||
| 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(); | ||||||
|  |  | ||||||
|  | @ -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, | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								net/socket.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								net/socket.c
									
									
									
									
									
								
							|  | @ -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, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Lorenzo Colitti
						Lorenzo Colitti