Bug 291003 - Fix panic in in6_selecthlim() while creating bridge interface
Summary: Fix panic in in6_selecthlim() while creating bridge interface
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 16.0-CURRENT
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-net (Nobody)
URL:
Keywords: crash
Depends on:
Blocks:
 
Reported: 2025-11-13 19:40 UTC by Olivier Cochard
Modified: 2025-11-19 20:55 UTC (History)
4 users (show)

See Also:


Attachments
patch fully generated by claude-code (4.40 KB, patch)
2025-11-13 19:40 UTC, Olivier Cochard
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Olivier Cochard freebsd_committer freebsd_triage 2025-11-13 19:40:59 UTC
Created attachment 265401 [details]
patch fully generated by claude-code

Running a  FreeBSD 16.0-CURRENT #2 main-n281790-abd53b16c03f is easy to crash, 100% reproducible on my setup (here using a USB ethernet adapter):

```
sudo sysrc cloned_interfaces="bridge0 tap0"
sudo sysrc ifconfig_ue0="up"
sudo sysrc ifconfig_bridge0="up addm ue0 addm tap0"
sudo service netif restart && sudo service routing restart
```

It will generate this panic:
```
 Fatal trap 12: page fault while in kernel mode
cpuid = 6; apic id = 00
fault virtual address   = 0x10
fault code              = supervisor read data, page not present
instruction pointer     = 0x20:0xffffffff80da6435
stack pointer           = 0x28:0xfffffe016020f940
frame pointer           = 0x28:0xfffffe016020f970
code segment            = base rx0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = 7689 (sshd-session)
rdi: fffff800225d3800 rsi: 000000000000001c rdx: fffff8000184ec78
rcx: fffff800225d3800  r8: 00000000ffffffbd  r9: 0000000000000000
rax: 0000000000000000 rbx: 0000000000000000 rbp: fffffe016020f970
r10: fffffe016020f8f0 r11: 0000000000000008 r12: 0000000000010300
r13: 0000000000000000 r14: fffffe016020f94c r15: fffff80041ea9400
trap number             = 12
panic: page fault
cpuid = 6
time = 1763050117
KDB: stack backtrace:
#0  __curthread () at /usr/src/sys/amd64/include/pcpu_aux.h:57
#1  doadump (textdump=textdump@entry=0) at /usr/src/sys/kern/kern_shutdown.c:399
#2  0xffffffff804a414a in db_dump (dummy=<optimized out>, dummy2=<optimized out>, dummy3=<optimized out>,
    dummy4=<optimized out>) at /usr/src/sys/ddb/db_command.c:596
#3  0xffffffff804a3f3d in db_command (last_cmdp=<optimized out>, cmd_table=<optimized out>, dopager=true)
    at /usr/src/sys/ddb/db_command.c:508
#4  0xffffffff804a3bfd in db_command_loop () at /usr/src/sys/ddb/db_command.c:555
#5  0xffffffff804a7526 in db_trap (type=<optimized out>, code=<optimized out>) at /usr/src/sys/ddb/db_main.c:267
#6  0xffffffff80bd1a95 in kdb_trap (type=type@entry=3, code=code@entry=0, tf=tf@entry=0xfffffe016020f5d0)
    at /usr/src/sys/kern/subr_kdb.c:790
#7  0xffffffff81099ffc in trap (frame=<optimized out>) at /usr/src/sys/amd64/amd64/trap.c:614
#8  <signal handler called>
#9  kdb_enter (why=<optimized out>, msg=<optimized out>) at /usr/src/sys/kern/subr_kdb.c:556
#10 0xffffffff80b838ab in vpanic (fmt=0xffffffff811f2708 "%s", ap=ap@entry=0xfffffe016020f800)
    at /usr/src/sys/kern/kern_shutdown.c:962
#11 0xffffffff80b83713 in panic (fmt=0xffffffff818a42f8 <vt_conswindow+16> "\262\302$\201\377\377\377\377")
    at /usr/src/sys/kern/kern_shutdown.c:887
#12 0xffffffff8109aa1f in trap_fatal (frame=<optimized out>, eva=<optimized out>)
    at /usr/src/sys/amd64/amd64/trap.c:969
#13 0xffffffff8109aa1f in trap_pfault (frame=0xfffffe016020f880, usermode=false, signo=<optimized out>,
    ucode=<optimized out>)
#14 <signal handler called>
#15 0xffffffff80da6435 in in6_selecthlim (inp=inp@entry=0xfffff800711a5000, ifp=ifp@entry=0x0)
    at /usr/src/sys/netinet6/in6_src.c:872
#16 0xffffffff80d7107e in tcp_default_output (tp=0xfffff800711a5000) at /usr/src/sys/netinet/tcp_output.c:1447
#17 0xffffffff80d82afa in tcp_output_nodrop (tp=0xfffff800711a5000) at /usr/src/sys/netinet/tcp_var.h:720
#18 tcp_usr_send (so=0xfffff80022879000, flags=0, m=0x0, nam=<optimized out>, control=<optimized out>,
    td=<optimized out>) at /usr/src/sys/netinet/tcp_usrreq.c:1127
#19 0xffffffff80c30c5f in sosend_generic_locked (so=so@entry=0xfffff80022879000, addr=addr@entry=0x0,
    uio=uio@entry=0xfffffe016020fda8, top=0xfffff80041ea9400, top@entry=0x0, control=control@entry=0x0,
    flags=flags@entry=0, td=0xfffff8000c3e2780) at /usr/src/sys/kern/uipc_socket.c:2537
#20 0xffffffff80c30541 in sosend_generic (so=0xfffff80022879000, addr=0x0, uio=0xfffffe016020fda8, top=0x0,
    control=0x0, flags=0, td=0xfffff8000c3e2780) at /usr/src/sys/kern/uipc_socket.c:2586
#21 0xffffffff80c311bf in sousrsend (so=0xfffff800225d3800, addr=0x1c, uio=0xfffff8000184ec78,
    control=0xffffffbd, flags=0, userproc=0x0) at /usr/src/sys/kern/uipc_socket.c:2626
#22 0xffffffff80bf5c01 in fo_write (fp=0xfffff8000e9a2c30, uio=0xfffffe016020fda8,
    active_cred=0xfffff8000184ec78, td=0xfffff8000c3e2780, flags=<optimized out>) at /usr/src/sys/sys/file.h:370
#23 dofilewrite (td=td@entry=0xfffff8000c3e2780, fd=fd@entry=7, fp=0xfffff8000e9a2c30,
    auio=auio@entry=0xfffffe016020fda8, offset=offset@entry=-1, flags=flags@entry=0)
    at /usr/src/sys/kern/sys_generic.c:565
#24 0xffffffff80bf5607 in kern_writev (td=0xfffff8000c3e2780, fd=7, auio=0xfffffe016020fda8)
    at /usr/src/sys/kern/sys_generic.c:492    
```

So I’ve requested claude code (AI agent) to study this problem and to wrote a patch (attached).
Once applied, I wasn’t able to reproduce the panic.

Here is the explanation that claude code generated:
```
  Root Cause

  The kernel panics were caused by NULL pointer dereferences in IPv6 code during network interface
  reconfiguration. The fundamental issue was that several IPv6 macros and functions assumed that
  ifp->if_afdata[AF_INET6] (IPv6 interface data) would always be available when ifp (network interface)
  exists.

  Technical Details:

  - When it happens: During bridge setup, interface configuration changes, or network reconfiguration
  - Why it happens: IPv6 data structures (struct in6_ifextra) can be temporarily unavailable while the base
  interface (struct ifnet) still exists
  - Where it manifests: Multiple locations in the IPv6 stack that use macros like ND_IFINFO(),
  in6_ifstat_inc(), LLTABLE6(), and DAD_FAILURES()

  Specific Crash Locations:

  1. First crash: in6_selecthlim() at line 872 in /usr/src/sys/netinet6/in6_src.c
  2. Second crash: ip6_output() at line 805 via in6_ifstat_inc() macro
  3. Potential crashes: Multiple other locations using similar unsafe patterns

  Solution

  Implemented defensive programming throughout the IPv6 stack by adding NULL checks before accessing
  IPv6-specific data structures.

  Files Modified:

  1. /usr/src/sys/netinet6/in6_src.c

  // BEFORE (unsafe):
  return (ND_IFINFO(ifp)->chlim);

  // AFTER (safe):
  ext = (struct in6_ifextra *)if_getafdata(ifp, AF_INET6);
  if (ext != NULL)
      return (ext->nd_ifinfo->chlim);

  2. /usr/src/sys/netinet6/in6_var.h

  // BEFORE (unsafe):
  #define in6_ifstat_inc(ifp, tag) \
  do { \
      if (ifp) \
          counter_u64_add(((struct in6_ifextra *) \
              ((ifp)->if_afdata[AF_INET6]))->in6_ifstat[...], 1); \
  } while (0)
  // AFTER (safe):
  #define in6_ifstat_inc(ifp, tag) \
  do { \
      if ((ifp) && (ifp)->if_afdata[AF_INET6]) \
          counter_u64_add(((struct in6_ifextra *) \
              ((ifp)->if_afdata[AF_INET6]))->in6_ifstat[...], 1); \
  } while (0)

  3. Multiple usage sites for DAD_FAILURES:

  - in6_ifattach.c: Added conditional check before atomic_load_int()
  - nd6_rtr.c: Added NULL check in conditional expression
  - nd6_nbr.c: Added checks before all atomic operations

  Key Changes:

  1. in6_selecthlim(): Replaced ND_IFINFO() macro with explicit NULL-safe code
  2. in6_ifstat_inc macro: Added (ifp)->if_afdata[AF_INET6] NULL check
  3. LLTABLE6 macro: Made it return NULL when IPv6 data unavailable
  4. DAD_FAILURES usage: Added NULL checks at all call sites to prevent atomic operations on NULL pointers

  Impact

  - Stability: Eliminates kernel panics during network reconfiguration
  - Compatibility: Maintains all existing functionality when IPv6 structures are properly initialized
  - Performance: Minimal overhead (just NULL pointer checks)
  - Scope: Comprehensive fix covering the entire IPv6 stack's vulnerable patterns
```
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2025-11-13 20:05:55 UTC
^Triage: assign.

Note to reviewers: the patch was generated by Claude code.
Comment 2 O. Hartmann 2025-11-14 14:38:06 UTC
After FreeBSD 16.0-CURRENT #101 master-n281878-587490dabc64: Thu Nov 13 16:12:43 CET 2025 amd64 with a very similar setup as reported herein (bridge setup) our CURRENT boxes crash in a similar way as reported. When will the patch to fix the issue hit the source tree?
Comment 3 Zhenlei Huang freebsd_committer freebsd_triage 2025-11-14 15:16:49 UTC
I think this bug is same with PR 279653 . But this report has some steps to reproduce.