Uninitialized value in __sk_nulls_add_node_rcu()
Subsystems (4)
Quoted 10 lines · Eric Dumazet
Quoted 9 lines · Craig Gallek
Quoted 6 lines · Eric Dumazet
Quoted 2 lines · Eric Dumazet
+
hlist_nulls_add_head_rcu(&sk->sk_nulss_node, list);Typo here, this needs
sk_nulls_nodeof course.
Quoted 8 lines
Quoted 6 lines
Thanks Eric, this looks good to me. The tail insertion is still required in
udp_lib_get_portfor the second layer hash, but not here. fwiw,reuseport_dualstackin the selftests directory verifies this behavior. I tried it with your patch (it still passes) and removing theudp_lib_get_portpath (to make sure it breaks when it should).Thanks for confirming this, I will send the official patch then ;)
Great, feel free to include my Acked-by.
PATCH 1/1 net: remove hlist_nulls_add_tail_rcu()
From: Eric Dumazet <[email protected]>
Alexander Potapenko reported use of uninitialized memory [1]
This happens when inserting a request socket into TCP ehash, in __sk_nulls_add_node_rcu(), since sk_reuseport is not initialized.
Bug was added by commit d894ba18d4e4 ("soreuseport: fix ordering for mixed v4/v6 sockets")
Note that d296ba60d8e2 ("soreuseport: Resolve merge conflict for v4/v6 ordering fix") missed the opportunity to get rid of hlist_nulls_add_tail_rcu() :
Both UDP sockets and TCP/DCCP listeners no longer use __sk_nulls_add_node_rcu() for their hash insertion.
Since all other sockets have unique 4-tuple, the reuseport status has no special meaning, so we can always use hlist_nulls_add_head_rcu() for them and save few cycles/instructions.
[1]
==================================================================
BUG: KMSAN: use of uninitialized memory in inet_ehash_insert+0xd40/0x1050 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.0+ #3288 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Call Trace: <IRQ> __dump_stack lib/dump_stack.c:16 dump_stack+0x185/0x1d0 lib/dump_stack.c:52 kmsan_report+0x13f/0x1c0 mm/kmsan/kmsan.c:1016 __msan_warning_32+0x69/0xb0 mm/kmsan/kmsan_instr.c:766 __sk_nulls_add_node_rcu ./include/net/sock.h:684 inet_ehash_insert+0xd40/0x1050 net/ipv4/inet_hashtables.c:413 reqsk_queue_hash_req net/ipv4/inet_connection_sock.c:754 inet_csk_reqsk_queue_hash_add+0x1cc/0x300 net/ipv4/inet_connection_sock.c:765 tcp_conn_request+0x31e7/0x36f0 net/ipv4/tcp_input.c:6414 tcp_v4_conn_request+0x16d/0x220 net/ipv4/tcp_ipv4.c:1314 tcp_rcv_state_process+0x42a/0x7210 net/ipv4/tcp_input.c:5917 tcp_v4_do_rcv+0xa6a/0xcd0 net/ipv4/tcp_ipv4.c:1483 tcp_v4_rcv+0x3de0/0x4ab0 net/ipv4/tcp_ipv4.c:1763 ip_local_deliver_finish+0x6bb/0xcb0 net/ipv4/ip_input.c:216 NF_HOOK ./include/linux/netfilter.h:248 ip_local_deliver+0x3fa/0x480 net/ipv4/ip_input.c:257 dst_input ./include/net/dst.h:477 ip_rcv_finish+0x6fb/0x1540 net/ipv4/ip_input.c:397 NF_HOOK ./include/linux/netfilter.h:248 ip_rcv+0x10f6/0x15c0 net/ipv4/ip_input.c:488 __netif_receive_skb_core+0x36f6/0x3f60 net/core/dev.c:4298 __netif_receive_skb net/core/dev.c:4336 netif_receive_skb_internal+0x63c/0x19c0 net/core/dev.c:4497 napi_skb_finish net/core/dev.c:4858 napi_gro_receive+0x629/0xa50 net/core/dev.c:4889 e1000_receive_skb drivers/net/ethernet/intel/e1000/e1000_main.c:4018 e1000_clean_rx_irq+0x1492/0x1d30 drivers/net/ethernet/intel/e1000/e1000_main.c:4474 e1000_clean+0x43aa/0x5970 drivers/net/ethernet/intel/e1000/e1000_main.c:3819 napi_poll net/core/dev.c:5500 net_rx_action+0x73c/0x1820 net/core/dev.c:5566 __do_softirq+0x4b4/0x8dd kernel/softirq.c:284 invoke_softirq kernel/softirq.c:364 irq_exit+0x203/0x240 kernel/softirq.c:405 exiting_irq+0xe/0x10 ./arch/x86/include/asm/apic.h:638 do_IRQ+0x15e/0x1a0 arch/x86/kernel/irq.c:263 common_interrupt+0x86/0x86
---
include/linux/rculist_nulls.h | 38 -------------------------------- include/net/sock.h | 6 -----
2 files changed, 1 insertion(+), 43 deletions(-)
include/linux/rculist_nulls.h +0 -38
@@ -100,44 +100,6 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, first->pprev = &n->next; } -/** -* hlist_nulls_add_tail_rcu -* @n: the element to add to the hash list. -* @h: the list to add to. -* -* Description: -* Adds the specified element to the end of the specified hlist_nulls, -* while permitting racing traversals. NOTE: tail insertion requires -* list traversal. -* -* The caller must take whatever precautions are necessary -* (such as holding appropriate locks) to avoid racing -* with another list-mutation primitive, such as hlist_nulls_add_head_rcu() -* or hlist_nulls_del_rcu(), running on this same list. -* However, it is perfectly legal to run concurrently with -* the _rcu list-traversal primitives, such as -* hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency -* problems on Alpha CPUs. Regardless of the type of CPU, the -* list-traversal primitive must be guarded by rcu_read_lock(). -*/ -static inline void hlist_nulls_add_tail_rcu (struct hlist_nulls_node *n, -struct hlist_nulls_head *h) -{ -struct hlist_nulls_node *i, *last =NULL ; - -for (i =hlist_nulls_first_rcu (h); !is_a_nulls (i); - i =hlist_nulls_next_rcu (i)) - last = i; - -if (last) { - n->next = last->next; - n->pprev = &last->next; -rcu_assign_pointer (hlist_nulls_next_rcu (last), n); - }else { -hlist_nulls_add_head_rcu (n, h); - } -} -/** * hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type * @tpos: the type * to use as a loop cursor.
include/net/sock.h +1 -5
@@ -685,11 +685,7 @@ static inline void sk_add_node_rcu(struct sock *sk, struct hlist_head *list)static inline void __sk_nulls_add_node_rcu (struct sock *sk,struct hlist_nulls_head *list) { -if (IS_ENABLED (CONFIG_IPV6 ) && sk->sk_reuseport && - sk->sk_family ==AF_INET6 ) -hlist_nulls_add_tail_rcu (&sk->sk_nulls_node, list); -else -hlist_nulls_add_head_rcu (&sk->sk_nulls_node, list); +hlist_nulls_add_head_rcu (&sk->sk_nulls_node, list); }static inline void sk_nulls_add_node_rcu (struct sock *sk,struct hlist_nulls_head *list)
David Miller
maintainerRe: [PATCH net] net: remove hlist_nulls_add_tail_rcu()
From: Eric Dumazet <[email protected]>
Date: Tue, 05 Dec 2017 12:45:56 -0800
Quoted 22 lines
From: Eric Dumazet <[email protected]>
Alexander Potapenko reported use of uninitialized memory [1]
This happens when inserting a request socket into TCP ehash, in
__sk_nulls_add_node_rcu(), sincesk_reuseportis not initialized.Bug was added by commit
d894ba18d4e4("soreuseport: fix ordering for mixed v4/v6 sockets")Note that
d296ba60d8e2("soreuseport: Resolve merge conflict for v4/v6 ordering fix") missed the opportunity to get rid ofhlist_nulls_add_tail_rcu():Both UDP sockets and TCP/DCCP listeners no longer use
__sk_nulls_add_node_rcu()for their hash insertion.Since all other sockets have unique 4-tuple, the reuseport status has no special meaning, so we can always use
hlist_nulls_add_head_rcu()for them and save few cycles/instructions.[1]
...
Quoted 5 lines
Fixes d894ba18d4e4 ("soreuseport: fix ordering for mixed v4/v6 sockets")Fixes d296ba60d8e2 ("soreuseport: Resolve merge conflict for v4/v6 ordering fix")Signed-off-by Eric Dumazet <[email protected]>Reported-by Alexander Potapenko <[email protected]>Acked-by Craig Gallek <[email protected]>
I was just talking with Craig and Willem about this change the other day, what a coincidence :-)
Applied and queued up for -stable, thanks Eric.