From 7bed585f37d10f62fe7389fdd704d3684d61cdf9 Mon Sep 17 00:00:00 2001
Message-Id: <7bed585f37d10f62fe7389fdd704d3684d61cdf9.1363863447.git.jan@stancek.eu>
From: Jan Stancek <jan@stancek.eu>
Date: Thu, 21 Mar 2013 11:20:18 +0100
Subject: [PATCH] af_unix: fix race in unix_release/unix_dgram_sendmsg

unix_release() will set sock->sk to NULL for server side,
while client may still be at unix_dgram_sendmsg(). When client
now calls security_unix_may_send(), other->sk->sk_security will
cause NULL pointer dereference.

Check that 'other' is not in process of being released.

  [  307.419660] BUG: unable to handle kernel NULL pointer dereference at 0000000000000250
  [  307.428453] IP: [<ffffffff812a2d04>] selinux_socket_unix_may_send+0x34/0x90
  [  307.436258] PGD 422cd8067 PUD 4081b1067 PMD 0
  [  307.441266] Oops: 0000 [#1] SMP
  [  307.558800] CPU 25
  [  307.560953] Pid: 7412, comm: a.out Tainted: GF            3.9.0-rc3 #1 Intel Corporation W2600CR/W2600CR
  [  307.571736] RIP: 0010:[<ffffffff812a2d04>]  [<ffffffff812a2d04>] selinux_socket_unix_may_send+0x34/0x90
  [  307.582240] RSP: 0018:ffff880423c67ab8  EFLAGS: 00010246
  [  307.588171] RAX: ffff8808243a0680 RBX: ffff880423c67be8 RCX: 0000000000000007
  [  307.596139] RDX: 0000000000000000 RSI: ffff88042ef1c380 RDI: ffff880423c67ad8
  [  307.604100] RBP: ffff880423c67b18 R08: ffff88042511e180 R09: 0000000000000000
  [  307.612067] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8808243a0680
  [  307.620034] R13: 7fffffffffffffff R14: ffff88042511e180 R15: ffff88042511e470
  [  307.628001] FS:  00007f19d1bb2740(0000) GS:ffff88082ef20000(0000) knlGS:0000000000000000
  [  307.637028] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  [  307.643437] CR2: 0000000000000250 CR3: 0000000404ff4000 CR4: 00000000000407e0
  [  307.651397] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
  [  307.659358] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
  [  307.667331] Process a.out (pid: 7412, threadinfo ffff880423c66000, task ffff880423600000)
  [  307.676453] Stack:
  [  307.678694]  ffff88042511e102 ffff88042749f600 ffff8808243a0680 ffff88042511e180
  [  307.686990]  ffff88042511e180 000000000000000a ffff880423c67af8 ffffffff8129ef36
  [  307.695284]  ffff880423c67b28 ffffffff81529747 ffff880423c67be8 00000000fdbc1448
  [  307.703584] Call Trace:
  [  307.706332]  [<ffffffff8129ef36>] ? security_sock_rcv_skb+0x16/0x20
  [  307.713339]  [<ffffffff81529747>] ? sk_filter+0x37/0xd0
  [  307.719168]  [<ffffffff8129ef16>] security_unix_may_send+0x16/0x20
  [  307.726075]  [<ffffffff815b694d>] unix_dgram_sendmsg+0x48d/0x640
  [  307.732802]  [<ffffffff814fd9c0>] sock_sendmsg+0xb0/0xe0
  [  307.738732]  [<ffffffff8103edde>] ? physflat_send_IPI_mask+0xe/0x10
  [  307.745726]  [<ffffffff814ff55c>] __sys_sendmsg+0x3ac/0x3c0
  [  307.751961]  [<ffffffff811a3357>] ? do_sync_write+0xa7/0xe0
  [  307.758186]  [<ffffffff811e31fb>] ? fsnotify+0x24b/0x340
  [  307.764120]  [<ffffffff815013c9>] sys_sendmsg+0x49/0x90
  [  307.769966]  [<ffffffff81630b99>] system_call_fastpath+0x16/0x1b
  [  307.776665] Code: 00 00 45 31 c9 48 89 e5 48 83 ec 60 48 8b 56 20 65 48 8b 04 25 28 00 00 00 48 89 45 f8 31 c0 48 8b 47 20 48 8d 7d c0 c6 45 a0 02 <48> 8b b2 50 02 00 00 4c 8b 80 50 02 00 00 31 c0 f3 48 ab 48 89
  [  307.798450] RIP  [<ffffffff812a2d04>] selinux_socket_unix_may_send+0x34/0x90
  [  307.806334]  RSP <ffff880423c67ab8>
  [  307.810223] CR2: 0000000000000250
  [  307.813957] ---[ end trace 0829e3985976c28a ]---

Signed-off-by: Jan Stancek <jan@stancek.eu>
---
 net/unix/af_unix.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 51be64f..433952c 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -993,6 +993,11 @@ restart:
 		if (!unix_may_send(sk, other))
 			goto out_unlock;
 
+		err = -ECONNREFUSED;
+		/* other is being released */
+		if (!other->sk_socket->sk)
+			goto out_unlock;
+
 		err = security_unix_may_send(sk->sk_socket, other->sk_socket);
 		if (err)
 			goto out_unlock;
@@ -1554,6 +1559,11 @@ restart:
 		goto out_unlock;
 
 	if (sk->sk_type != SOCK_SEQPACKET) {
+		err = -ECONNREFUSED;
+		/* other is being released */
+		if (!other->sk_socket->sk)
+			goto out_unlock;
+
 		err = security_unix_may_send(sk->sk_socket, other->sk_socket);
 		if (err)
 			goto out_unlock;
-- 
1.7.1

