From patchwork Thu Mar 15 16:09:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Soheil Hassas Yeganeh X-Patchwork-Id: 886324 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="YXE6Cr0/"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 402D775cdPz9sVK for ; Fri, 16 Mar 2018 03:09:23 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751833AbeCOQJV (ORCPT ); Thu, 15 Mar 2018 12:09:21 -0400 Received: from mail-qk0-f193.google.com ([209.85.220.193]:33141 "EHLO mail-qk0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751482AbeCOQJS (ORCPT ); Thu, 15 Mar 2018 12:09:18 -0400 Received: by mail-qk0-f193.google.com with SMTP id l25so1448655qkj.0 for ; Thu, 15 Mar 2018 09:09:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=oSksS4VwCjGJRNYGjphnKnYTv30ZK3rRMU7bgX8Xz3w=; b=YXE6Cr0/F1cL+5TVFKXnVCxH0lccD76hLb+Rdwx3SQLFm9RilEVFsK9XOwYkBd1XDE Mhfqv+kq4zUE0xXlRRFNb1DIuWDxOLbIrXlkO/Ssp2FKhVTUsmHHJkzzd48PNviyBIUS wslCEv2ep07wa1AK6ghqRdNjd6xgLkBAnb8XAFW0cw8xngYQJ1q3wmbRERqkGZhSDYkN m7Iutg5dIw814otQy4WCB8UWjwPIHkQr36nkFxjv6i5BwrlgKR/N5Un/fJu6+g6GbDDx Rkj25U/b7N1klkxYngZMM+oUTSnU3GDHq/QLa2p6vMKhxjlcyPndqfCl7il49frOK9V6 6gAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=oSksS4VwCjGJRNYGjphnKnYTv30ZK3rRMU7bgX8Xz3w=; b=BeGnYCwAChjXP1alJi3M2VOt9x7S166nQ2IB1TlWKovK8zora/YtdIpJyT+kB6857Z WFEf0Pemh1hzd9b2dgSnKjO7d+YaiIWSC2q5qlW/P7fZ16GPuJqmDGbGm/yznsOP9ypg iHkRJQc7Poon7z2SOgePNRGVk09DggqGdZZIJx++vTqTfUbBARaAYALs+np+CnGTF8Oi CHImPlz7HTfHO9tlVE0yh6Ygo3jrBvjVJivxTxLv4ke+Ug9CT8bfBrE2NH0E39IfXF5/ s787owLCu2irgQUXcpuHfOdsz9vJTs9b5Vs+mOnoR9cJVt5ULpEp0aunqMS02KvtC7TU jb4Q== X-Gm-Message-State: AElRT7ELCP8MAts9XGDlZmaYdAVia0mJaT5Ay/P5eA5oC9xOn6OWcHa0 zsMOhf+tMtdq/5Plm4F7W3MXkbAN X-Google-Smtp-Source: AG47ELuWXEYaPKVD/VJHaFssGE/uzkLVJPQfmx+XGmGaeZ0QItBf1ZP70qYC3dR/ZfpqfFRFLiA4oA== X-Received: by 10.55.40.137 with SMTP id o9mr2950406qko.16.1521130157677; Thu, 15 Mar 2018 09:09:17 -0700 (PDT) Received: from z.nyc.corp.google.com ([2620:0:1003:315:9c67:ffa0:44c0:d273]) by smtp.gmail.com with ESMTPSA id r77sm3394469qka.33.2018.03.15.09.09.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 15 Mar 2018 09:09:17 -0700 (PDT) From: Soheil Hassas Yeganeh To: davem@davemloft.net, netdev@vger.kernel.org Cc: ycheng@google.com, ncardwell@google.com, yongjianchn@gmail.com, nefelim4ag@gmail.com, Soheil Hassas Yeganeh , Eric Dumazet Subject: [PATCH linux-stable-4.14] tcp: reset sk_send_head in tcp_write_queue_purge Date: Thu, 15 Mar 2018 12:09:13 -0400 Message-Id: <20180315160913.180918-1-soheil.kdev@gmail.com> X-Mailer: git-send-email 2.16.2.804.g6dcf76e118-goog Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Soheil Hassas Yeganeh tcp_write_queue_purge clears all the SKBs in the write queue but does not reset the sk_send_head. As a result, we can have a NULL pointer dereference anywhere that we use tcp_send_head instead of the tcp_write_queue_tail. For example, after 27fid7a8ed38 (tcp: purge write queue upon RST), we can purge the write queue on RST. Prior to 75c119afe14f (tcp: implement rb-tree based retransmit queue), tcp_push will only check tcp_send_head and then accesses tcp_write_queue_tail to send the actual SKB. As a result, it will dereference a NULL pointer. This has been reported twice for 4.14 where we don't have 75c119afe14f: By Timofey Titovets: [ 422.081094] BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 [ 422.081254] IP: tcp_push+0x42/0x110 [ 422.081314] PGD 0 P4D 0 [ 422.081364] Oops: 0002 [#1] SMP PTI By Yongjian Xu: BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 IP: tcp_push+0x48/0x120 PGD 80000007ff77b067 P4D 80000007ff77b067 PUD 7fd989067 PMD 0 Oops: 0002 [#18] SMP PTI Modules linked in: tcp_diag inet_diag tcp_bbr sch_fq iTCO_wdt iTCO_vendor_support pcspkr ixgbe mdio i2c_i801 lpc_ich joydev input_leds shpchp e1000e igb dca ptp pps_core hwmon mei_me mei ipmi_si ipmi_msghandler sg ses scsi_transport_sas enclosure ext4 jbd2 mbcache sd_mod ahci libahci megaraid_sas wmi ast ttm dm_mirror dm_region_hash dm_log dm_mod dax CPU: 6 PID: 14156 Comm: [ET_NET 6] Tainted: G D 4.14.26-1.el6.x86_64 #1 Hardware name: LENOVO ThinkServer RD440 /ThinkServer RD440, BIOS A0TS80A 09/22/2014 task: ffff8807d78d8140 task.stack: ffffc9000e944000 RIP: 0010:tcp_push+0x48/0x120 RSP: 0018:ffffc9000e947a88 EFLAGS: 00010246 RAX: 00000000000005b4 RBX: ffff880f7cce9c00 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000040 RDI: ffff8807d00f5000 RBP: ffffc9000e947aa8 R08: 0000000000001c84 R09: 0000000000000000 R10: ffff8807d00f5158 R11: 0000000000000000 R12: ffff8807d00f5000 R13: 0000000000000020 R14: 00000000000256d4 R15: 0000000000000000 FS: 00007f5916de9700(0000) GS:ffff88107fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000038 CR3: 00000007f8226004 CR4: 00000000001606e0 Call Trace: tcp_sendmsg_locked+0x33d/0xe50 tcp_sendmsg+0x37/0x60 inet_sendmsg+0x39/0xc0 sock_sendmsg+0x49/0x60 sock_write_iter+0xb6/0x100 do_iter_readv_writev+0xec/0x130 ? rw_verify_area+0x49/0xb0 do_iter_write+0x97/0xd0 vfs_writev+0x7e/0xe0 ? __wake_up_common_lock+0x80/0xa0 ? __fget_light+0x2c/0x70 ? __do_page_fault+0x1e7/0x530 do_writev+0x60/0xf0 ? inet_shutdown+0xac/0x110 SyS_writev+0x10/0x20 do_syscall_64+0x6f/0x140 ? prepare_exit_to_usermode+0x8b/0xa0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x3135ce0c57 RSP: 002b:00007f5916de4b00 EFLAGS: 00000293 ORIG_RAX: 0000000000000014 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 0000003135ce0c57 RDX: 0000000000000002 RSI: 00007f5916de4b90 RDI: 000000000000606f RBP: 0000000000000000 R08: 0000000000000000 R09: 00007f5916de8c38 R10: 0000000000000000 R11: 0000000000000293 R12: 00000000000464cc R13: 00007f5916de8c30 R14: 00007f58d8bef080 R15: 0000000000000002 Code: 48 8b 97 60 01 00 00 4c 8d 97 58 01 00 00 41 b9 00 00 00 00 41 89 f3 4c 39 d2 49 0f 44 d1 41 81 e3 00 80 00 00 0f 85 b0 00 00 00 <80> 4a 38 08 44 8b 8f 74 06 00 00 44 89 8f 7c 06 00 00 83 e6 01 RIP: tcp_push+0x48/0x120 RSP: ffffc9000e947a88 CR2: 0000000000000038 ---[ end trace 8d545c2e93515549 ]--- Fixes: a27fid7a8ed38 (tcp: purge write queue upon RST) Reported-by: Timofey Titovets Reported-by: Yongjian Xu Signed-off-by: Eric Dumazet Signed-off-by: Soheil Hassas Yeganeh Tested-by: Yongjian Xu --- include/net/tcp.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 0a13574134b8b..d323d4fa742ca 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1600,6 +1600,11 @@ enum tcp_chrono { void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type); void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type); +static inline void tcp_init_send_head(struct sock *sk) +{ + sk->sk_send_head = NULL; +} + /* write queue abstraction */ static inline void tcp_write_queue_purge(struct sock *sk) { @@ -1610,6 +1615,7 @@ static inline void tcp_write_queue_purge(struct sock *sk) sk_wmem_free_skb(sk, skb); sk_mem_reclaim(sk); tcp_clear_all_retrans_hints(tcp_sk(sk)); + tcp_init_send_head(sk); } static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk) @@ -1672,11 +1678,6 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli tcp_sk(sk)->highest_sack = NULL; } -static inline void tcp_init_send_head(struct sock *sk) -{ - sk->sk_send_head = NULL; -} - static inline void __tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb) { __skb_queue_tail(&sk->sk_write_queue, skb);