diff mbox series

[bpf-next,v2,1/8] tcp, ulp: enforce sock_owned_by_me upon ulp init and cleanup

Message ID 20181013004603.3747-2-daniel@iogearbox.net
State Accepted, archived
Delegated to: BPF Maintainers
Headers show
Series sockmap integration for ktls | expand

Commit Message

Daniel Borkmann Oct. 13, 2018, 12:45 a.m. UTC
Whenever the ULP data on the socket is mangled, enforce that the
caller has the socket lock held as otherwise things may race with
initialization and cleanup callbacks from ulp ops as both would
mangle internal socket state.

Joint work with John.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
 net/ipv4/tcp_ulp.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Eric Dumazet Oct. 16, 2018, 2:17 p.m. UTC | #1
On 10/12/2018 05:45 PM, Daniel Borkmann wrote:
> Whenever the ULP data on the socket is mangled, enforce that the
> caller has the socket lock held as otherwise things may race with
> initialization and cleanup callbacks from ulp ops as both would
> mangle internal socket state.
> 
> Joint work with John.
> 
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Signed-off-by: John Fastabend <john.fastabend@gmail.com>
> ---
>  net/ipv4/tcp_ulp.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c
> index a5995bb..34e9635 100644
> --- a/net/ipv4/tcp_ulp.c
> +++ b/net/ipv4/tcp_ulp.c
> @@ -123,6 +123,8 @@ void tcp_cleanup_ulp(struct sock *sk)
>  {
>  	struct inet_connection_sock *icsk = inet_csk(sk);
>  
> +	sock_owned_by_me(sk);
> +
>  	if (!icsk->icsk_ulp_ops)
>  		return;

Ahem... inet_csk_prepare_forced_close() releases the socket lock,
and tcp_done(newsk); is called after inet_csk_prepare_forced_close() 


syzkaller got the following trace



TCP: request_sock_TCPv6: Possible SYN flooding on port 20002. Sending cookies.  Check SNMP counters.
tmpfs: Bad mount option s\xA8\xFE\x9E\x92\xE9K\xD7:\x85\x87$z\x94\xFB3\xBF\xE4\x8E\x88\xE2\xF0%\x92\xF8\xE5\xC3lh
WARNING: CPU: 0 PID: 12625 at include/net/sock.h:1539 sock_owned_by_me include/net/sock.h:1539 [inline]
WARNING: CPU: 0 PID: 12625 at include/net/sock.h:1539 tcp_cleanup_ulp+0x1ad/0x200 net/ipv4/tcp_ulp.c:102
Kernel panic - not syncing: panic_on_warn set ...
CPU: 0 PID: 12625 Comm: syz-executor3 Not tainted 4.19.0-rc8-next-20181016+ #95
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 <IRQ>
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x244/0x39d lib/dump_stack.c:113
 panic+0x2ad/0x55c kernel/panic.c:188
 __warn.cold.8+0x20/0x45 kernel/panic.c:540
 report_bug+0x254/0x2d0 lib/bug.c:186
 fixup_bug arch/x86/kernel/traps.c:178 [inline]
 do_error_trap+0x11b/0x200 arch/x86/kernel/traps.c:271
 do_invalid_op+0x36/0x40 arch/x86/kernel/traps.c:290
 invalid_op+0x14/0x20 arch/x86/entry/entry_64.S:969
RIP: 0010:sock_owned_by_me include/net/sock.h:1539 [inline]
RIP: 0010:tcp_cleanup_ulp+0x1ad/0x200 net/ipv4/tcp_ulp.c:102
Code: 83 c0 03 38 d0 7c 04 84 d2 75 61 44 8b 25 cb 4e df 02 31 ff 44 89 e6 e8 51 3d ed fa 45 85 e4 0f 84 91 fe ff ff e8 33 3c ed fa <0f> 0b e9 85 fe ff ff 4c 89 ef e8 34 84 30 fb e9 9f fe ff ff 4c 89
RSP: 0018:ffff8801dae06860 EFLAGS: 00010206
RAX: ffff8801bf202040 RBX: ffff8801918501c0 RCX: ffffffff8690e6ff
RDX: 0000000000000100 RSI: ffffffff8690e70d RDI: 0000000000000005
RBP: ffff8801dae06880 R08: ffff8801bf202040 R09: 0000000000000002
R10: 0000000000000000 R11: ffff8801bf202040 R12: 0000000000000001
R13: 0000000000000000 R14: 0000000000000003 R15: ffff8801dae069a0
 tcp_v4_destroy_sock+0x15c/0x980 net/ipv4/tcp_ipv4.c:1980
 tcp_v6_destroy_sock+0x15/0x20 net/ipv6/tcp_ipv6.c:1762
 inet_csk_destroy_sock+0x19f/0x440 net/ipv4/inet_connection_sock.c:838
 tcp_done+0x272/0x310 net/ipv4/tcp.c:3760
 tcp_v6_syn_recv_sock+0x1f21/0x25f0 net/ipv6/tcp_ipv6.c:1236
 tcp_get_cookie_sock+0x10e/0x580 net/ipv4/syncookies.c:213
 cookie_v6_check+0x1830/0x27d0 net/ipv6/syncookies.c:257
 tcp_v6_cookie_check net/ipv6/tcp_ipv6.c:1028 [inline]
 tcp_v6_do_rcv+0x10ea/0x13c0 net/ipv6/tcp_ipv6.c:1336
 tcp_v6_rcv+0x34e0/0x3ab0 net/ipv6/tcp_ipv6.c:1545
 ip6_input_finish+0x3fc/0x1aa0 net/ipv6/ip6_input.c:384
 NF_HOOK include/linux/netfilter.h:289 [inline]
 ip6_input+0xe4/0x600 net/ipv6/ip6_input.c:427
 dst_input include/net/dst.h:450 [inline]
 ip6_rcv_finish+0x17a/0x330 net/ipv6/ip6_input.c:76
 NF_HOOK include/linux/netfilter.h:289 [inline]
 ipv6_rcv+0x110/0x630 net/ipv6/ip6_input.c:272
 __netif_receive_skb_one_core+0x14d/0x200 net/core/dev.c:4930
 __netif_receive_skb+0x27/0x1e0 net/core/dev.c:5040
 process_backlog+0x24e/0x7a0 net/core/dev.c:5844
 napi_poll net/core/dev.c:6264 [inline]
 net_rx_action+0x7fa/0x19b0 net/core/dev.c:6330
 __do_softirq+0x308/0xb7e kernel/softirq.c:292
 do_softirq_own_stack+0x2a/0x40 arch/x86/entry/entry_64.S:1023
 </IRQ>
 do_softirq.part.14+0x126/0x160 kernel/softirq.c:337
 do_softirq kernel/softirq.c:329 [inline]
 __local_bh_enable_ip+0x21d/0x260 kernel/softirq.c:189
 local_bh_enable include/linux/bottom_half.h:32 [inline]
 rcu_read_unlock_bh include/linux/rcupdate.h:696 [inline]
 ip6_finish_output2+0xce4/0x27a0 net/ipv6/ip6_output.c:121
 ip6_finish_output+0x468/0xc60 net/ipv6/ip6_output.c:154
 NF_HOOK_COND include/linux/netfilter.h:278 [inline]
 ip6_output+0x232/0x9d0 net/ipv6/ip6_output.c:171
 dst_output include/net/dst.h:444 [inline]
 NF_HOOK include/linux/netfilter.h:289 [inline]
 ip6_xmit+0xf64/0x2410 net/ipv6/ip6_output.c:275
 inet6_csk_xmit+0x375/0x630 net/ipv6/inet6_connection_sock.c:139
 __tcp_transmit_skb+0x1bc5/0x3b00 net/ipv4/tcp_output.c:1162
 tcp_transmit_skb net/ipv4/tcp_output.c:1178 [inline]
 tcp_write_xmit+0x1676/0x5710 net/ipv4/tcp_output.c:2364
 tcp_push_one+0xdd/0x110 net/ipv4/tcp_output.c:2551
 tcp_sendmsg_locked+0xbc3/0x3fa0 net/ipv4/tcp.c:1386
 tcp_sendmsg+0x2f/0x50 net/ipv4/tcp.c:1443
 inet_sendmsg+0x19c/0x690 net/ipv4/af_inet.c:798
 sock_sendmsg_nosec net/socket.c:622 [inline]
 sock_sendmsg+0xd5/0x120 net/socket.c:632
 __sys_sendto+0x3d7/0x670 net/socket.c:1789
 __do_sys_sendto net/socket.c:1801 [inline]
 __se_sys_sendto net/socket.c:1797 [inline]
 __x64_sys_sendto+0xe1/0x1a0 net/socket.c:1797
 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
 entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x457569
Code: fd b3 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 cb b3 fb ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007f438931cc78 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
RAX: ffffffffffffffda RBX: 0000000000000006 RCX: 0000000000457569
RDX: fffffffffffffedd RSI: 0000000020000280 RDI: 0000000000000005
RBP: 000000000072bf00 R08: 0000000020000080 R09: 000000000000001c
R10: 000000002000012c R11: 0000000000000246 R12: 00007f438931d6d4
R13: 00000000004c3921 R14: 00000000004d57d8 R15: 00000000ffffffff
Kernel Offset: disabled
Rebooting in 86400 seconds..
Daniel Borkmann Oct. 16, 2018, 2:29 p.m. UTC | #2
On 10/16/2018 04:17 PM, Eric Dumazet wrote:
> On 10/12/2018 05:45 PM, Daniel Borkmann wrote:
[...]
>> diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c
>> index a5995bb..34e9635 100644
>> --- a/net/ipv4/tcp_ulp.c
>> +++ b/net/ipv4/tcp_ulp.c
>> @@ -123,6 +123,8 @@ void tcp_cleanup_ulp(struct sock *sk)
>>  {
>>  	struct inet_connection_sock *icsk = inet_csk(sk);
>>  
>> +	sock_owned_by_me(sk);
>> +
>>  	if (!icsk->icsk_ulp_ops)
>>  		return;
> 
> Ahem... inet_csk_prepare_forced_close() releases the socket lock,
> and tcp_done(newsk); is called after inet_csk_prepare_forced_close() 

Right you are, will fix it up. Thanks!
diff mbox series

Patch

diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c
index a5995bb..34e9635 100644
--- a/net/ipv4/tcp_ulp.c
+++ b/net/ipv4/tcp_ulp.c
@@ -123,6 +123,8 @@  void tcp_cleanup_ulp(struct sock *sk)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	sock_owned_by_me(sk);
+
 	if (!icsk->icsk_ulp_ops)
 		return;
 
@@ -140,6 +142,7 @@  int tcp_set_ulp(struct sock *sk, const char *name)
 	const struct tcp_ulp_ops *ulp_ops;
 	int err = 0;
 
+	sock_owned_by_me(sk);
 	if (icsk->icsk_ulp_ops)
 		return -EEXIST;
 
@@ -168,6 +171,7 @@  int tcp_set_ulp_id(struct sock *sk, int ulp)
 	const struct tcp_ulp_ops *ulp_ops;
 	int err;
 
+	sock_owned_by_me(sk);
 	if (icsk->icsk_ulp_ops)
 		return -EEXIST;