From: Dmitry Torokhov Date: Thu, 3 Sep 2015 20:08:37 +0000 (-0700) Subject: net: fix crash in tcp_nuke_addr() X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=08f7c4280cd5efe9e274240c42177f459431bac2;p=GitHub%2Fexynos8895%2Fandroid_kernel_samsung_universal8895.git net: fix crash in tcp_nuke_addr() When iterating through sockets we need to skip sockets in TIME_WAIT state as they use lightweight structure inet_timewait_sock that does not have sk_lock member, and if we try to lock them we'll crash thusly: [ 89.376383] BUG: spinlock lockup suspected on CPU#0, netd/431 [ 89.382139] lock: 0xffffffc039d05070, .magic: 66d30606, .owner: /-1682098992, .owner_cpu: 0 [ 89.390598] CPU: 0 PID: 431 Comm: netd Tainted: G U W 3.18.0 #5 [ 89.397389] Hardware name: Google Tegra210 Smaug Rev 1+ (DT) [ 89.403049] Call trace: [ 89.405501] [] dump_backtrace+0x0/0x10c [ 89.410918] [] show_stack+0x10/0x1c [ 89.415971] [] dump_stack+0x74/0x94 [ 89.421018] [] spin_dump+0x78/0x88 [ 89.425984] [] do_raw_spin_lock+0xfc/0x158 [ 89.431666] [] _raw_spin_lock+0x34/0x44 [ 89.437059] [] tcp_nuke_addr+0x1fc/0x29c [ 89.442548] [] devinet_ioctl+0x288/0x680 [ 89.448053] [] inet_ioctl+0xc4/0xf4 [ 89.453103] [] sock_do_ioctl+0x2c/0x5c [ 89.458408] [] sock_ioctl+0x210/0x230 [ 89.463633] [] do_vfs_ioctl+0x4ac/0x590 [ 89.469049] [] SyS_ioctl+0x5c/0x88 (or with NULL pointer dereference if lockdep is still working). Change-Id: I07c70d9a60b125b1070ff05c4eec27daee1a3e90 Signed-off-by: Dmitry Torokhov --- diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c8cfe784c79a..47b147ca69d1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3241,8 +3241,19 @@ restart: sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) { struct inet_sock *inet = inet_sk(sk); + if (sk->sk_state == TCP_TIME_WAIT) { + /* + * Sockets that are in TIME_WAIT state are + * instances of lightweight inet_timewait_sock, + * we should simply skip them (or we'll try to + * access non-existing fields and crash). + */ + continue; + } + if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT) continue; + if (sock_flag(sk, SOCK_DEAD)) continue;