From mboxrd@z Thu Jan 1 00:00:00 1970 From: Sean Tranchetti Subject: [PATCH net-next] udp: Fix kernel panic in UDP GSO path Date: Thu, 10 May 2018 18:38:47 -0600 Message-ID: <1525999127-11585-1-git-send-email-stranche@codeaurora.org> Cc: Sean Tranchetti , Subash Abhinov Kasiviswanathan To: willemb@google.com, davem@davemloft.net, netdev@vger.kernel.org Return-path: Received: from wolverine01.qualcomm.com ([199.106.114.254]:9846 "EHLO wolverine01.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750751AbeEKAps (ORCPT ); Thu, 10 May 2018 20:45:48 -0400 Sender: netdev-owner@vger.kernel.org List-ID: Using GSO in the UDP path on a device with scatter-gather netdevice feature disabled will result in a kernel panic with the following call stack: kernel BUG at net/core/skbuff.c:104! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP PC is at skb_panic+0x4c/0x54 LR is at skb_panic+0x4c/0x54 Process udpgso_bench_tx (pid: 4078, stack limit = 0xffffff8048de8000) [] skb_panic+0x4c/0x54 [] skb_copy_bits+0x0/0x244 [] __ip_append_data+0x230/0x814 [] ip_make_skb+0xe4/0x178 [] udp_sendmsg+0x828/0x888 [] inet_sendmsg+0xe4/0x130 [] ___sys_sendmsg+0x1d8/0x2c0 [] SyS_sendmsg+0x90/0xe0 This panic is the result of allocating SKBs with small size for the newly segmented SKB. If the scatter-gather feature is disabled, the code attempts to call skb_put() on the small SKB with an argument of nearly the entire unsegmented SKB length. After this patch, attempting to use GSO with scatter-gather disabled will result in -EINVAL being returned. Fixes: 15e36f5b8e98 ("udp: paged allocation with gso") Signed-off-by: Sean Tranchetti Signed-off-by: Subash Abhinov Kasiviswanathan --- net/ipv4/ip_output.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index b5e21eb..0d63690 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1054,8 +1054,16 @@ static int __ip_append_data(struct sock *sk, copy = length; if (!(rt->dst.dev->features&NETIF_F_SG)) { + struct sk_buff *tmp; unsigned int off; + if (paged) { + err = -EINVAL; + while ((tmp = __skb_dequeue(queue)) != NULL) + kfree(tmp); + goto error; + } + off = skb->len; if (getfrag(from, skb_put(skb, copy), offset, copy, off, skb) < 0) { -- 1.9.1