diff options
author | Eric Dumazet <edumazet@google.com> | 2017-10-20 12:04:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-20 20:33:19 -0400 |
commit | c92e8c02fe664155ac4234516e32544bec0f113d (patch) | |
tree | bd3b3d5757c511e32391283a37bba7c924906a9f /net/ipv4/tcp_ipv4.c | |
parent | e95c6cf447ecac5ab5bc38600e1d2ac7b3d54aae (diff) |
tcp/dccp: fix ireq->opt races
syzkaller found another bug in DCCP/TCP stacks [1]
For the reasons explained in commit ce1050089c96 ("tcp/dccp: fix
ireq->pktopts race"), we need to make sure we do not access
ireq->opt unless we own the request sock.
Note the opt field is renamed to ireq_opt to ease grep games.
[1]
BUG: KASAN: use-after-free in ip_queue_xmit+0x1687/0x18e0 net/ipv4/ip_output.c:474
Read of size 1 at addr ffff8801c951039c by task syz-executor5/3295
CPU: 1 PID: 3295 Comm: syz-executor5 Not tainted 4.14.0-rc4+ #80
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
__dump_stack lib/dump_stack.c:16 [inline]
dump_stack+0x194/0x257 lib/dump_stack.c:52
print_address_description+0x73/0x250 mm/kasan/report.c:252
kasan_report_error mm/kasan/report.c:351 [inline]
kasan_report+0x25b/0x340 mm/kasan/report.c:409
__asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:427
ip_queue_xmit+0x1687/0x18e0 net/ipv4/ip_output.c:474
tcp_transmit_skb+0x1ab7/0x3840 net/ipv4/tcp_output.c:1135
tcp_send_ack.part.37+0x3bb/0x650 net/ipv4/tcp_output.c:3587
tcp_send_ack+0x49/0x60 net/ipv4/tcp_output.c:3557
__tcp_ack_snd_check+0x2c6/0x4b0 net/ipv4/tcp_input.c:5072
tcp_ack_snd_check net/ipv4/tcp_input.c:5085 [inline]
tcp_rcv_state_process+0x2eff/0x4850 net/ipv4/tcp_input.c:6071
tcp_child_process+0x342/0x990 net/ipv4/tcp_minisocks.c:816
tcp_v4_rcv+0x1827/0x2f80 net/ipv4/tcp_ipv4.c:1682
ip_local_deliver_finish+0x2e2/0xba0 net/ipv4/ip_input.c:216
NF_HOOK include/linux/netfilter.h:249 [inline]
ip_local_deliver+0x1ce/0x6e0 net/ipv4/ip_input.c:257
dst_input include/net/dst.h:464 [inline]
ip_rcv_finish+0x887/0x19a0 net/ipv4/ip_input.c:397
NF_HOOK include/linux/netfilter.h:249 [inline]
ip_rcv+0xc3f/0x1820 net/ipv4/ip_input.c:493
__netif_receive_skb_core+0x1a3e/0x34b0 net/core/dev.c:4476
__netif_receive_skb+0x2c/0x1b0 net/core/dev.c:4514
netif_receive_skb_internal+0x10b/0x670 net/core/dev.c:4587
netif_receive_skb+0xae/0x390 net/core/dev.c:4611
tun_rx_batched.isra.50+0x5ed/0x860 drivers/net/tun.c:1372
tun_get_user+0x249c/0x36d0 drivers/net/tun.c:1766
tun_chr_write_iter+0xbf/0x160 drivers/net/tun.c:1792
call_write_iter include/linux/fs.h:1770 [inline]
new_sync_write fs/read_write.c:468 [inline]
__vfs_write+0x68a/0x970 fs/read_write.c:481
vfs_write+0x18f/0x510 fs/read_write.c:543
SYSC_write fs/read_write.c:588 [inline]
SyS_write+0xef/0x220 fs/read_write.c:580
entry_SYSCALL_64_fastpath+0x1f/0xbe
RIP: 0033:0x40c341
RSP: 002b:00007f469523ec10 EFLAGS: 00000293 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000000000718000 RCX: 000000000040c341
RDX: 0000000000000037 RSI: 0000000020004000 RDI: 0000000000000015
RBP: 0000000000000086 R08: 0000000000000000 R09: 0000000000000000
R10: 00000000000f4240 R11: 0000000000000293 R12: 00000000004b7fd1
R13: 00000000ffffffff R14: 0000000020000000 R15: 0000000000025000
Allocated by task 3295:
save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
save_stack+0x43/0xd0 mm/kasan/kasan.c:447
set_track mm/kasan/kasan.c:459 [inline]
kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:551
__do_kmalloc mm/slab.c:3725 [inline]
__kmalloc+0x162/0x760 mm/slab.c:3734
kmalloc include/linux/slab.h:498 [inline]
tcp_v4_save_options include/net/tcp.h:1962 [inline]
tcp_v4_init_req+0x2d3/0x3e0 net/ipv4/tcp_ipv4.c:1271
tcp_conn_request+0xf6d/0x3410 net/ipv4/tcp_input.c:6283
tcp_v4_conn_request+0x157/0x210 net/ipv4/tcp_ipv4.c:1313
tcp_rcv_state_process+0x8ea/0x4850 net/ipv4/tcp_input.c:5857
tcp_v4_do_rcv+0x55c/0x7d0 net/ipv4/tcp_ipv4.c:1482
tcp_v4_rcv+0x2d10/0x2f80 net/ipv4/tcp_ipv4.c:1711
ip_local_deliver_finish+0x2e2/0xba0 net/ipv4/ip_input.c:216
NF_HOOK include/linux/netfilter.h:249 [inline]
ip_local_deliver+0x1ce/0x6e0 net/ipv4/ip_input.c:257
dst_input include/net/dst.h:464 [inline]
ip_rcv_finish+0x887/0x19a0 net/ipv4/ip_input.c:397
NF_HOOK include/linux/netfilter.h:249 [inline]
ip_rcv+0xc3f/0x1820 net/ipv4/ip_input.c:493
__netif_receive_skb_core+0x1a3e/0x34b0 net/core/dev.c:4476
__netif_receive_skb+0x2c/0x1b0 net/core/dev.c:4514
netif_receive_skb_internal+0x10b/0x670 net/core/dev.c:4587
netif_receive_skb+0xae/0x390 net/core/dev.c:4611
tun_rx_batched.isra.50+0x5ed/0x860 drivers/net/tun.c:1372
tun_get_user+0x249c/0x36d0 drivers/net/tun.c:1766
tun_chr_write_iter+0xbf/0x160 drivers/net/tun.c:1792
call_write_iter include/linux/fs.h:1770 [inline]
new_sync_write fs/read_write.c:468 [inline]
__vfs_write+0x68a/0x970 fs/read_write.c:481
vfs_write+0x18f/0x510 fs/read_write.c:543
SYSC_write fs/read_write.c:588 [inline]
SyS_write+0xef/0x220 fs/read_write.c:580
entry_SYSCALL_64_fastpath+0x1f/0xbe
Freed by task 3306:
save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
save_stack+0x43/0xd0 mm/kasan/kasan.c:447
set_track mm/kasan/kasan.c:459 [inline]
kasan_slab_free+0x71/0xc0 mm/kasan/kasan.c:524
__cache_free mm/slab.c:3503 [inline]
kfree+0xca/0x250 mm/slab.c:3820
inet_sock_destruct+0x59d/0x950 net/ipv4/af_inet.c:157
__sk_destruct+0xfd/0x910 net/core/sock.c:1560
sk_destruct+0x47/0x80 net/core/sock.c:1595
__sk_free+0x57/0x230 net/core/sock.c:1603
sk_free+0x2a/0x40 net/core/sock.c:1614
sock_put include/net/sock.h:1652 [inline]
inet_csk_complete_hashdance+0xd5/0xf0 net/ipv4/inet_connection_sock.c:959
tcp_check_req+0xf4d/0x1620 net/ipv4/tcp_minisocks.c:765
tcp_v4_rcv+0x17f6/0x2f80 net/ipv4/tcp_ipv4.c:1675
ip_local_deliver_finish+0x2e2/0xba0 net/ipv4/ip_input.c:216
NF_HOOK include/linux/netfilter.h:249 [inline]
ip_local_deliver+0x1ce/0x6e0 net/ipv4/ip_input.c:257
dst_input include/net/dst.h:464 [inline]
ip_rcv_finish+0x887/0x19a0 net/ipv4/ip_input.c:397
NF_HOOK include/linux/netfilter.h:249 [inline]
ip_rcv+0xc3f/0x1820 net/ipv4/ip_input.c:493
__netif_receive_skb_core+0x1a3e/0x34b0 net/core/dev.c:4476
__netif_receive_skb+0x2c/0x1b0 net/core/dev.c:4514
netif_receive_skb_internal+0x10b/0x670 net/core/dev.c:4587
netif_receive_skb+0xae/0x390 net/core/dev.c:4611
tun_rx_batched.isra.50+0x5ed/0x860 drivers/net/tun.c:1372
tun_get_user+0x249c/0x36d0 drivers/net/tun.c:1766
tun_chr_write_iter+0xbf/0x160 drivers/net/tun.c:1792
call_write_iter include/linux/fs.h:1770 [inline]
new_sync_write fs/read_write.c:468 [inline]
__vfs_write+0x68a/0x970 fs/read_write.c:481
vfs_write+0x18f/0x510 fs/read_write.c:543
SYSC_write fs/read_write.c:588 [inline]
SyS_write+0xef/0x220 fs/read_write.c:580
entry_SYSCALL_64_fastpath+0x1f/0xbe
Fixes: e994b2f0fb92 ("tcp: do not lock listener to process SYN packets")
Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 85164d4d3e53..4c43365c374c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -877,7 +877,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
877 | 877 | ||
878 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, | 878 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, |
879 | ireq->ir_rmt_addr, | 879 | ireq->ir_rmt_addr, |
880 | ireq->opt); | 880 | rcu_dereference(ireq->ireq_opt)); |
881 | err = net_xmit_eval(err); | 881 | err = net_xmit_eval(err); |
882 | } | 882 | } |
883 | 883 | ||
@@ -889,7 +889,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
889 | */ | 889 | */ |
890 | static void tcp_v4_reqsk_destructor(struct request_sock *req) | 890 | static void tcp_v4_reqsk_destructor(struct request_sock *req) |
891 | { | 891 | { |
892 | kfree(inet_rsk(req)->opt); | 892 | kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); |
893 | } | 893 | } |
894 | 894 | ||
895 | #ifdef CONFIG_TCP_MD5SIG | 895 | #ifdef CONFIG_TCP_MD5SIG |
@@ -1265,10 +1265,11 @@ static void tcp_v4_init_req(struct request_sock *req, | |||
1265 | struct sk_buff *skb) | 1265 | struct sk_buff *skb) |
1266 | { | 1266 | { |
1267 | struct inet_request_sock *ireq = inet_rsk(req); | 1267 | struct inet_request_sock *ireq = inet_rsk(req); |
1268 | struct net *net = sock_net(sk_listener); | ||
1268 | 1269 | ||
1269 | sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); | 1270 | sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); |
1270 | sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); | 1271 | sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); |
1271 | ireq->opt = tcp_v4_save_options(sock_net(sk_listener), skb); | 1272 | RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); |
1272 | } | 1273 | } |
1273 | 1274 | ||
1274 | static struct dst_entry *tcp_v4_route_req(const struct sock *sk, | 1275 | static struct dst_entry *tcp_v4_route_req(const struct sock *sk, |
@@ -1355,10 +1356,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, | |||
1355 | sk_daddr_set(newsk, ireq->ir_rmt_addr); | 1356 | sk_daddr_set(newsk, ireq->ir_rmt_addr); |
1356 | sk_rcv_saddr_set(newsk, ireq->ir_loc_addr); | 1357 | sk_rcv_saddr_set(newsk, ireq->ir_loc_addr); |
1357 | newsk->sk_bound_dev_if = ireq->ir_iif; | 1358 | newsk->sk_bound_dev_if = ireq->ir_iif; |
1358 | newinet->inet_saddr = ireq->ir_loc_addr; | 1359 | newinet->inet_saddr = ireq->ir_loc_addr; |
1359 | inet_opt = ireq->opt; | 1360 | inet_opt = rcu_dereference(ireq->ireq_opt); |
1360 | rcu_assign_pointer(newinet->inet_opt, inet_opt); | 1361 | RCU_INIT_POINTER(newinet->inet_opt, inet_opt); |
1361 | ireq->opt = NULL; | ||
1362 | newinet->mc_index = inet_iif(skb); | 1362 | newinet->mc_index = inet_iif(skb); |
1363 | newinet->mc_ttl = ip_hdr(skb)->ttl; | 1363 | newinet->mc_ttl = ip_hdr(skb)->ttl; |
1364 | newinet->rcv_tos = ip_hdr(skb)->tos; | 1364 | newinet->rcv_tos = ip_hdr(skb)->tos; |
@@ -1403,9 +1403,12 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, | |||
1403 | if (__inet_inherit_port(sk, newsk) < 0) | 1403 | if (__inet_inherit_port(sk, newsk) < 0) |
1404 | goto put_and_exit; | 1404 | goto put_and_exit; |
1405 | *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); | 1405 | *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); |
1406 | if (*own_req) | 1406 | if (likely(*own_req)) { |
1407 | tcp_move_syn(newtp, req); | 1407 | tcp_move_syn(newtp, req); |
1408 | 1408 | ireq->ireq_opt = NULL; | |
1409 | } else { | ||
1410 | newinet->inet_opt = NULL; | ||
1411 | } | ||
1409 | return newsk; | 1412 | return newsk; |
1410 | 1413 | ||
1411 | exit_overflow: | 1414 | exit_overflow: |
@@ -1416,6 +1419,7 @@ exit: | |||
1416 | tcp_listendrop(sk); | 1419 | tcp_listendrop(sk); |
1417 | return NULL; | 1420 | return NULL; |
1418 | put_and_exit: | 1421 | put_and_exit: |
1422 | newinet->inet_opt = NULL; | ||
1419 | inet_csk_prepare_forced_close(newsk); | 1423 | inet_csk_prepare_forced_close(newsk); |
1420 | tcp_done(newsk); | 1424 | tcp_done(newsk); |
1421 | goto exit; | 1425 | goto exit; |