* [PATCH net] xfrm: fix stack-out-of-bounds in xfrm_tmpl_resolve_one
@ 2026-06-25 9:24 Eric Dumazet
2026-06-25 17:43 ` Antony Antony
0 siblings, 1 reply; 2+ messages in thread
From: Eric Dumazet @ 2026-06-25 9:24 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, netdev, eric.dumazet, Eric Dumazet,
syzbot+0ac4d84afe1066a1f3e9, Steffen Klassert, Herbert Xu
syzbot reported a stack-out-of-bounds read in xfrm_state_find()
which flows from xfrm_tmpl_resolve_one().
The issue occurs when a policy has a mix of family-changing templates
(e.g. BEET or IPTFS) and transport templates. If an optional
family-changing template is skipped because no state is found, the
current family of the flow (`family`) is not updated. The subsequent
transport template is then evaluated using the unchanged family (e.g.
AF_INET), but it uses the template's `encap_family` (e.g. AF_INET6)
to perform the state lookup.
This causes `xfrm_state_find()` to interpret the IPv4 flow addresses
(allocated on the stack as `struct flowi4` in `raw_sendmsg` or
`udp_sendmsg`) as IPv6 addresses (`xfrm_address_t`), leading to a
16-byte read from the 4-byte stack variables, triggering KASAN.
Fix this by tracking the active family of the flow (`cur_family`)
during template resolution:
1. Initialize `cur_family` to the flow's original family.
2. For transport templates, verify that `tmpl->encap_family` matches
`cur_family`. If they mismatch, abort with -EINVAL.
3. When a template that can change the family (tunnel, beet, iptfs) is
successfully resolved, update `cur_family` to `tmpl->encap_family`.
4. If a template is skipped (optional), `cur_family` remains unchanged.
This prevents mismatched transport lookups and makes the resolution
robust against any family-transition gaps.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+0ac4d84afe1066a1f3e9@syzkaller.appspotmail.com
Closes: https://www.spinics.net/lists/netdev/msg1200923.html
Assisted-by: Jetski:gemini-3.1-pro-preview
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
---
net/xfrm/xfrm_policy.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 7ef861a0e8231b63ece816b5237b03fa1367ccf9..95e30670303d34598ba164dff59a65c14489d5f3 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2485,6 +2485,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
int i, error;
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
+ unsigned short cur_family = family;
xfrm_address_t tmp;
for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
@@ -2511,6 +2512,11 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
goto fail;
local = &tmp;
}
+ } else {
+ if (tmpl->encap_family != cur_family) {
+ error = -EINVAL;
+ goto fail;
+ }
}
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error,
@@ -2526,6 +2532,11 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
xfrm[nx++] = x;
daddr = remote;
saddr = local;
+ if (tmpl->mode == XFRM_MODE_TUNNEL ||
+ tmpl->mode == XFRM_MODE_IPTFS ||
+ tmpl->mode == XFRM_MODE_BEET) {
+ cur_family = tmpl->encap_family;
+ }
continue;
}
if (x) {
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH net] xfrm: fix stack-out-of-bounds in xfrm_tmpl_resolve_one
2026-06-25 9:24 [PATCH net] xfrm: fix stack-out-of-bounds in xfrm_tmpl_resolve_one Eric Dumazet
@ 2026-06-25 17:43 ` Antony Antony
0 siblings, 0 replies; 2+ messages in thread
From: Antony Antony @ 2026-06-25 17:43 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
netdev, eric.dumazet, syzbot+0ac4d84afe1066a1f3e9,
Steffen Klassert, Herbert Xu, Tobias Brunner, Christian Hopps
Hi Eric,
On Thu, Jun 25, 2026 at 09:24:17AM +0000, Eric Dumazet wrote:
> syzbot reported a stack-out-of-bounds read in xfrm_state_find()
> which flows from xfrm_tmpl_resolve_one().
>
> The issue occurs when a policy has a mix of family-changing templates
> (e.g. BEET or IPTFS) and transport templates. If an optional
> family-changing template is skipped because no state is found, the
> current family of the flow (`family`) is not updated. The subsequent
> transport template is then evaluated using the unchanged family (e.g.
> AF_INET), but it uses the template's `encap_family` (e.g. AF_INET6)
> to perform the state lookup.
Thank you for the quick fix. I would like to look at it from a
different angle.
The commit message mentions BEET as a trigger, but I notice BEET
optional templates in outbound policies are already rejected since:
commit 3d776e31c841 ("xfrm: Reject optional tunnel/BEET mode templates in outbound policies")
Here is the effect of blocker for BEET mode.
ip netns exec ns_a ip link add dummy0 type dummy
ip netns exec ns_a ip link set dummy0 up
ip netns exec ns_a ip addr add 10.1.1.1/24 dev dummy0
ip xfrm policy add src 10.1.1.1/32 dst 10.1.1.2/32 dir out tmpl \
src fc00::dead:1 dst fc00::dead:2 proto esp reqid 1 mode beet \
level use tmpl src fc00::dead:1 dst fc00::dead:2 proto esp reqid 2 \
mode transport
Error: Mode in optional template not allowed in outbound policy.
However, IPTF is allowed. I think fix should include this.
Does syzbot give a clue which mode was used? I am new syzbot postmartum!
Any way look cordump or so tsee the which mode was actually used?
I suspect it is IPTFS, other mode would not tirgger this code path.
In practice, only IPTFS can still reach xfrm_tmpl_resolve_one() with
the family-mismatch condition, since xfrm_user.c has no equivalent
guard for XFRM_MODE_IPTFS.
ip link add dummy0 type dummy
ip link set dummy0 up
ip addr add 10.1.1.1/24 dev dummy0
ip xfrm policy add src 10.1.1.1/32 dst 10.1.1.2/32 dir out tmpl \
src fc00::dead:1 dst fc00::dead:2 proto esp reqid 1 mode iptfs \
level use tmpl src fc00::dead:1 dst fc00::dead:2 proto esp reqid 2 \
mode transport
ping -W 1 -c 1 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
[ 3.477151] Adding 998396k swap on /dev/vda5. Priority:-1 extents:1 across:998396k
[ 17.565672] ==================================================================
[ 17.567270] BUG: KASAN: stack-out-of-bounds in __xfrm6_addr_hash+0x11e/0x170
[ 17.567270] Read of size 4 at addr ffff88800f79fd20 by task ping/2777
[ 17.567270] CPU: 1 UID: 0 PID: 2777 Comm: ping Not tainted 7.1.0-rc7-02029-gfb92cc029b34-dirty #94 PREEMPT(full)
[ 17.567270] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 17.567270] Call Trace:
[ 17.567270] <TASK>
[ 17.567270] dump_stack_lvl+0x47/0x70
[ 17.567270] ? __xfrm6_addr_hash+0x11e/0x170
[ 17.567270] print_report+0x152/0x4b0
[ 17.567270] ? ksys_mmap_pgoff+0x6d/0xa0
[ 17.567270] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 17.567270] ? rcu_read_unlock_sched+0xa/0x20
[ 17.567270] ? __virt_addr_valid+0x21b/0x230
[ 17.567270] ? __xfrm6_addr_hash+0x11e/0x170
[ 17.567270] kasan_report+0xa8/0xd0
[ 17.567270] ? __xfrm6_addr_hash+0x11e/0x170
[ 17.567270] __xfrm6_addr_hash+0x11e/0x170
[ 17.567270] __xfrm_dst_hash+0x24/0xc0
[ 17.567270] xfrm_state_find+0xa2d/0x2f90
[ 17.567270] ? __pfx_xfrm_state_find+0x10/0x10
[ 17.567270] ? __pfx_ftrace_graph_ret_addr+0x10/0x10
[ 17.567270] ? __pfx_ftrace_graph_ret_addr+0x10/0x10
[ 17.567270] xfrm_tmpl_resolve_one+0x210/0x570
[ 17.567270] ? __pfx_xfrm_tmpl_resolve_one+0x10/0x10
[ 17.567270] ? __pfx_stack_trace_consume_entry+0x10/0x10
[ 17.567270] ? kernel_text_address+0x5b/0x80
[ 17.567270] ? __kernel_text_address+0xe/0x30
[ 17.567270] ? unwind_get_return_address+0x5e/0x90
[ 17.567270] ? arch_stack_walk+0x8c/0xe0
[ 17.567270] xfrm_tmpl_resolve+0x130/0x200
[ 17.567270] ? __pfx_xfrm_tmpl_resolve+0x10/0x10
[ 17.567270] ? __pfx_xfrm_policy_inexact_lookup_rcu+0x10/0x10
[ 17.567270] ? __refcount_add_not_zero.constprop.0+0xb2/0x110
[ 17.567270] ? __pfx___refcount_add_not_zero.constprop.0+0x10/0x10
[ 17.567270] xfrm_resolve_and_create_bundle+0xd5/0x310
[ 17.567270] ? __pfx_xfrm_resolve_and_create_bundle+0x10/0x10
[ 17.567270] ? __pfx_xfrm_policy_lookup_bytype+0x10/0x10
[ 17.567270] ? __pfx_xfrm_policy_lookup_bytype+0x10/0x10
[ 17.567270] xfrm_lookup_with_ifid+0x3d7/0xb80
[ 17.567270] ? __pfx_xfrm_lookup_with_ifid+0x10/0x10
[ 17.567270] ? ip_route_output_key_hash+0xc6/0x110
[ 17.567270] ? kasan_save_track+0x10/0x30
[ 17.567270] xfrm_lookup_route+0x18/0xe0
[ 17.567270] ip4_datagram_release_cb+0x4c9/0x530
[ 17.567270] ? __pfx_ip4_datagram_release_cb+0x10/0x10
[ 17.567270] ? do_raw_spin_lock+0x71/0xc0
[ 17.567270] ? __pfx_do_raw_spin_lock+0x10/0x10
[ 17.567270] release_sock+0xb0/0x170
[ 17.567270] udp_connect+0x43/0x50
[ 17.567270] __sys_connect+0xa6/0x100
[ 17.567270] ? alloc_fd+0x2e9/0x300
[ 17.567270] ? __pfx___sys_connect+0x10/0x10
[ 17.567270] ? preempt_latency_start+0x1f/0x70
[ 17.567270] ? fd_install+0x7e/0x150
[ 17.567270] ? rcu_read_unlock_sched+0xa/0x20
[ 17.567270] ? __sys_socket+0xdf/0x130
[ 17.567270] ? __pfx___sys_socket+0x10/0x10
[ 17.567270] ? vma_refcount_put+0x43/0xa0
[ 17.567270] __x64_sys_connect+0x7e/0x90
[ 17.567270] do_syscall_64+0x11b/0x2b0
[ 17.567270] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 17.567270] RIP: 0033:0x7f6604eb0570
[ 17.567270] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 80 3d f9 ca 0d 00 00 74 17 b8 2a 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 18 89 54
[ 17.567270] RSP: 002b:00007ffd02bdf658 EFLAGS: 00000202 ORIG_RAX: 000000000000002a
[ 17.567270] RAX: ffffffffffffffda RBX: 00007ffd02bdf690 RCX: 00007f6604eb0570
[ 17.567270] RDX: 0000000000000010 RSI: 00007ffd02bdf690 RDI: 0000000000000005
[ 17.567270] RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000000
[ 17.567270] R10: 0000000000000006 R11: 0000000000000202 R12: 0000000000000005
[ 17.567270] R13: 0000000000000000 R14: 0000557fb777a340 R15: 0000000000000000
[ 17.567270] </TASK>
[ 17.567270] The buggy address belongs to stack of task ping/2777
[ 17.567270] and is located at offset 88 in frame:
[ 17.567270] ip4_datagram_release_cb+0x0/0x530
[ 17.567270] This frame has 1 object:
[ 17.567270] [32, 88) 'fl4'
[ 17.567270] The buggy address belongs to the physical page:
[ 17.567270] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xf79f
[ 17.567270] flags: 0x4000000000000000(zone=1)
[ 17.567270] raw: 4000000000000000 0000000000000000 ffffea00003de7c8 0000000000000000
[ 17.567270] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
[ 17.567270] page dumped because: kasan: bad access detected
[ 17.567270] Memory state around the buggy address:
[ 17.567270] ffff88800f79fc00: f2 f2 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00
[ 17.567270] ffff88800f79fc80: 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 00
[ 17.567270] >ffff88800f79fd00: 00 00 00 00 f3 f3 f3 f3 f3 00 00 00 00 00 00 00
[ 17.567270] ^
[ 17.567270] ffff88800f79fd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
[ 17.567270] ffff88800f79fe00: f1 f1 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 17.567270] ==================================================================
[ 17.658376] Disabling lock debugging due to kernel taint
I have another proposed fix:
https://lore.kernel.org/all/20260625-xfrm-pol-out-tmpl-iptfs-reject-fix-v1-1-814861129086@secunet.com/
After this IPTF wouldn't be allowed.
ip xfrm policy add src 10.1.1.1/32 dst 10.1.1.2/32 dir out tmpl \
src fc00::dead:1 dst fc00::dead:2 proto esp reqid 1 mode iptfs \
level use tmpl src fc00::dead:1 dst fc00::dead:2 proto esp reqid 2 mode transport
Error: Mode in optional template not allowed in outbound policy.
>
> This causes `xfrm_state_find()` to interpret the IPv4 flow addresses
> (allocated on the stack as `struct flowi4` in `raw_sendmsg` or
> `udp_sendmsg`) as IPv6 addresses (`xfrm_address_t`), leading to a
> 16-byte read from the 4-byte stack variables, triggering KASAN.
>
> Fix this by tracking the active family of the flow (`cur_family`)
> during template resolution:
> 1. Initialize `cur_family` to the flow's original family.
> 2. For transport templates, verify that `tmpl->encap_family` matches
> `cur_family`. If they mismatch, abort with -EINVAL.
> 3. When a template that can change the family (tunnel, beet, iptfs) is
> successfully resolved, update `cur_family` to `tmpl->encap_family`.
> 4. If a template is skipped (optional), `cur_family` remains unchanged.
>
> This prevents mismatched transport lookups and makes the resolution
> robust against any family-transition gaps.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: syzbot+0ac4d84afe1066a1f3e9@syzkaller.appspotmail.com
> Closes: https://www.spinics.net/lists/netdev/msg1200923.html
> Assisted-by: Jetski:gemini-3.1-pro-preview
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
> Cc: Steffen Klassert <steffen.klassert@secunet.com>
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> ---
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-25 17:43 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 9:24 [PATCH net] xfrm: fix stack-out-of-bounds in xfrm_tmpl_resolve_one Eric Dumazet
2026-06-25 17:43 ` Antony Antony
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox