Skip to content

Commit

Permalink
[NETLINK]: Fix two socket hashing bugs.
Browse files Browse the repository at this point in the history
1) netlink_release() should only decrement the hash entry
   count if the socket was actually hashed.

   This was causing hash->entries to underflow, which
   resulting in all kinds of troubles.

   On 64-bit systems, this would cause the following
   conditional to erroneously trigger:

	err = -ENOMEM;
	if (BITS_PER_LONG > 32 && unlikely(hash->entries >= UINT_MAX))
		goto err;

2) netlink_autobind() needs to propagate the error return from
   netlink_insert().  Otherwise, callers will not see the error
   as they should and thus try to operate on a socket with a zero pid,
   which is very bad.

   However, it should not propagate -EBUSY.  If two threads race
   to autobind the socket, that is fine.  This is consistent with the
   autobind behavior in other protocols.

   So bug Freescale#1 above, combined with this one, resulted in hangs
   on netlink_sendmsg() calls to the rtnetlink socket.  We'd try
   to do the user sendmsg() with the socket's pid set to zero,
   later we do a socket lookup using that pid (via the value we
   stashed away in NETLINK_CB(skb).pid), but that won't give us the
   user socket, it will give us the rtnetlink socket.  So when we
   try to wake up the receive queue, we dive back into rtnetlink_rcv()
   which tries to recursively take the rtnetlink semaphore.

Thanks to Jakub Jelink for providing backtraces.  Also, thanks to
Herbert Xu for supplying debugging patches to help track this down,
and also finding a mistake in an earlier version of this fix.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Jun 26, 2005
1 parent 32e9e25 commit d470e3b
Showing 1 changed file with 8 additions and 3 deletions.
11 changes: 8 additions & 3 deletions net/netlink/af_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ static int netlink_insert(struct sock *sk, u32 pid)
static void netlink_remove(struct sock *sk)
{
netlink_table_grab();
nl_table[sk->sk_protocol].hash.entries--;
sk_del_node_init(sk);
if (sk_del_node_init(sk))
nl_table[sk->sk_protocol].hash.entries--;
if (nlk_sk(sk)->groups)
__sk_del_bind_node(sk);
netlink_table_ungrab();
Expand Down Expand Up @@ -429,7 +429,12 @@ static int netlink_autobind(struct socket *sock)
err = netlink_insert(sk, pid);
if (err == -EADDRINUSE)
goto retry;
return 0;

/* If 2 threads race to autobind, that is fine. */
if (err == -EBUSY)
err = 0;

return err;
}

static inline int netlink_capable(struct socket *sock, unsigned int flag)
Expand Down

0 comments on commit d470e3b

Please sign in to comment.