Patch "net: Clone skb before setting peeked flag" has been added to the 4.1-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
net: Clone skb before setting peeked flag
to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
net-clone-skb-before-setting-peeked-flag.patch
and it can be found in the queue-4.1 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From foo@baz Sat Sep 26 11:13:07 PDT 2015
From: Herbert Xu <[email protected]>
Date: Mon, 13 Jul 2015 16:04:13 +0800
Subject: net: Clone skb before setting peeked flag
From: Herbert Xu <[email protected]>
[ Upstream commit 738ac1ebb96d02e0d23bc320302a6ea94c612dec ]
Shared skbs must not be modified and this is crucial for broadcast and/or multicast paths where we use it as an optimisation to avoid unnecessary cloning.
The function skb_recv_datagram breaks this rule by setting peeked without cloning the skb first. This causes funky races which leads to double-free.
This patch fixes this by cloning the skb and replacing the skb in the list when setting skb->peeked.
--- net/core/datagram.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)
net/core/datagram.c +38 -3
@@ -131,6 +131,35 @@ out_noerr: goto out; } +static int skb_set_peeked (struct sk_buff *skb) +{ +struct sk_buff *nskb; + +if (skb->peeked) +return 0 ; + +/* We have to unshare an skb before modifying it. */ +if (!skb_shared (skb)) + goto done; + + nskb =skb_clone (skb,GFP_ATOMIC ); +if (!nskb) +return -ENOMEM ; + + skb->prev->next = nskb; + skb->next->prev = nskb; + nskb->prev = skb->prev; + nskb->next = skb->next; + +consume_skb (skb); + skb = nskb; + +done: + skb->peeked =1 ; + +return 0 ; +} +/** * __skb_recv_datagram - Receive a datagram skbuff * @sk: socket
@@ -165,7 +194,9 @@ out_noerr:struct sk_buff *__skb_recv_datagram (struct sock *sk,unsigned int flags,int *peeked,int *off,int *err) { +struct sk_buff_head *queue = &sk->sk_receive_queue;struct sk_buff *skb, *last; +unsigned long cpu_flags;long timeo;/* * Caller is allowed not to check sk->sk_err before skb_recv_datagram()
@@ -184,8 +215,6 @@ struct sk_buff *__skb_recv_datagram(stru* Look at current nfs client by the way... * However, this function was correct in any case. 8) */ -unsigned long cpu_flags; -struct sk_buff_head *queue = &sk->sk_receive_queue;int _off = *off; last = (struct sk_buff *)queue;
@@ -199,7 +228,11 @@ struct sk_buff *__skb_recv_datagram(stru _off -= skb->len;continue ; } - skb->peeked =1 ; + + error =skb_set_peeked (skb); +if (error) + goto unlock_err; +atomic_inc (&skb->users); }else __skb_unlink (skb, queue);
@@ -223,6 +256,8 @@ struct sk_buff *__skb_recv_datagram(strureturn NULL ; +unlock_err: +spin_unlock_irqrestore (&queue->lock, cpu_flags); no_packet: *err = error;return NULL ;
Patches currently in stable-queue which might be from [email protected] are
queue-4.1/powerpc-uncomment-and-make-enable_kernel_vsx-routine-available.patch queue-4.1/net-fix-skb_set_peeked-use-after-free-bug.patch queue-4.1/ipv6-lock-socket-in-ip6_datagram_connect.patch queue-4.1/net-fix-skb-csum-races-when-peeking.patch queue-4.1/rhashtable-fix-for-resize-events-during-table-walk.patch queue-4.1/net-clone-skb-before-setting-peeked-flag.patch queue-4.1/revert-sit-add-gro-callbacks-to-sit_offload.patch queue-4.1/crypto-vmx-adding-enable_kernel_vsx-to-access-vsx-instructions.patch queue-4.1/netlink-make-sure-ebusy-won-t-escape-from-netlink_insert.patch