[Bug 295644] net/ngrep: -I broken by Capsicum patch; pcap_fileno() returns -1 for savefile handles

From: <bugzilla-noreply_at_freebsd.org>
Date: Wed, 27 May 2026 13:36:12 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=295644

            Bug ID: 295644
           Summary: net/ngrep: -I broken by Capsicum patch; pcap_fileno()
                    returns -1 for savefile handles
           Product: Ports & Packages
           Version: Latest
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: Individual Port(s)
          Assignee: ports-bugs@FreeBSD.org
          Reporter: lbm@lbm.dk

Description:
============

`ngrep -I file.pcap` exits immediately with
"unable to limit pcap descriptor" on FreeBSD 14.4 with ngrep
1.48.3.  Reproduces regardless of whether CAPSICUM is enabled.

System: FreeBSD 14.4, ngrep 1.48.3, libpcap 1.10.5

Reproduction:
  pkg install net/ngrep   # default options, CAPSICUM on or off
  tcpdump -w /tmp/test.pcap -c 10
  ngrep -I /tmp/test.pcap

Expected: packet output
Actual:   "unable to limit pcap descriptorexit" (exit code 1)

The "exit" suffix is stdout from clean_exit() interleaved with
the stderr fprintf -- two separate strings on stdout and stderr.

Root cause 1 (primary): pcap_fileno() returns -1 for offline handles
---------------------------------------------------------------------
The Capsicum sandboxing block added by patch-ngrep.c calls:

    cap_rights_limit(pcap_fileno(pd), &rights)

When pd was opened with pcap_open_offline() (i.e. the -I flag),
pcap_fileno() returns -1.  There is no BPF device fd for a savefile
handle -- libpcap uses a FILE* internally and sets p->fd = -1.

cap_rights_limit(-1, ...) fails with EBADF (errno 9), not ENOSYS (38),
so the errno != ENOSYS guard does not fire and ngrep exits.

This worked in the ngrep 1.45 port era because the libpcap available at
that time returned fileno(fp->sf.rfile) from pcap_fileno() for offline
handles.  Modern libpcap no longer does this.

The fix is to cache pcap_fileno(pd) and skip cap_rights_limit() and
cap_ioctls_limit() when the fd is -1.  Offline handles need no Capsicum
fd sandboxing since the file is already open; live captures
on a BPF device are unaffected.

Root cause 2 (contributing): USE_CAPSICUM always defined
---------------------------------------------------------
Even with CAPSICUM set to off in the port options, the Capsicum code is
compiled in, which is why root cause 1 affects all users,
not only those who explicitly enabled CAPSICUM.

patch-configure.ac never initialises USE_CAPSICUM to "0".  The detection
block only sets it in the success branch; the else branch
leaves the shell variable empty:

    if ...; then
        USE_CAPSICUM="1"    # set on success
    else
        AC_MSG_RESULT(no)   # USE_CAPSICUM left empty
    fi
    AC_DEFINE_UNQUOTED(USE_CAPSICUM, $USE_CAPSICUM, ...)

AC_DEFINE_UNQUOTED with an empty second argument writes:

    #define USE_CAPSICUM

to config.h -- defined with no value regardless of the option.

patch-ngrep.c then uses #ifdef USE_CAPSICUM throughout, which tests for
mere presence of the macro rather than its value.  The Capsicum
code compiles in unconditionally.  The "CONFIG: capsicum disabled"
message is from AC_MSG_RESULT and misleading -- code is always active.

Fix:
====
Two patches are attached, each addressing one concern.  Both apply
to ports tree commit ad45e2e26e700cddd942fd3da0424e92cc0568d0.

0001-net-ngrep-fix-capsicum-crash-with-i-offline-capture.patch:
  patch-ngrep.c: cache pcap_fileno(pd) in a local int and guard both
  cap_rights_limit() and cap_ioctls_limit() calls with pcap_fd >= 0,
  so offline handles (pcap_fileno returns -1) are silently skipped.

0002-net-ngrep-fix-use_capsicum-always-defined.patch:
  patch-ngrep.c: replace all #ifdef USE_CAPSICUM with #if USE_CAPSICUM
  so the preprocessor tests the value rather than mere presence.
  patch-configure.ac: initialise USE_CAPSICUM="0" before the detection
  block so AC_DEFINE_UNQUOTED always emits a numeric value (0 or 1).

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