[Bug 297439] netmap: pipe peer teardown leaves a NULL kring array in netmap_monitor_stop()

[email protected]
Newsgroups gmane.os.freebsd.bugs
Message-ID <[email protected]/bugzilla/>
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297439

            Bug ID: 297439
           Summary: netmap: pipe peer teardown leaves a NULL kring array
                    in netmap_monitor_stop()
           Product: Base System
           Version: 14.4-STABLE
          Hardware: amd64
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: [email protected]
          Reporter: [email protected]

Created attachment 273631
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=273631&action=edit
Minimized four-call pipe master/slave reproducer

Overview
  ========

  A netmap pipe master/slave registration sequence can leave an adapter with a
  NULL TX/RX kring-array pointer while its advertised ring count remains
  nonzero.

  During descriptor teardown, netmap_do_unregif() reaches
  netmap_monitor_stop(). The latter iterates over the advertised rings and
  dereferences NMR(na, t)[i], even though the selected ring-array base is NULL.
  This produces a supervisor read from address 0 and a kernel page fault.

  The crash has been reduced to a four-call modern NIOCCTRL registration
  program containing one pipe master registration and one corresponding pipe
  slave registration.

  Tested environment
  ==================

  Operating system: FreeBSD 14.4-STABLE
  Architecture: amd64
  Kernel ident: SYZKALLER
  Base image source revision: cc921088d9ee
  Base image date: 2026-05-14
  Virtualization: QEMU/KVM

  The kernel is based on the FreeBSD 14.4-STABLE amd64 image identified by
  revision cc921088d9ee, with the SYZKALLER kernel
  configuration/instrumentation.

  The reported reproductions were performed as root in clean snapshot VMs.
  Unprivileged-user and jail reachability have not been tested.

  Reproducer
  ==========

  The attached minimized .syz program contains four system calls:

  1. open /dev/netmap
  2. register a netmap pipe master named "vale0:pipebase{p0"
  3. open /dev/netmap
  4. register the corresponding pipe slave named "vale0:pipebase}p0"

  The program does not contain explicit close() calls. Descriptor teardown
  occurs when the executor process exits.

  The reproducer uses a local syzkaller syscall-description suffix named
  NIOCCTRL_SAFE. This suffix invokes the normal NIOCCTRL ioctl with a regular
  NETMAP_REQ_REGISTER request. The suffix only constrains mutation of the
  request fields; it does not refer to a different kernel ioctl.

  The crash reproduced using the following syzkaller execution settings:

      Threaded: true
      Repeat: true
      Procs: 6
      Sandbox: none

  A single one-shot execution is not claimed to reproduce deterministically.
  The four-call input reproduced the exact crash site in a clean VM under the
  above repeated threaded settings.

  A subsequent focused pipe-lifecycle campaign used the minimized program as a
  seed. It reached the same direct instruction pointer eight times across
  consecutive VM boots, including hits after only 25, 33, 47, and 65 cumulative
  executions.

  Observed result
  ===============

  The original and reproduced failures reported:

      Fatal trap 12: page fault while in kernel mode
      fault virtual address = 0x0
      instruction pointer = 0xffffffff80a1ff80
      panic: page fault

  Relevant stack:

      panic
      trap_pfault
      netmap_do_unregif+0x1c7
      netmap_dtor+0xae
      devfs_destroy_cdevpriv
      devfs_close_f
      _fdrop
      closef
      fdescfree / closefp_impl
      exit1 / amd64_syscall

  Exact-image disassembly resolves direct instruction pointer
  0xffffffff80a1ff80 to netmap_monitor_stop(), inlined or called from the
  netmap_do_unregif path.

  At the faulting instruction, the selected TX/RX kring-array base is NULL.
  The adapter still has a nonzero ring count, so the loop executes and attempts
  to evaluate:

      NMR(na, t)[i]

  This results in a read from address 0.

  Expected result
  ===============

  Closing or destroying either endpoint of a netmap pipe must not leave the
  peer or a related adapter with NULL ring arrays and stale nonzero ring
  counts.

  Teardown should either preserve the arrays until the final user is gone or
  atomically clear/update all state used by later teardown and monitor cleanup.

  Confirmed invariant violation
  =============================

  The directly confirmed state at the crash is:

  1. The TX/RX kring-array pointer selected by NMR(na, t) is NULL.
  2. netmap_all_rings(na, t), or the corresponding ring-count state, still
     causes netmap_monitor_stop() to enter the ring loop.
  3. netmap_monitor_stop() indexes the NULL array.
  4. The crash occurs during descriptor teardown through netmap_do_unregif().

  Possible underlying cause
  =========================

  The current leading hypothesis involves pipe-peer teardown.

  netmap_pipe_krings_delete_both() can delete or clear the kring arrays for
  both pipe endpoints. A later teardown of the other still-live endpoint may
  then enter netmap_monitor_stop() using stale/nonzero ring-count metadata
  after the peer arrays have already been cleared.

  This hypothesis is consistent with:

  - the minimized master/slave registration sequence;
  - the fault occurring during process-exit descriptor teardown;
  - related crashes observed in netmap_pipe_krings_delete_both();
  - exact register and disassembly evidence showing a NULL array with a
    nonempty ring iteration range.

  However, the precise reference-count or ownership transition responsible for
  the stale state has not yet been proven. This report therefore distinguishes
  the confirmed NULL-array invariant violation from the proposed pipe-peer
  teardown explanation.

  Impact
  ======

  The demonstrated impact is a local kernel panic caused by a NULL pointer
  dereference during netmap descriptor teardown.

  The reproductions reported here were performed as root and require access to
  /dev/netmap. Unprivileged-user and jail reachability have not been tested.

  Exploitability has not been assessed.

  Affected branches
  =================

  The issue was reproduced on stable/14.

  Source review found the same relevant monitor-stop ring iteration and
  two-endpoint pipe teardown structure in FreeBSD main, but the crash has not
  yet been reproduced on main.

  Suggested investigation
  =======================

  No tested patch is currently provided.

  Areas that may need review include:

  1. Ownership and reference transitions between pipe master and slave
     adapters.
  2. Whether netmap_pipe_krings_delete_both() can clear both endpoints while
     one endpoint remains reachable.
  3. Whether ring counts and kring-array pointers are updated atomically and
     consistently.
  4. Whether netmap_monitor_stop() should defensively reject a NULL ring array
     even when a nonzero ring count is present.
  5. Whether teardown of the second endpoint can enter monitor cleanup after
     the peer has already removed the shared ring state.

  Reproduction history
  ====================

  The original fuzzing campaign saved five reports at the same direct crash
  site.

  Automatic reduction then produced the following accepted exact-title
  reproducers:

  - 9-call modern-only program;
  - 6-call master/slave pipe program;
  - final 4-call master/slave pipe program.

  Removing either complete open/register pair prevented reproduction during
  minimization. Both successful master and slave registrations are therefore
  required at the syscall level in the current minimized input.

  The focused follow-up campaign subsequently produced eight additional exact
  direct-PC hits across consecutive VM boots.

  Tools used
  ==========

  The issue was discovered and reproduced using syzkaller with locally
  developed FreeBSD netmap syscall descriptions and structured seed programs.

  AI-assisted tools were used to organize experiment artifacts, inspect crash
  logs, group related crash sites, and help draft this report. The minimized
  input, direct fault location, register state, and reproduction results were
  manually checked against the saved kernel image and source tree.

-- 
You are receiving this mail because:
You are the assignee for the bug.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.