https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=288263

            Bug ID: 288263
           Summary: with pf, link-local target address in icmp6 ADVERT can
                    cause NULL deref
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: [email protected]
          Reporter: [email protected]
 Attachment #262207 text/plain
         mime type:

Created attachment 262207
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=262207&action=edit
demonstrate link-local address problem with ip6 and pf

I've attached a demo that sets up tun0 for ip6 and pf with

  pass in on tap0 inet6 from any to any af-to inet from 192.168.3.1 keep state

The demo sends ip6 / icmp6 / ND_NEIGHBOR_ADVERT / target=ff a2 00 03...
on tap0, but with an illegal ip6_dst. Target "ff a2 00 03" is a
link-local address, and on my setup interface #3 is pflog0.

ip6_forward() rejects the packet and calls icmp6_error(), whose
ip6_output() calls pf_check6_out() / pf_test() / pf_test_state_icmp(),
which changes the error reply's ip6 destination to the target found
inside the original icmp6 packet, i.e. to the link-local address ff a2
00 03, in this code:

                                if (PF_ANEQ(pd2.src,
                                    &nk->addr[pd2.sidx], pd2.af) ||
                                    ((virtual_type ==
htons(ICMP6_ECHO_REQUEST)) &&
                                    nk->port[pd2.sidx] != iih->icmp6_id))
                                        pf_change_icmp(pd2.src,
                                            (virtual_type ==
htons(ICMP6_ECHO_REQUEST))
                                            ? &iih->icmp6_id : NULL,
                                            daddr, &nk->addr[pd2.sidx],
                                            (virtual_type ==
htons(ICMP6_ECHO_REQUEST))
                                            ? nk->port[iidx] : 0, NULL,
                                            pd2.ip_sum, icmpsum,
                                            pd->ip_sum, 0, AF_INET6);

Then ip6_output() continues, now with the link-local ip6_dst. If the
link specified in the address is not configured for ip6, then there's
a crash in this code in ip6_output():

        if ((flags & IPV6_FORWARDING) == 0) {
                /* XXX: the FORWARDING flag can be set for mrouting. */
                in6_ifstat_inc(ifp, ifs6_out_request);
        }

because in6_ifstat_inc() attempts to dereference ifp->if_afdata[AF_INET6],
which can be NULL for a non-ip6 interface.

The demo code I've attached supplies a link-local address with
interface #3, which on my setup is pflog0. You may need to adjust the
demo code if your pflog0 has a different index and you want to see the
crash.

# uname -a
FreeBSD xxx 15.0-CURRENT FreeBSD 15.0-CURRENT #30 main-n275522-551d428b5bdc:
Fri Jun 27 16:05:41 AST 2025    
root@xxx:/usr/obj/usr/src/amd64.amd64/sys/GENERIC amd64
# cc npf23b.c
# ./a.out
...
Fatal trap 12: page fault while in kernel mode
cpuid = 2; apic id = 02
fault virtual address   = 0x0
fault code              = supervisor read data, page not present
instruction pointer     = 0x20:0xffffffff80e0a10f
stack pointer           = 0x28:0xfffffe00d6de8610
frame pointer           = 0x28:0xfffffe00d6de87c0
code segment            = base 0x0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = 759 (a.out)
rdi: ffffffff81df7d80 rsi: fffff80066613800 rdx: fffffe00d6de8644
rcx: 5f1221280300a2ff  r8: ffffffff81ad48a0  r9: 0000000000000000
rax: 0000000000000000 rbx: 0000000000000000 rbp: fffffe00d6de87c0
r10: 0000000000000000 r11: 0000000000000001 r12: 0000000000000000
r13: fffffe00d6de872c r14: fffff80066613800 r15: 0000000000000000
trap number             = 12
panic: page fault
cpuid = 2
time = 1752681305
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe00d6de8340
vpanic() at vpanic+0x136/frame 0xfffffe00d6de8470
panic() at panic+0x43/frame 0xfffffe00d6de84d0
trap_pfault() at trap_pfault+0x48d/frame 0xfffffe00d6de8540
calltrap() at calltrap+0x8/frame 0xfffffe00d6de8540
--- trap 0xc, rip = 0xffffffff80e0a10f, rsp = 0xfffffe00d6de8610, rbp =
0xfffffe00d6de87c0 ---
ip6_output() at ip6_output+0xeef/frame 0xfffffe00d6de87c0
icmp6_reflect() at icmp6_reflect+0x329/frame 0xfffffe00d6de8880
icmp6_error() at icmp6_error+0x3e4/frame 0xfffffe00d6de88f0
ip6_forward() at ip6_forward+0x835/frame 0xfffffe00d6de89f0
ip6_input() at ip6_input+0xd0b/frame 0xfffffe00d6de8ad0
netisr_dispatch_src() at netisr_dispatch_src+0xb4/frame 0xfffffe00d6de8b30
ether_demux() at ether_demux+0x16a/frame 0xfffffe00d6de8b60
ether_nh_input() at ether_nh_input+0x3ce/frame 0xfffffe00d6de8bb0
netisr_dispatch_src() at netisr_dispatch_src+0xb4/frame 0xfffffe00d6de8c10
ether_input() at ether_input+0xd5/frame 0xfffffe00d6de8c70
tunwrite() at tunwrite+0x57d/frame 0xfffffe00d6de8ce0
devfs_write_f() at devfs_write_f+0xf3/frame 0xfffffe00d6de8d40
dofilewrite() at dofilewrite+0x81/frame 0xfffffe00d6de8d90
sys_write() at sys_write+0xb7/frame 0xfffffe00d6de8e00
amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe00d6de8f30
fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe00d6de8f30
--- syscall (4, FreeBSD ELF64, write), rip = 0x8234dfe9a, rsp = 0x820d911e8,
rbp = 0x820d91320 ---

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to