]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.10.7/net-unix-properly-re-increment-inflight-counter-of-gc-discarded-candidates.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.10.7 / net-unix-properly-re-increment-inflight-counter-of-gc-discarded-candidates.patch
CommitLineData
ad3041a8
GKH
1From foo@baz Mon Mar 27 18:18:08 CEST 2017
2From: Andrey Ulanov <andreyu@google.com>
3Date: Tue, 14 Mar 2017 20:16:42 -0700
4Subject: net: unix: properly re-increment inflight counter of GC discarded candidates
5
6From: Andrey Ulanov <andreyu@google.com>
7
8
9[ Upstream commit 7df9c24625b9981779afb8fcdbe2bb4765e61147 ]
10
11Dmitry has reported that a BUG_ON() condition in unix_notinflight()
12may be triggered by a simple code that forwards unix socket in an
13SCM_RIGHTS message.
14That is caused by incorrect unix socket GC implementation in unix_gc().
15
16The GC first collects list of candidates, then (a) decrements their
17"children's" inflight counter, (b) checks which inflight counters are
18now 0, and then (c) increments all inflight counters back.
19(a) and (c) are done by calling scan_children() with inc_inflight or
20dec_inflight as the second argument.
21
22Commit 6209344f5a37 ("net: unix: fix inflight counting bug in garbage
23collector") changed scan_children() such that it no longer considers
24sockets that do not have UNIX_GC_CANDIDATE flag. It also added a block
25of code that that unsets this flag _before_ invoking
26scan_children(, dec_iflight, ). This may lead to incorrect inflight
27counters for some sockets.
28
29This change fixes this bug by changing order of operations:
30UNIX_GC_CANDIDATE is now unset only after all inflight counters are
31restored to the original state.
32
33 kernel BUG at net/unix/garbage.c:149!
34 RIP: 0010:[<ffffffff8717ebf4>] [<ffffffff8717ebf4>]
35 unix_notinflight+0x3b4/0x490 net/unix/garbage.c:149
36 Call Trace:
37 [<ffffffff8716cfbf>] unix_detach_fds.isra.19+0xff/0x170 net/unix/af_unix.c:1487
38 [<ffffffff8716f6a9>] unix_destruct_scm+0xf9/0x210 net/unix/af_unix.c:1496
39 [<ffffffff86a90a01>] skb_release_head_state+0x101/0x200 net/core/skbuff.c:655
40 [<ffffffff86a9808a>] skb_release_all+0x1a/0x60 net/core/skbuff.c:668
41 [<ffffffff86a980ea>] __kfree_skb+0x1a/0x30 net/core/skbuff.c:684
42 [<ffffffff86a98284>] kfree_skb+0x184/0x570 net/core/skbuff.c:705
43 [<ffffffff871789d5>] unix_release_sock+0x5b5/0xbd0 net/unix/af_unix.c:559
44 [<ffffffff87179039>] unix_release+0x49/0x90 net/unix/af_unix.c:836
45 [<ffffffff86a694b2>] sock_release+0x92/0x1f0 net/socket.c:570
46 [<ffffffff86a6962b>] sock_close+0x1b/0x20 net/socket.c:1017
47 [<ffffffff81a76b8e>] __fput+0x34e/0x910 fs/file_table.c:208
48 [<ffffffff81a771da>] ____fput+0x1a/0x20 fs/file_table.c:244
49 [<ffffffff81483ab0>] task_work_run+0x1a0/0x280 kernel/task_work.c:116
50 [< inline >] exit_task_work include/linux/task_work.h:21
51 [<ffffffff8141287a>] do_exit+0x183a/0x2640 kernel/exit.c:828
52 [<ffffffff8141383e>] do_group_exit+0x14e/0x420 kernel/exit.c:931
53 [<ffffffff814429d3>] get_signal+0x663/0x1880 kernel/signal.c:2307
54 [<ffffffff81239b45>] do_signal+0xc5/0x2190 arch/x86/kernel/signal.c:807
55 [<ffffffff8100666a>] exit_to_usermode_loop+0x1ea/0x2d0
56 arch/x86/entry/common.c:156
57 [< inline >] prepare_exit_to_usermode arch/x86/entry/common.c:190
58 [<ffffffff81009693>] syscall_return_slowpath+0x4d3/0x570
59 arch/x86/entry/common.c:259
60 [<ffffffff881478e6>] entry_SYSCALL_64_fastpath+0xc4/0xc6
61
62Link: https://lkml.org/lkml/2017/3/6/252
63Signed-off-by: Andrey Ulanov <andreyu@google.com>
64Reported-by: Dmitry Vyukov <dvyukov@google.com>
65Fixes: 6209344 ("net: unix: fix inflight counting bug in garbage collector")
66Signed-off-by: David S. Miller <davem@davemloft.net>
67Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
68---
69 net/unix/garbage.c | 17 +++++++++--------
70 1 file changed, 9 insertions(+), 8 deletions(-)
71
72--- a/net/unix/garbage.c
73+++ b/net/unix/garbage.c
74@@ -146,6 +146,7 @@ void unix_notinflight(struct user_struct
75 if (s) {
76 struct unix_sock *u = unix_sk(s);
77
78+ BUG_ON(!atomic_long_read(&u->inflight));
79 BUG_ON(list_empty(&u->link));
80
81 if (atomic_long_dec_and_test(&u->inflight))
82@@ -341,6 +342,14 @@ void unix_gc(void)
83 }
84 list_del(&cursor);
85
86+ /* Now gc_candidates contains only garbage. Restore original
87+ * inflight counters for these as well, and remove the skbuffs
88+ * which are creating the cycle(s).
89+ */
90+ skb_queue_head_init(&hitlist);
91+ list_for_each_entry(u, &gc_candidates, link)
92+ scan_children(&u->sk, inc_inflight, &hitlist);
93+
94 /* not_cycle_list contains those sockets which do not make up a
95 * cycle. Restore these to the inflight list.
96 */
97@@ -350,14 +359,6 @@ void unix_gc(void)
98 list_move_tail(&u->link, &gc_inflight_list);
99 }
100
101- /* Now gc_candidates contains only garbage. Restore original
102- * inflight counters for these as well, and remove the skbuffs
103- * which are creating the cycle(s).
104- */
105- skb_queue_head_init(&hitlist);
106- list_for_each_entry(u, &gc_candidates, link)
107- scan_children(&u->sk, inc_inflight, &hitlist);
108-
109 spin_unlock(&unix_gc_lock);
110
111 /* Here we are. Hitlist is filled. Die. */