Home Home > GIT Browse > SLE15
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-06-19 15:23:25 +0200
committerTakashi Iwai <tiwai@suse.de>2019-06-19 15:23:25 +0200
commit3ddf01172af9c7956cef2590dffde1d83a734cae (patch)
tree6a38c5ea2f774b4d292a22dcd0c6e5b6070b9da7
parenta37dca9dd619283cf5ace0f191c9925c585b96ed (diff)
af_key: unconditionally clone on broadcast (bsc#1051510).
-rw-r--r--patches.fixes/af_key-unconditionally-clone-on-broadcast.patch132
-rw-r--r--series.conf1
2 files changed, 133 insertions, 0 deletions
diff --git a/patches.fixes/af_key-unconditionally-clone-on-broadcast.patch b/patches.fixes/af_key-unconditionally-clone-on-broadcast.patch
new file mode 100644
index 0000000000..518434a9b2
--- /dev/null
+++ b/patches.fixes/af_key-unconditionally-clone-on-broadcast.patch
@@ -0,0 +1,132 @@
+From fc2d5cfdcfe2ab76b263d91429caa22451123085 Mon Sep 17 00:00:00 2001
+From: Sean Tranchetti <stranche@codeaurora.org>
+Date: Thu, 7 Feb 2019 13:33:21 -0700
+Subject: [PATCH] af_key: unconditionally clone on broadcast
+Git-commit: fc2d5cfdcfe2ab76b263d91429caa22451123085
+Patch-mainline: v5.0-rc8
+References: bsc#1051510
+
+Attempting to avoid cloning the skb when broadcasting by inflating
+the refcount with sock_hold/sock_put while under RCU lock is dangerous
+and violates RCU principles. It leads to subtle race conditions when
+attempting to free the SKB, as we may reference sockets that have
+already been freed by the stack.
+
+Unable to handle kernel paging request at virtual address 6b6b6b6b6b6c4b
+[006b6b6b6b6b6c4b] address between user and kernel address ranges
+Internal error: Oops: 96000004 [#1] PREEMPT SMP
+Task: fffffff78f65b380 task.stack: ffffff8049a88000
+pc : sock_rfree+0x38/0x6c
+lr : skb_release_head_state+0x6c/0xcc
+Process repro (pid: 7117, stack limit = 0xffffff8049a88000)
+Call trace:
+ sock_rfree+0x38/0x6c
+ skb_release_head_state+0x6c/0xcc
+ skb_release_all+0x1c/0x38
+ __kfree_skb+0x1c/0x30
+ kfree_skb+0xd0/0xf4
+ pfkey_broadcast+0x14c/0x18c
+ pfkey_sendmsg+0x1d8/0x408
+ sock_sendmsg+0x44/0x60
+ ___sys_sendmsg+0x1d0/0x2a8
+ __sys_sendmsg+0x64/0xb4
+ SyS_sendmsg+0x34/0x4c
+ el0_svc_naked+0x34/0x38
+Kernel panic - not syncing: Fatal exception
+
+Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: Sean Tranchetti <stranche@codeaurora.org>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ net/key/af_key.c | 40 +++++++++++++++-------------------------
+ 1 file changed, 15 insertions(+), 25 deletions(-)
+
+diff --git a/net/key/af_key.c b/net/key/af_key.c
+index 637030f43b67..5651c29cb5bd 100644
+--- a/net/key/af_key.c
++++ b/net/key/af_key.c
+@@ -196,30 +196,22 @@ static int pfkey_release(struct socket *sock)
+ return 0;
+ }
+
+-static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
+- gfp_t allocation, struct sock *sk)
++static int pfkey_broadcast_one(struct sk_buff *skb, gfp_t allocation,
++ struct sock *sk)
+ {
+ int err = -ENOBUFS;
+
+- sock_hold(sk);
+- if (*skb2 == NULL) {
+- if (refcount_read(&skb->users) != 1) {
+- *skb2 = skb_clone(skb, allocation);
+- } else {
+- *skb2 = skb;
+- refcount_inc(&skb->users);
+- }
+- }
+- if (*skb2 != NULL) {
+- if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
+- skb_set_owner_r(*skb2, sk);
+- skb_queue_tail(&sk->sk_receive_queue, *skb2);
+- sk->sk_data_ready(sk);
+- *skb2 = NULL;
+- err = 0;
+- }
++ if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
++ return err;
++
++ skb = skb_clone(skb, allocation);
++
++ if (skb) {
++ skb_set_owner_r(skb, sk);
++ skb_queue_tail(&sk->sk_receive_queue, skb);
++ sk->sk_data_ready(sk);
++ err = 0;
+ }
+- sock_put(sk);
+ return err;
+ }
+
+@@ -234,7 +226,6 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
+ {
+ struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
+ struct sock *sk;
+- struct sk_buff *skb2 = NULL;
+ int err = -ESRCH;
+
+ /* XXX Do we need something like netlink_overrun? I think
+@@ -253,7 +244,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
+ * socket.
+ */
+ if (pfk->promisc)
+- pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
++ pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
+
+ /* the exact target will be processed later */
+ if (sk == one_sk)
+@@ -268,7 +259,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
+ continue;
+ }
+
+- err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
++ err2 = pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
+
+ /* Error is cleared after successful sending to at least one
+ * registered KM */
+@@ -278,9 +269,8 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
+ rcu_read_unlock();
+
+ if (one_sk != NULL)
+- err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
++ err = pfkey_broadcast_one(skb, allocation, one_sk);
+
+- kfree_skb(skb2);
+ kfree_skb(skb);
+ return err;
+ }
+--
+2.16.4
+
diff --git a/series.conf b/series.conf
index e60f88e4f1..c56a3f8b4a 100644
--- a/series.conf
+++ b/series.conf
@@ -21364,6 +21364,7 @@
patches.suse/missing-barriers-in-some-of-unix_sock-addr-and-path-.patch
patches.suse/bonding-fix-PACKET_ORIGDEV-regression.patch
patches.suse/net-avoid-false-positives-in-untrusted-gso-validatio.patch
+ patches.fixes/af_key-unconditionally-clone-on-broadcast.patch
patches.suse/ipvlan-disallow-userns-cap_net_admin-to-change-globa.patch
patches.fixes/mac80211_hwsim-propagate-genlmsg_reply-return-code.patch
patches.drivers/bnxt_en-Fix-typo-in-firmware-message-timeout-logic.patch