Bug #395
closedUse after free in RTR4 code
0%
Description
Just compiled a new linux-next kernel as described in https://www.open-mesh.org/projects/open-mesh/wiki/Emulation_Debug/38 and linux v4.19.56. Batman-adv was e2b064ff5cf53e75fb8176b1c749474366a20ab9 with the two attached patches (sorry that it was an unclean test environment). I have then bridged my local node to a freifunk vogtland mesh node.
The freifunk vogtland node was just using one ethernet device (eth0) as slave of its bat0 device. And I was therefore able to see the mesh traffic in my virtual machine. And thus it could participate in the mesh via its own bat0 interface.
The node was pinging the IPv6 address of the freifunk vogtland node for some hours and suddenly I saw following error:
Message from syslogd@sven-edge at Jul 7 16:49:57 ... kernel:page:ffffea00001ed000 count:1 mapcount:0 mapping:ffff88801a40c000 index:0xffff888007b43b80 compound_mapcount: 0 Message from syslogd@sven-edge at Jul 7 16:49:57 ... kernel:flags: 0x4000000000008100(slab|head)
The oops for that was:
[ 5074.200617] ================================================================== [ 5074.202112] BUG: KASAN: use-after-free in batadv_mcast_want_rtr4_update+0x335/0x3a0 [batman_adv] [ 5074.203871] Write of size 8 at addr ffff888007b41a38 by task swapper/0/0 [ 5074.205232] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 4.19.56 #1 [ 5074.206686] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 [ 5074.208356] Call Trace: [ 5074.208661] <IRQ> [ 5074.208862] dump_stack+0x9a/0xf0 [ 5074.209458] print_address_description.cold.1+0x9/0x225 [ 5074.210472] kasan_report.cold.2+0x6d/0xa0 [ 5074.211221] batadv_mcast_want_rtr4_update+0x335/0x3a0 [batman_adv] [ 5074.212493] batadv_mcast_purge_orig+0x71/0xa0 [batman_adv] [ 5074.213591] batadv_orig_node_free_rcu+0x19/0x60 [batman_adv] [ 5074.214734] ? batadv_frag_check_entry+0x90/0x90 [batman_adv] [ 5074.215865] rcu_process_callbacks+0xab1/0x1950 [ 5074.216706] ? call_rcu_sched+0x20/0x20 [ 5074.217382] __do_softirq+0x238/0x987 [ 5074.218017] irq_exit+0x101/0x130 [ 5074.218567] smp_apic_timer_interrupt+0x16e/0x510 [ 5074.219445] apic_timer_interrupt+0xf/0x20 [ 5074.220155] </IRQ> [ 5074.220406] RIP: 0010:native_safe_halt+0x24/0x30 [ 5074.221238] Code: 00 00 00 00 00 90 be 04 00 00 00 48 c7 c7 40 f7 00 84 e8 1f b4 fb fe 8b 05 59 a7 af 01 85 c0 7e 07 0f 00 2d 0e 39 52 00 fb f4 <c3> 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 41 57 41 56 41 [ 5074.225342] RSP: 0018:ffffffff83007de0 EFLAGS: 00000246 ORIG_RAX: ffffffffffffff13 [ 5074.226802] RAX: 0000000000000000 RBX: ffffffff83761ea8 RCX: ffffffff82514fe1 [ 5074.228036] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffff8400f740 [ 5074.229251] RBP: dffffc0000000000 R08: fffffbfff0801ee9 R09: fffffbfff0801ee8 [ 5074.230475] R10: fffffbfff0801ee8 R11: 0000000000000003 R12: 0000000000000000 [ 5074.231694] R13: 0000000000000000 R14: ffffffff8376c7a8 R15: ffffffff83007e50 [ 5074.232913] ? native_safe_halt+0x11/0x30 [ 5074.233495] default_idle+0x68/0x340 [ 5074.233989] do_idle+0x264/0x2c0 [ 5074.234418] ? arch_cpu_idle_exit+0x40/0x40 [ 5074.235033] ? finish_task_switch+0x214/0x620 [ 5074.235679] cpu_startup_entry+0x19/0x1b [ 5074.236240] start_kernel+0x473/0x494 [ 5074.236749] ? mem_encrypt_init+0x6/0x6 [ 5074.237290] ? memcpy_orig+0x54/0x110 [ 5074.237796] secondary_startup_64+0xa4/0xb0 [ 5074.238481] Allocated by task 0: [ 5074.238901] kasan_kmalloc+0xbf/0xe0 [ 5074.239400] __kmalloc_track_caller+0x114/0x2c0 [ 5074.240084] __kmalloc_reserve.isra.7+0x29/0xa0 [ 5074.240774] __alloc_skb+0x100/0x550 [ 5074.241269] skb_copy+0x10c/0x2d0 [ 5074.241718] batadv_iv_ogm_process_per_outif+0xba/0x2f80 [batman_adv] [ 5074.242806] batadv_iv_ogm_receive+0x980/0x1690 [batman_adv] [ 5074.243760] batadv_batman_skb_recv+0x472/0x5a0 [batman_adv] [ 5074.244791] __netif_receive_skb_one_core+0xda/0x140 [ 5074.245659] netif_receive_skb_internal+0x12a/0x3e0 [ 5074.246513] napi_gro_receive+0x1d0/0x340 [ 5074.247162] receive_buf+0x5b3/0x2320 [ 5074.247726] virtnet_poll+0x6fd/0xca9 [ 5074.248297] net_rx_action+0x30d/0xba0 [ 5074.248886] __do_softirq+0x238/0x987 [ 5074.249516] Freed by task 0: [ 5074.249901] __kasan_slab_free+0x12e/0x180 [ 5074.250570] kfree+0x117/0x2e0 [ 5074.250997] consume_skb+0xc6/0x280 [ 5074.251529] batadv_iv_ogm_process_per_outif+0x82e/0x2f80 [batman_adv] [ 5074.252756] batadv_iv_ogm_receive+0x980/0x1690 [batman_adv] [ 5074.253784] batadv_batman_skb_recv+0x472/0x5a0 [batman_adv] [ 5074.254811] __netif_receive_skb_one_core+0xda/0x140 [ 5074.255666] netif_receive_skb_internal+0x12a/0x3e0 [ 5074.256518] napi_gro_receive+0x1d0/0x340 [ 5074.257162] receive_buf+0x5b3/0x2320 [ 5074.257714] virtnet_poll+0x6fd/0xca9 [ 5074.258305] net_rx_action+0x30d/0xba0 [ 5074.258908] __do_softirq+0x238/0x987 [ 5074.259568] The buggy address belongs to the object at ffff888007b41980 which belongs to the cache kmalloc-2048 of size 2048 [ 5074.261891] The buggy address is located 184 bytes inside of 2048-byte region [ffff888007b41980, ffff888007b42180) [ 5074.263797] The buggy address belongs to the page: [ 5074.264537] page:ffffea00001ed000 count:1 mapcount:0 mapping:ffff88801a40c000 index:0xffff888007b43b80 compound_mapcount: 0 [ 5074.266636] flags: 0x4000000000008100(slab|head) [ 5074.267421] raw: 4000000000008100 ffffea00002f8600 0000000400000004 ffff88801a40c000 [ 5074.268941] raw: ffff888007b43b80 00000000800f0003 00000001ffffffff 0000000000000000 [ 5074.270474] page dumped because: kasan: bad access detected [ 5074.271569] Memory state around the buggy address: [ 5074.272416] ffff888007b41900: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 5074.273807] ffff888007b41980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 5074.275213] >ffff888007b41a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 5074.276614] ^ [ 5074.277516] ffff888007b41a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 5074.278930] ffff888007b41b00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 5074.280261] ==================================================================
Some interesting address translations for you
# use-after-free $ ./scripts/faddr2line ../batman-adv/net/batman-adv/batman-adv.o 'batadv_mcast_want_rtr4_update+0x335/0x3a0' batadv_mcast_want_rtr4_update+0x335/0x3a0: hlist_add_head_rcu at /home/sven/tmp/qemu-batman/linux-next/./include/linux/rculist.h:516 (inlined by) batadv_mcast_want_rtr4_update at /home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/multicast.c:1902 $ gdb net/batman-adv/batman-adv.ko (gdb) l *(&batadv_mcast_want_rtr4_update+0x335) 0x36785 is in batadv_mcast_want_rtr4_update (./include/linux/list.h:666). 661 h->pprev = NULL; 662 } 663 664 static inline int hlist_unhashed(const struct hlist_node *h) 665 { 666 return !h->pprev; 667 } 668 669 static inline int hlist_empty(const struct hlist_head *h) 670 { $ ./scripts/faddr2line ../batman-adv/net/batman-adv/batman-adv.o 'batadv_mcast_purge_orig+0x71' batadv_mcast_purge_orig+0x71/0xa0: batadv_mcast_purge_orig at /home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/multicast.c:2424 $ gdb net/batman-adv/batman-adv.ko (gdb) l *(&batadv_mcast_purge_orig+0x71) 0x3db51 is in batadv_mcast_purge_orig (/home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/multicast.c:2424). 2419 2420 batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS); 2421 batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS); 2422 batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS); 2423 batadv_mcast_want_rtr4_update(bat_priv, orig, BATADV_NO_FLAGS); 2424 batadv_mcast_want_rtr6_update(bat_priv, orig, BATADV_NO_FLAGS); 2425 2426 spin_unlock_bh(&orig->mcast_handler_lock); 2427 } $ ./scripts/faddr2line ../batman-adv/net/batman-adv/batman-adv.o 'batadv_orig_node_free_rcu+0x19' batadv_orig_node_free_rcu+0x19/0x60: batadv_orig_node_free_rcu at /home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/originator.c:894 $ gdb net/batman-adv/batman-adv.ko (gdb) l *(&batadv_orig_node_free_rcu+0x19) 0x43009 is in batadv_orig_node_free_rcu (/home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/originator.c:894). 889 890 orig_node = container_of(rcu, struct batadv_orig_node, rcu); 891 892 batadv_mcast_purge_orig(orig_node); 893 894 batadv_frag_purge_orig(orig_node, NULL); 895 896 kfree(orig_node->tt_buff); 897 kfree(orig_node); 898 } # allocated $ ./scripts/faddr2line vmlinux.o 'skb_copy+0x10c/0x2d0' skb_copy+0x10c/0x2d0: skb_copy at /home/sven/tmp/qemu-batman/linux-next/net/core/skbuff.c:1349 $ ./scripts/faddr2line ../batman-adv/net/batman-adv/batman-adv.o 'batadv_iv_ogm_process_per_outif+0xba/0x2f80' skipping batadv_iv_ogm_process_per_outif address at 0x6a6a due to size mismatch (0x2f80 != 0x10b0) no match for batadv_iv_ogm_process_per_outif+0xba/0x2f80 $ gdb net/batman-adv/batman-adv.ko (gdb) l *(&batadv_iv_ogm_process_per_outif+0xba) 0x6aaa is in batadv_iv_ogm_process_per_outif (/home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/bat_iv_ogm.c:1285). 1280 bool is_bidirect; 1281 1282 /* create a private copy of the skb, as some functions change tq value 1283 * and/or flags. 1284 */ 1285 skb_priv = skb_copy(skb, GFP_ATOMIC); 1286 if (!skb_priv) 1287 return; 1288 1289 ethhdr = eth_hdr(skb_priv); # freed $ ./scripts/faddr2line ../batman-adv/net/batman-adv/batman-adv.o 'batadv_iv_ogm_process_per_outif+0x82e' batadv_iv_ogm_process_per_outif+0x82e/0x10b0: batadv_iv_ogm_process_per_outif at /home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/bat_iv_ogm.c:1263 (gdb) l *(&batadv_iv_ogm_process_per_outif+0x82e) 0x721e is in batadv_iv_ogm_process_per_outif (/home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/bat_iv_ogm.c:1454). 1449 if (orig_neigh_router) 1450 batadv_neigh_node_put(orig_neigh_router); 1451 if (hardif_neigh) 1452 batadv_hardif_neigh_put(hardif_neigh); 1453 1454 consume_skb(skb_priv); 1455 } 1456 1457 /** 1458 * batadv_iv_ogm_process_reply() - Check OGM for direct reply and process it # common for allocated + freed $ ./scripts/faddr2line ../batman-adv/net/batman-adv/batman-adv.o 'batadv_iv_ogm_receive+0x980/0x1690' batadv_iv_ogm_receive+0x980/0x1690: __preempt_count_add at /home/sven/tmp/qemu-batman/linux-next/./arch/x86/include/asm/preempt.h:76 (inlined by) __rcu_read_lock at /home/sven/tmp/qemu-batman/linux-next/./include/linux/rcupdate.h:81 (inlined by) rcu_read_lock at /home/sven/tmp/qemu-batman/linux-next/./include/linux/rcupdate.h:625 (inlined by) batadv_iv_ogm_process at /home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/bat_iv_ogm.c:1619 (inlined by) batadv_iv_ogm_receive at /home/sven/tmp/qemu-batman/batman-adv/net/batman-adv/bat_iv_ogm.c:1708 $ gdb net/batman-adv/batman-adv.ko (gdb) l *(&batadv_iv_ogm_receive+0x980) 0xa2f0 is in batadv_iv_ogm_receive (./arch/x86/include/asm/preempt.h:76). 71 * The various preempt_count add/sub methods 72 */ 73 74 static __always_inline void __preempt_count_add(int val) 75 { 76 raw_cpu_add_4(__preempt_count, val); 77 } 78 79 static __always_inline void __preempt_count_sub(int val) 80 {
Please check whether this looks to you more like an bug in the RCU implementation or whether this could actually be related to your multicast code.
Files