1 From f1fa557a115c6c83445bd989b260e6e929dc5035 Mon Sep 17 00:00:00 2001
2 From: Sean Tranchetti <stranche@codeaurora.org>
3 Date: Thu, 7 Feb 2019 13:33:21 -0700
4 Subject: af_key: unconditionally clone on broadcast
6 [ Upstream commit fc2d5cfdcfe2ab76b263d91429caa22451123085 ]
8 Attempting to avoid cloning the skb when broadcasting by inflating
9 the refcount with sock_hold/sock_put while under RCU lock is dangerous
10 and violates RCU principles. It leads to subtle race conditions when
11 attempting to free the SKB, as we may reference sockets that have
12 already been freed by the stack.
14 Unable to handle kernel paging request at virtual address 6b6b6b6b6b6c4b
15 [006b6b6b6b6b6c4b] address between user and kernel address ranges
16 Internal error: Oops: 96000004 [#1] PREEMPT SMP
17 task: fffffff78f65b380 task.stack: ffffff8049a88000
18 pc : sock_rfree+0x38/0x6c
19 lr : skb_release_head_state+0x6c/0xcc
20 Process repro (pid: 7117, stack limit = 0xffffff8049a88000)
23 skb_release_head_state+0x6c/0xcc
24 skb_release_all+0x1c/0x38
27 pfkey_broadcast+0x14c/0x18c
28 pfkey_sendmsg+0x1d8/0x408
29 sock_sendmsg+0x44/0x60
30 ___sys_sendmsg+0x1d0/0x2a8
31 __sys_sendmsg+0x64/0xb4
33 el0_svc_naked+0x34/0x38
34 Kernel panic - not syncing: Fatal exception
36 Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
37 Signed-off-by: Sean Tranchetti <stranche@codeaurora.org>
38 Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
39 Signed-off-by: Sasha Levin <sashal@kernel.org>
41 net/key/af_key.c | 40 +++++++++++++++-------------------------
42 1 file changed, 15 insertions(+), 25 deletions(-)
44 diff --git a/net/key/af_key.c b/net/key/af_key.c
45 index 3b209cbfe1df..b095551a5773 100644
46 --- a/net/key/af_key.c
47 +++ b/net/key/af_key.c
48 @@ -196,30 +196,22 @@ static int pfkey_release(struct socket *sock)
52 -static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
53 - gfp_t allocation, struct sock *sk)
54 +static int pfkey_broadcast_one(struct sk_buff *skb, gfp_t allocation,
60 - if (*skb2 == NULL) {
61 - if (refcount_read(&skb->users) != 1) {
62 - *skb2 = skb_clone(skb, allocation);
65 - refcount_inc(&skb->users);
68 - if (*skb2 != NULL) {
69 - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
70 - skb_set_owner_r(*skb2, sk);
71 - skb_queue_tail(&sk->sk_receive_queue, *skb2);
72 - sk->sk_data_ready(sk);
76 + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
79 + skb = skb_clone(skb, allocation);
82 + skb_set_owner_r(skb, sk);
83 + skb_queue_tail(&sk->sk_receive_queue, skb);
84 + sk->sk_data_ready(sk);
91 @@ -234,7 +226,6 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
93 struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
95 - struct sk_buff *skb2 = NULL;
98 /* XXX Do we need something like netlink_overrun? I think
99 @@ -253,7 +244,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
103 - pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
104 + pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
106 /* the exact target will be processed later */
108 @@ -268,7 +259,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
112 - err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
113 + err2 = pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
115 /* Error is cleared after successful sending to at least one
117 @@ -278,9 +269,8 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
121 - err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
122 + err = pfkey_broadcast_one(skb, allocation, one_sk);