| Message ID | 20260901115021.50057-1-ihuguet@riseup.net |
|---|---|
| State | Changes Requested |
| Headers | show |
| Series | [net] net/ipv6: don't route packets with unknown source address | expand |
Hi Íñigo, On 01/09/2026 13:50, Íñigo Huguet wrote: > Don't allow routing packets with a source address that is not configured > in the host. Allow it only in certain cases like when using a > transparent socket, by setting the ANYSRC flag in flowi_flags. > > Until now, it was possible to send such a packet if a route can be found > in the routing table for it. For example: > 1. Configure an address 1:2::3:4/64 and a static route 1:2::/64 > 2. Establish a TCP connection to 1:2::3:4 > 3. Remove the address from the interface, but keep the route. > 4. Packets are still sent out by the TCP connection because of > the static route. No incoming packets are accepted, though. > > This patch prevents the outgoing packets to be sent in normal > circumnstances. > > This aligns the behaviour with the IPv4 stack. To determine the places > where the ANYSRC needs to be set, I set the flag in the same places as > the IPv4 stack does. > > Apart from consolidating the behaviour of both stacks, there is a more > important reason why this is needed. RFC 4862 states that "an invalid > address MUST NOT be used as the source address of outbound packets". > Therefore, sending packets with a source address considered "invalid", > like an expired address, is disallowed. Thank you for looking at this, but I think your patch is causing multiple KASAN warnings, e.g. https://netdev-ctrl.bots.linux.dev/logs/vmksft/net-extra-dbg/results/804584/24-connect-deny-ipv6/stderr And a few more, see: https://netdev.bots.linux.dev/branch_deltas/net-next-2026-09-01--15-01.html Cheers, Matt
syzbot ci has tested the following series [v1] net/ipv6: don't route packets with unknown source address https://lore.kernel.org/all/20260901115021.50057-1-ihuguet@riseup.net * [PATCH net] net/ipv6: don't route packets with unknown source address and found the following issues: * KASAN: slab-out-of-bounds Read in tcp_v6_send_response * KASAN: use-after-free Read in tcp_v6_send_response Full report is available here: https://ci.syzbot.org/series/bf5b7c3c-6165-4e2e-b403-34a698f5ee76 *** KASAN: slab-out-of-bounds Read in tcp_v6_send_response tree: net URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net.git base: 1d2929d0850fff683b8aff051275945e65f082c8 arch: amd64 compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8 config: https://ci.syzbot.org/builds/19ac2ebf-5913-40a0-982b-446415180382/config syz repro: https://ci.syzbot.org/findings/103185a7-eed2-413d-9bb8-0cfd4d802dbb/syz_repro ================================================================== BUG: KASAN: slab-out-of-bounds in instrument_atomic_read include/linux/instrumented.h:82 [inline] BUG: KASAN: slab-out-of-bounds in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] BUG: KASAN: slab-out-of-bounds in inet_sk_flowi_flags include/net/inet_sock.h:411 [inline] BUG: KASAN: slab-out-of-bounds in tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983 Read of size 8 at addr ffff8881bc3cecb8 by task kworker/u8:3/5678 CPU: 1 UID: 0 PID: 5678 Comm: kworker/u8:3 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 Workqueue: krdsd rds_tcp_accept_worker Call Trace: <IRQ> dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 print_address_description+0x55/0x1e0 mm/kasan/report.c:378 print_report+0x58/0x70 mm/kasan/report.c:482 kasan_report+0x117/0x150 mm/kasan/report.c:595 check_region_inline mm/kasan/generic.c:-1 [inline] kasan_check_range+0x264/0x2c0 mm/kasan/generic.c:200 instrument_atomic_read include/linux/instrumented.h:82 [inline] _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] inet_sk_flowi_flags include/net/inet_sock.h:411 [inline] tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983 tcp_v6_send_ack net/ipv6/tcp_ipv6.c:1149 [inline] tcp_v6_timewait_ack+0x2c6/0x4c0 net/ipv6/tcp_ipv6.c:1201 tcp_v6_rcv+0x1f09/0x2d90 net/ipv6/tcp_ipv6.c:1993 ip6_protocol_deliver_rcu+0xab9/0x1680 net/ipv6/ip6_input.c:479 ip6_input_finish+0x191/0x370 net/ipv6/ip6_input.c:534 NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325 ip6_input+0x16a/0x270 net/ipv6/ip6_input.c:545 NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325 __netif_receive_skb_one_core net/core/dev.c:6264 [inline] __netif_receive_skb net/core/dev.c:6377 [inline] process_backlog+0x795/0x18b0 net/core/dev.c:6728 __napi_poll+0xaa/0x330 net/core/dev.c:7787 napi_poll net/core/dev.c:7850 [inline] net_rx_action+0x61d/0xf50 net/core/dev.c:8007 handle_softirqs+0x226/0x860 kernel/softirq.c:645 do_softirq+0x77/0xd0 kernel/softirq.c:546 </IRQ> <TASK> __local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473 local_bh_enable include/linux/bottom_half.h:33 [inline] rcu_read_unlock_bh include/linux/rcupdate.h:923 [inline] __dev_queue_xmit+0x1edc/0x3820 net/core/dev.c:4961 NF_HOOK_COND include/linux/netfilter.h:314 [inline] ip6_output+0x337/0x540 net/ipv6/ip6_output.c:248 dst_output include/net/dst.h:471 [inline] NF_HOOK include/linux/netfilter.h:325 [inline] ip6_xmit+0x117f/0x1a60 net/ipv6/ip6_output.c:381 inet6_csk_xmit+0x397/0x660 net/ipv6/inet6_connection_sock.c:123 __tcp_transmit_skb+0x2640/0x47c0 net/ipv4/tcp_output.c:1717 tcp_transmit_skb net/ipv4/tcp_output.c:1734 [inline] tcp_write_xmit+0x1bfa/0x6400 net/ipv4/tcp_output.c:3062 __tcp_push_pending_frames+0x96/0x380 net/ipv4/tcp_output.c:3245 __tcp_close+0x56e/0xe70 net/ipv4/tcp.c:3220 tcp_close+0x28/0x110 net/ipv4/tcp.c:3311 inet_release+0x143/0x190 net/ipv4/af_inet.c:442 __sock_release net/socket.c:735 [inline] sock_release+0x85/0x150 net/socket.c:763 rds_tcp_accept_one+0x62c/0xd40 net/rds/tcp_listen.c:341 rds_tcp_accept_worker+0x1d/0x70 net/rds/tcp.c:556 process_one_work kernel/workqueue.c:3387 [inline] process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470 worker_thread+0xa47/0xfb0 kernel/workqueue.c:3551 kthread+0x38b/0x480 kernel/kthread.c:436 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 </TASK> The buggy address belongs to the object at ffff8881bc3ceb80 which belongs to the cache tw_sock_TCPv6 of size 304 The buggy address is located 8 bytes to the right of allocated 304-byte region [ffff8881bc3ceb80, ffff8881bc3cecb0) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff8881bc3ce8a0 pfn:0x1bc3ce head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 memcg:ffff8881bb1a4301 flags: 0x57ff00000000240(workingset|head|node=1|zone=2|lastcpupid=0x7ff) page_type: f5(slab) raw: 057ff00000000240 ffff8881042e0640 ffff88816fedf1c8 ffff88816fedf1c8 raw: ffff8881bc3ce8a0 0000000200160006 00000000f5000000 ffff8881bb1a4301 head: 057ff00000000240 ffff8881042e0640 ffff88816fedf1c8 ffff88816fedf1c8 head: ffff8881bc3ce8a0 0000000200160006 00000000f5000000 ffff8881bb1a4301 head: 057ff00000000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000002 page dumped because: kasan: bad access detected page_owner tracks the page as allocated page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5678, tgid 5678 (kworker/u8:3), ts 57920184007 set_page_owner include/linux/page_owner.h:33 [inline] post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1871 prep_new_page mm/page_alloc.c:1879 [inline] get_page_from_freelist+0x2209/0x2280 mm/page_alloc.c:3943 __alloc_frozen_pages_noprof+0x217/0x5a0 mm/page_alloc.c:5436 alloc_slab_page mm/slub.c:3347 [inline] allocate_slab+0x7d/0x620 mm/slub.c:3462 new_slab mm/slub.c:3513 [inline] refill_objects+0x2d5/0x350 mm/slub.c:7410 refill_sheaf mm/slub.c:2885 [inline] __pcs_replace_empty_main+0x2c8/0x6c0 mm/slub.c:4774 alloc_from_pcs mm/slub.c:4850 [inline] slab_alloc_node mm/slub.c:4984 [inline] kmem_cache_alloc_noprof+0x399/0x600 mm/slub.c:5010 inet_twsk_alloc+0xe3/0x8d0 net/ipv4/inet_timewait_sock.c:178 tcp_time_wait+0x5d/0xee0 net/ipv4/tcp_minisocks.c:333 tcp_rcv_state_process+0xba1/0x4980 net/ipv4/tcp_input.c:-1 tcp_v6_do_rcv+0xf3d/0x1c70 net/ipv6/tcp_ipv6.c:1653 tcp_v6_rcv+0x2496/0x2d90 net/ipv6/tcp_ipv6.c:1906 ip6_protocol_deliver_rcu+0xab9/0x1680 net/ipv6/ip6_input.c:479 ip6_input_finish+0x191/0x370 net/ipv6/ip6_input.c:534 NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325 ip6_input+0x16a/0x270 net/ipv6/ip6_input.c:545 page last free pid 24 tgid 24 ts 57909757259 stack trace: reset_page_owner include/linux/page_owner.h:26 [inline] __free_pages_prepare mm/page_alloc.c:1418 [inline] __free_frozen_pages+0xc93/0xd90 mm/page_alloc.c:2962 rcu_do_batch kernel/rcu/tree.c:2650 [inline] rcu_core+0x926/0x1260 kernel/rcu/tree.c:2919 handle_softirqs+0x226/0x860 kernel/softirq.c:645 __do_softirq kernel/softirq.c:679 [inline] invoke_softirq kernel/softirq.c:519 [inline] __irq_exit_rcu+0xcb/0x220 kernel/softirq.c:767 irq_exit_rcu+0x9/0x30 kernel/softirq.c:784 instr_sysvec_call_function_single arch/x86/kernel/smp.c:267 [inline] sysvec_call_function_single+0xa3/0xc0 arch/x86/kernel/smp.c:267 asm_sysvec_call_function_single+0x1a/0x20 arch/x86/include/asm/idtentry.h:681 Memory state around the buggy address: ffff8881bc3ceb80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff8881bc3cec00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc >ffff8881bc3cec80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ^ ffff8881bc3ced00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff8881bc3ced80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ================================================================== *** KASAN: use-after-free Read in tcp_v6_send_response tree: net URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net.git base: 1d2929d0850fff683b8aff051275945e65f082c8 arch: amd64 compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8 config: https://ci.syzbot.org/builds/19ac2ebf-5913-40a0-982b-446415180382/config syz repro: https://ci.syzbot.org/findings/e7a2188a-bd9d-4259-856a-ad2e7415f5e1/syz_repro ================================================================== BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:82 [inline] BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] BUG: KASAN: use-after-free in inet_sk_flowi_flags include/net/inet_sock.h:411 [inline] BUG: KASAN: use-after-free in tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983 Read of size 8 at addr ffff888169a4a248 by task syz.0.28/5835 CPU: 1 UID: 0 PID: 5835 Comm: syz.0.28 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 Call Trace: <IRQ> dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 print_address_description+0x55/0x1e0 mm/kasan/report.c:378 print_report+0x58/0x70 mm/kasan/report.c:482 kasan_report+0x117/0x150 mm/kasan/report.c:595 check_region_inline mm/kasan/generic.c:-1 [inline] kasan_check_range+0x264/0x2c0 mm/kasan/generic.c:200 instrument_atomic_read include/linux/instrumented.h:82 [inline] _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] inet_sk_flowi_flags include/net/inet_sock.h:411 [inline] tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983 tcp_v6_send_ack net/ipv6/tcp_ipv6.c:1149 [inline] tcp_v6_timewait_ack+0x2c6/0x4c0 net/ipv6/tcp_ipv6.c:1201 tcp_v6_rcv+0x1f09/0x2d90 net/ipv6/tcp_ipv6.c:1993 ip6_protocol_deliver_rcu+0xab9/0x1680 net/ipv6/ip6_input.c:479 ip6_input_finish+0x191/0x370 net/ipv6/ip6_input.c:534 NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325 ip6_input+0x16a/0x270 net/ipv6/ip6_input.c:545 NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325 __netif_receive_skb_one_core net/core/dev.c:6264 [inline] __netif_receive_skb net/core/dev.c:6377 [inline] process_backlog+0x795/0x18b0 net/core/dev.c:6728 __napi_poll+0xaa/0x330 net/core/dev.c:7787 napi_poll net/core/dev.c:7850 [inline] net_rx_action+0x61d/0xf50 net/core/dev.c:8007 handle_softirqs+0x226/0x860 kernel/softirq.c:645 do_softirq+0x77/0xd0 kernel/softirq.c:546 </IRQ> <TASK> __local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473 local_bh_enable include/linux/bottom_half.h:33 [inline] rcu_read_unlock_bh include/linux/rcupdate.h:923 [inline] __dev_queue_xmit+0x1edc/0x3820 net/core/dev.c:4961 NF_HOOK_COND include/linux/netfilter.h:314 [inline] ip6_output+0x337/0x540 net/ipv6/ip6_output.c:248 dst_output include/net/dst.h:471 [inline] NF_HOOK include/linux/netfilter.h:325 [inline] ip6_xmit+0x117f/0x1a60 net/ipv6/ip6_output.c:381 inet6_csk_xmit+0x397/0x660 net/ipv6/inet6_connection_sock.c:123 __tcp_transmit_skb+0x2640/0x47c0 net/ipv4/tcp_output.c:1717 tcp_transmit_skb net/ipv4/tcp_output.c:1734 [inline] tcp_write_xmit+0x1bfa/0x6400 net/ipv4/tcp_output.c:3062 __tcp_push_pending_frames+0x96/0x380 net/ipv4/tcp_output.c:3245 __tcp_close+0x56e/0xe70 net/ipv4/tcp.c:3220 tcp_close+0x28/0x110 net/ipv4/tcp.c:3311 inet_release+0x143/0x190 net/ipv4/af_inet.c:442 __sock_release+0xa0/0x1f0 net/socket.c:735 sock_close+0x1c/0x30 net/socket.c:1526 __fput+0x418/0xa50 fs/file_table.c:512 task_work_run+0x1d9/0x270 kernel/task_work.c:233 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] __exit_to_user_mode_loop kernel/entry/common.c:70 [inline] exit_to_user_mode_loop+0x204/0x770 kernel/entry/common.c:101 __exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline] syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:230 [inline] syscall_exit_to_user_mode include/linux/entry-common.h:336 [inline] do_syscall_64+0x328/0x520 arch/x86/entry/syscall_64.c:89 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fb1d8b9e159 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 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 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffef2a01168 EFLAGS: 00000246 ORIG_RAX: 00000000000001b4 RAX: 0000000000000000 RBX: 00007ffef2a01250 RCX: 00007fb1d8b9e159 RDX: 0000000000000000 RSI: 000000000000001e RDI: 0000000000000003 RBP: 000000000000d50a R08: 0000000000000001 R09: 0000000000000000 R10: 0000001b31820000 R11: 0000000000000246 R12: 00007ffef2a01290 R13: 00007fb1d8e25fac R14: 000000000000d53d R15: 00007fb1d8e25fa0 </TASK> The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888169a4bc80 pfn:0x169a4a flags: 0x57ff00000000000(node=1|zone=2|lastcpupid=0x7ff) raw: 057ff00000000000 ffffea0005c32488 ffffea0005c32508 0000000000000000 raw: ffff888169a4bc80 0000000000000000 00000000ffffffff 0000000000000000 page dumped because: kasan: bad access detected page_owner tracks the page as freed page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5565, tgid 5565 (sshd), ts 40657811568 set_page_owner include/linux/page_owner.h:33 [inline] post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1871 prep_new_page mm/page_alloc.c:1879 [inline] get_page_from_freelist+0x2209/0x2280 mm/page_alloc.c:3943 __alloc_frozen_pages_noprof+0x217/0x5a0 mm/page_alloc.c:5436 alloc_slab_page mm/slub.c:3347 [inline] allocate_slab+0x7d/0x620 mm/slub.c:3462 new_slab mm/slub.c:3513 [inline] refill_objects+0x2d5/0x350 mm/slub.c:7410 refill_sheaf mm/slub.c:2885 [inline] __pcs_replace_empty_main+0x2c8/0x6c0 mm/slub.c:4774 alloc_from_pcs mm/slub.c:4850 [inline] slab_alloc_node mm/slub.c:4984 [inline] kmem_cache_alloc_noprof+0x399/0x600 mm/slub.c:5010 skb_clone+0x212/0x3a0 net/core/skbuff.c:2119 dev_queue_xmit_nit+0x28d/0xac0 net/core/dev.c:2600 xmit_one net/core/dev.c:3933 [inline] dev_hard_start_xmit+0x1c1/0x830 net/core/dev.c:3953 sch_direct_xmit+0x257/0x4c0 net/sched/sch_generic.c:372 __dev_xmit_skb net/core/dev.c:4262 [inline] __dev_queue_xmit+0x177f/0x3820 net/core/dev.c:4884 dev_queue_xmit include/linux/netdevice.h:3461 [inline] neigh_hh_output include/net/neighbour.h:544 [inline] neigh_output include/net/neighbour.h:558 [inline] ip_finish_output2+0xbda/0x10b0 net/ipv4/ip_output.c:236 NF_HOOK_COND include/linux/netfilter.h:314 [inline] ip_output+0x29f/0x450 net/ipv4/ip_output.c:437 __ip_queue_xmit+0x10df/0x1b10 net/ipv4/ip_output.c:533 __tcp_transmit_skb+0x2d18/0x47c0 net/ipv4/tcp_output.c:1717 page last free pid 5040 tgid 5040 ts 54399149504 stack trace: reset_page_owner include/linux/page_owner.h:26 [inline] __free_pages_prepare mm/page_alloc.c:1418 [inline] __free_frozen_pages+0xc93/0xd90 mm/page_alloc.c:2962 __slab_free+0x274/0x2c0 mm/slub.c:5815 qlink_free mm/kasan/quarantine.c:163 [inline] qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350 kasan_slab_alloc include/linux/kasan.h:253 [inline] slab_post_alloc_hook mm/slub.c:4683 [inline] slab_alloc_node mm/slub.c:4996 [inline] __do_kmalloc_node mm/slub.c:5413 [inline] __kvmalloc_node_noprof+0x49f/0x820 mm/slub.c:7005 seq_buf_alloc fs/seq_file.c:39 [inline] seq_read_iter+0x1ea/0xca0 fs/seq_file.c:211 new_sync_read fs/read_write.c:493 [inline] vfs_read+0x595/0xa80 fs/read_write.c:574 ksys_read+0x150/0x270 fs/read_write.c:716 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline] do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84 entry_SYSCALL_64_after_hwframe+0x77/0x7f Memory state around the buggy address: ffff888169a4a100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ffff888169a4a180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff >ffff888169a4a200: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ^ ffff888169a4a280: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ffff888169a4a300: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ================================================================== *** If these findings have caused you to resend the series or submit a separate fix, please add the following tag to your commit message: Tested-by: syzbot@syzkaller.appspotmail.com --- This report is generated by a bot. It may contain errors. syzbot ci engineers can be reached at syzkaller@googlegroups.com. To test a fix for this bug, please reply with `#syz test` (on a separate line) and attach the patch to the email. Notes: - The patch will be applied on top of the tested series (as an incremental fix). - To test a new version of the whole series, please send it directly to syzbot@lists.linux.dev. - Arguments like custom git repos and branches are not supported.
On Tue, Sep 1, 2026 at 7:41 PM Matthieu Baerts <matttbe@kernel.org> wrote: > Thank you for looking at this, but I think your patch is causing > multiple KASAN warnings, e.g. > > https://netdev-ctrl.bots.linux.dev/logs/vmksft/net-extra-dbg/results/804584/24-connect-deny-ipv6/stderr > > And a few more, see: > > https://netdev.bots.linux.dev/branch_deltas/net-next-2026-09-01--15-01.html As far as I can see all the warnings are in the tcp_v6_send_response function. I guess that sk may be a request socket there, so it's not valid to treat it as a inet_sk in all cases. I will send a v2 with the fix. Thanks!
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index a0557a3a7026..6c09d5f46d6b 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -432,6 +432,7 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb, fl6.flowlabel = ip6_flowinfo(iph); fl6.flowi6_mark = skb->mark; fl6.flowi6_proto = iph->nexthdr; + fl6.flowi6_flags = FLOWI_FLAG_ANYSRC; dst = ip6_dst_lookup_flow(net, NULL, &fl6, NULL); if (IS_ERR(dst) || dst == dst_null) diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c index da49364ec63d..e8b954282689 100644 --- a/net/core/lwt_bpf.c +++ b/net/core/lwt_bpf.c @@ -233,6 +233,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) fl6.flowi6_mark = skb->mark; fl6.flowi6_uid = sock_net_uid(net, sk); fl6.flowlabel = ip6_flowinfo(iph6); + fl6.flowi6_flags = FLOWI_FLAG_ANYSRC; fl6.flowi6_proto = iph6->nexthdr; fl6.daddr = iph6->daddr; fl6.saddr = iph6->saddr; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 282912a11999..e55a36372ab2 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -820,6 +820,7 @@ int inet6_sk_rebuild_header(struct sock *sk) fl6->fl6_dport = inet->inet_dport; fl6->fl6_sport = inet->inet_sport; fl6->flowi6_uid = sk_uid(sk); + fl6->flowi6_flags = inet_sk_flowi_flags(sk); security_sk_classify_flow(sk, flowi6_to_flowi_common(fl6)); ip6_ecmp_set_mp_hash(sock_net(sk), fl6, sk->sk_txhash); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 38d7b4845281..0773bfa0342d 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -52,6 +52,7 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6, fl6->flowi6_mark = sk->sk_mark; fl6->fl6_dport = inet->inet_dport; fl6->fl6_sport = inet->inet_sport; + fl6->flowi6_flags = inet_sk_flowi_flags(sk); fl6->flowlabel = ip6_make_flowinfo(np->tclass, np->flow_label); fl6->flowi6_uid = sk_uid(sk); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 3e4ce8cb478e..f295f3efe243 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -45,6 +45,7 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk, fl6->flowi6_mark = ireq->ir_mark; fl6->fl6_dport = ireq->ir_rmt_port; fl6->fl6_sport = htons(ireq->ir_num); + fl6->flowi6_flags = inet_sk_flowi_flags(sk); fl6->flowi6_uid = sk_uid(sk); security_req_classify_flow(req, flowi6_to_flowi_common(fl6)); @@ -71,6 +72,7 @@ struct dst_entry *inet6_csk_route_socket(struct sock *sk, fl6->daddr = sk->sk_v6_daddr; fl6->saddr = np->saddr; fl6->flowlabel = np->flow_label; + fl6->flowi6_flags = inet_sk_flowi_flags(sk); IP6_ECN_flow_xmit(sk, fl6->flowlabel); if (sk->sk_protocol == IPPROTO_TCP) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 8fc4766c8da9..57eebe347902 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1191,6 +1191,34 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, if (err) goto out_err_release; + /* Routing packets with a source address not present in the host is + * disallowed unless the ANYSRC flag is set (i.e. with transparent sockets). + * The source address must be in the same L3 domain as the destination device. + */ + if (!ipv6_addr_any(&fl6->saddr) && + !(fl6->flowi6_flags & FLOWI_FLAG_ANYSRC)) { + struct net_device *oif_dev; + + rcu_read_lock(); + /* For local routes, (*dst)->dev can be 'lo', which has no l3mdev + * master, so that the L3 domain wouldn't match if the source + * address is in a VRF-enslaved device. To avoid that, check the + * outgoing interface from the flowi6 structure instead. + */ + if (fl6->flowi6_oif) + oif_dev = dev_get_by_index_rcu(net, fl6->flowi6_oif); + else + oif_dev = (*dst)->dev; + + if (!ipv6_chk_addr_and_flags(net, &fl6->saddr, oif_dev, + 1, 1, IFA_F_TENTATIVE)) + err = -ENETUNREACH; + rcu_read_unlock(); + + if (err) + goto out_err_release; + } + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD /* * Here if the dst entry we've looked up diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index a7025ec87035..7c19ecbec112 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -26,11 +26,11 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff const struct ipv6hdr *iph = ipv6_hdr(skb); struct sock *sk = sk_to_full_sk(sk_partial); struct net_device *dev = skb_dst_dev(skb); + int daddr_type = ipv6_addr_type(&iph->daddr); struct flow_keys flkeys; unsigned int hh_len; struct dst_entry *dst; - int strict = (ipv6_addr_type(&iph->daddr) & - (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); + int strict = daddr_type & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL); struct flowi6 fl6 = { .flowi6_l3mdev = l3mdev_master_ifindex(dev), .flowi6_mark = skb->mark, @@ -41,6 +41,12 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff }; int err; + fl6.flowi6_flags = sk ? inet_sk_flowi_flags(sk) : 0; + if (daddr_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL)) + fl6.flowi6_flags |= FLOWI_FLAG_ANYSRC; + else + fl6.saddr = in6addr_any; + if (sk && sk->sk_bound_dev_if) fl6.flowi6_oif = sk->sk_bound_dev_if; else if (strict) diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 6e90d0bf9f3d..d0964396c2c5 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -140,6 +140,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) fl6.flowi6_proto = IPPROTO_ICMPV6; fl6.saddr = np->saddr; fl6.daddr = *daddr; + fl6.flowi6_flags = inet_sk_flowi_flags(sk); fl6.flowi6_mark = ipc6.sockc.mark; fl6.flowi6_uid = sk_uid(sk); fl6.fl6_icmp_type = user_icmph.icmp6_type; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index b965258cf9e5..ef5ddbe7ac10 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -887,6 +887,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) fl6.flowi6_oif = READ_ONCE(np->ucast_oif); security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); + fl6.flowi6_flags = inet_sk_flowi_flags(sk); if (hdrincl) fl6.flowi6_flags |= FLOWI_FLAG_KNOWN_NH; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index b581cb1ee2e8..3d665e93fcac 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -242,6 +242,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) fl6.flowi6_mark = ireq->ir_mark; fl6.fl6_dport = ireq->ir_rmt_port; fl6.fl6_sport = inet_sk(sk)->inet_sport; + fl6.flowi6_flags = inet_sk_flowi_flags(sk); fl6.flowi6_uid = sk_uid(sk); security_req_classify_flow(req, flowi6_to_flowi_common(&fl6)); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index df9c29eb5c1f..401a1297e7db 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -268,6 +268,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr_unsized *uaddr, fl6->flowi6_mark = sk->sk_mark; fl6->fl6_dport = usin->sin6_port; fl6->fl6_sport = inet->inet_sport; + fl6->flowi6_flags = inet_sk_flowi_flags(sk); if (IS_ENABLED(CONFIG_IP_ROUTE_MULTIPATH) && !fl6->fl6_sport) fl6->flowi6_flags = FLOWI_FLAG_ANY_SPORT; fl6->flowi6_uid = sk_uid(sk); @@ -979,6 +980,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 fl6.fl6_dport = t1->dest; fl6.fl6_sport = t1->source; fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL); + fl6.flowi6_flags = sk ? inet_sk_flowi_flags(sk) : 0; security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6)); /* Pass a socket to ip6_dst_lookup either it is for RST diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 93478d1ad576..5154d445ba9c 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1656,6 +1656,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) if (ipv6_addr_any(&fl6->saddr) && !ipv6_addr_any(&np->saddr)) fl6->saddr = np->saddr; fl6->fl6_sport = inet->inet_sport; + fl6->flowi6_flags = inet_sk_flowi_flags(sk); if (cgroup_bpf_enabled(CGROUP_UDP6_SENDMSG) && !connected) { err = BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk, diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index bdaae1b64d25..22ae5bc2669a 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -633,6 +633,8 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) else if (!fl6.flowi6_oif) fl6.flowi6_oif = READ_ONCE(np->ucast_oif); + fl6.flowi6_flags = inet_sk_flowi_flags(sk); + security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
Don't allow routing packets with a source address that is not configured in the host. Allow it only in certain cases like when using a transparent socket, by setting the ANYSRC flag in flowi_flags. Until now, it was possible to send such a packet if a route can be found in the routing table for it. For example: 1. Configure an address 1:2::3:4/64 and a static route 1:2::/64 2. Establish a TCP connection to 1:2::3:4 3. Remove the address from the interface, but keep the route. 4. Packets are still sent out by the TCP connection because of the static route. No incoming packets are accepted, though. This patch prevents the outgoing packets to be sent in normal circumnstances. This aligns the behaviour with the IPv4 stack. To determine the places where the ANYSRC needs to be set, I set the flag in the same places as the IPv4 stack does. Apart from consolidating the behaviour of both stacks, there is a more important reason why this is needed. RFC 4862 states that "an invalid address MUST NOT be used as the source address of outbound packets". Therefore, sending packets with a source address considered "invalid", like an expired address, is disallowed. Signed-off-by: Íñigo Huguet <ihuguet@riseup.net> --- Testing: tested with a manual reproducer executing the steps described above. Tested also with transparent sockets to ensure that the packets are sent in that case. Also executed the following selftests to prevent potential regressions: fcnal-ipv6, fib_tests, fib-onlink-tests, nft_nat, nft_tproxy_tcp, nft_tproxy_udp. The change in the netfilter's ip6_route_me_harder function is the one that I'm more unsure about. It was not clear to me the reason why it was done like this in the IPv4 counterpart. Please review carefully. --- drivers/net/vrf.c | 1 + net/core/lwt_bpf.c | 1 + net/ipv6/af_inet6.c | 1 + net/ipv6/datagram.c | 1 + net/ipv6/inet6_connection_sock.c | 2 ++ net/ipv6/ip6_output.c | 28 ++++++++++++++++++++++++++++ net/ipv6/netfilter.c | 10 ++++++++-- net/ipv6/ping.c | 1 + net/ipv6/raw.c | 1 + net/ipv6/syncookies.c | 1 + net/ipv6/tcp_ipv6.c | 2 ++ net/ipv6/udp.c | 1 + net/l2tp/l2tp_ip6.c | 2 ++ 13 files changed, 50 insertions(+), 2 deletions(-)