Skip to contentSkip to conversation

Don't attach callback to a going-away netlink socket

PATCH In review Pavel Emelianov 3 participants 5 messages Apr 16, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Don't attach callback to a going-away netlink socket

From: Denis Lunev <[email protected]>

There is a race between netlink_dump_start() and netlink_release() that can lead to the situation when a netlink socket with non-zero callback is freed.

net/netlink/af_netlink.c +3 -3
@@ -255,6 +255,7 @@ static int netlink_release(struct socket
 		return 0;
 
 	netlink_remove(sk);
+	sock_orphan(sk);
 	nlk = nlk_sk(sk);
 
 	spin_lock(&nlk->cb_lock);
@@ -269,7 +270,6 @@ static int netlink_release(struct socket
 	/* OK. Socket is unlinked, and, therefore,
 	   no new packets will arrive */
 
-	sock_orphan(sk);
 	sock->sk = NULL;
 	wake_up_interruptible_all(&nlk->wait);
 
@@ -942,9 +942,9 @@ int netlink_dump_start(struct sock *ssk,
 		return -ECONNREFUSED;
 	}
 	nlk = nlk_sk(sk);
-	/* A dump is in progress... */
+	/* A dump or destruction is in progress... */
 	spin_lock(&nlk->cb_lock);
-	if (nlk->cb) {
+	if (nlk->cb || sock_flag(sk, SOCK_DEAD)) {
 		spin_unlock(&nlk->cb_lock);
 		netlink_destroy_callback(cb);
 		sock_put(sk);
#1 lore raw
Quoted 5 lines · Pavel Emelianov

From: Denis Lunev <[email protected]>

There is a race between netlink_dump_start() and netlink_release() that can lead to the situation when a netlink socket with non-zero callback is freed.

Can you describe the race in more detail please?

#2 lore raw
Quoted 11 lines · Patrick McHardy
Quoted 5 lines · Pavel Emelianov

From: Denis Lunev <[email protected]>

There is a race between netlink_dump_start() and netlink_release() that can lead to the situation when a netlink socket with non-zero callback is freed.

Can you describe the race in more detail please?

Here it is:

CPU1:                           CPU2
netlink_release():              netlink_dump_start():
                                sk = netlink_lookup(); /* OK */

netlink_remove();

spin_lock(&nlk->cb_lock);
if (nlk->cb) { /* false */
...
}
spin_unlock(&nlk->cb_lock);

                                spin_lock(&nlk->cb_lock);
                                if (nlk->cb) { /* false */
                                         ...
                                }
                                nlk->cb = cb;
                                spin_unlock(&nlk->cb_lock);
                                ...

sock_orphan(sk);
/*
* proceed with releasing
* the socket
*/

The proposal it to make sock_orphan before detaching the callback in netlink_release() and to check for the sock to be SOCK_DEAD in netlink_dump_start() before setting a new callback.

#3 lore raw
Quoted 10 lines · Pavel Emelianov
Quoted 7 lines · Patrick McHardy
Quoted 3 lines

There is a race between netlink_dump_start() and netlink_release() that can lead to the situation when a netlink socket with non-zero callback is freed.

Can you describe the race in more detail please?

Quoted 6 lines

Here it is:

[...]
The proposal it to make sock_orphan before detaching the callback in netlink_release() and to check for the sock to be SOCK_DEAD in netlink_dump_start() before setting a new callback.

Thanks, good catch. Your patch also looks good.