mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	unix_diag: Dumping exact socket core
The socket inode is used as a key for lookup. This is effectively the only really unique ID of a unix socket, but using this for search currently has one problem -- it is O(number of sockets) :( Does it worth fixing this lookup or inventing some other ID for unix sockets? Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									45a96b9be6
								
							
						
					
					
						commit
						5d3cae8bc3
					
				
					 1 changed files with 66 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -89,11 +89,76 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 | 
			
		|||
	return skb->len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sock *unix_lookup_by_ino(int ino)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct sock *sk;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&unix_table_lock);
 | 
			
		||||
	for (i = 0; i <= UNIX_HASH_SIZE; i++) {
 | 
			
		||||
		struct hlist_node *node;
 | 
			
		||||
 | 
			
		||||
		sk_for_each(sk, node, &unix_socket_table[i])
 | 
			
		||||
			if (ino == sock_i_ino(sk)) {
 | 
			
		||||
				sock_hold(sk);
 | 
			
		||||
				spin_unlock(&unix_table_lock);
 | 
			
		||||
 | 
			
		||||
				return sk;
 | 
			
		||||
			}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock(&unix_table_lock);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int unix_diag_get_exact(struct sk_buff *in_skb,
 | 
			
		||||
			       const struct nlmsghdr *nlh,
 | 
			
		||||
			       struct unix_diag_req *req)
 | 
			
		||||
{
 | 
			
		||||
	return -EAFNOSUPPORT;
 | 
			
		||||
	int err = -EINVAL;
 | 
			
		||||
	struct sock *sk;
 | 
			
		||||
	struct sk_buff *rep;
 | 
			
		||||
	unsigned int extra_len;
 | 
			
		||||
 | 
			
		||||
	if (req->udiag_ino == 0)
 | 
			
		||||
		goto out_nosk;
 | 
			
		||||
 | 
			
		||||
	sk = unix_lookup_by_ino(req->udiag_ino);
 | 
			
		||||
	err = -ENOENT;
 | 
			
		||||
	if (sk == NULL)
 | 
			
		||||
		goto out_nosk;
 | 
			
		||||
 | 
			
		||||
	err = sock_diag_check_cookie(sk, req->udiag_cookie);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	extra_len = 256;
 | 
			
		||||
again:
 | 
			
		||||
	err = -ENOMEM;
 | 
			
		||||
	rep = alloc_skb(NLMSG_SPACE((sizeof(struct unix_diag_msg) + extra_len)),
 | 
			
		||||
			GFP_KERNEL);
 | 
			
		||||
	if (!rep)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).pid,
 | 
			
		||||
			   nlh->nlmsg_seq, 0, req->udiag_ino);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		kfree_skb(rep);
 | 
			
		||||
		extra_len += 256;
 | 
			
		||||
		if (extra_len >= PAGE_SIZE)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		goto again;
 | 
			
		||||
	}
 | 
			
		||||
	err = netlink_unicast(sock_diag_nlsk, rep, NETLINK_CB(in_skb).pid,
 | 
			
		||||
			      MSG_DONTWAIT);
 | 
			
		||||
	if (err > 0)
 | 
			
		||||
		err = 0;
 | 
			
		||||
out:
 | 
			
		||||
	if (sk)
 | 
			
		||||
		sock_put(sk);
 | 
			
		||||
out_nosk:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue