[GH-ISSUE #7292] [Bug] Invalid pcap limiter selections are misreported as capinfos or unreadable-output failures #4327

Closed
opened 2026-10-31 00:48:57 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 26, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7292

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Provider or capability discovery

Observed behavior

On Linux, inspect-pcap-capture admits a directory or /usr/bin/true selected through REA_TSHARK_PRLIMIT_COMMAND, then attributes the resulting failure to the capture tool or its output. Relative and missing limiter paths instead receive the existing limiter-specific configuration refusal. The same capture and controlled Wireshark fixtures succeed with real util-linux prlimit.

The directory case exits 1 with capability_unavailable, but its message says Cannot run selected tool <work>/capinfos: spawn <work>/limiter-directory EACCES and recommends supplying Wireshark through REA_TSHARK_COMMAND or REA_CAPINFOS_COMMAND. The limiter path is present in the spawn diagnostic; its configuration variable and the appropriate recovery instruction are absent. The /usr/bin/true case exits 1 with unreadable_output, category execution_failure, no details, and generic doctor guidance. Neither case runs either fixture in data mode; the successful version probes do run.

Reproduction

From a prepared checkout root on Linux, with its supported Node version, Python 3 and /usr/bin/prlimit available, run the following program. It creates a valid empty 24-byte pcap header, two shell fixtures with Wireshark 4.x version banners, fixed zero-packet metadata and an empty TShark packet array. Marker files distinguish version probes from data commands. Writable home/config/cache/temp state is isolated. These are controlled producer fixtures, not real Wireshark.

python3 - <<'PYTHON'
import json, os, pathlib, shutil, subprocess, tempfile
node = shutil.which('node')
assert node, 'Use the Node version required by this checkout'
with tempfile.TemporaryDirectory(prefix='pcap-limiter-') as directory:
    work = pathlib.Path(directory).resolve()
    env = {'PATH': os.environ['PATH']}
    for key, name in [('HOME','home'), ('TMPDIR','tmp'), ('XDG_CONFIG_HOME','config'), ('XDG_CACHE_HOME','cache'), ('XDG_DATA_HOME','data'), ('XDG_STATE_HOME','state')]:
        path = work / name
        path.mkdir()
        env[key] = str(path)
    selected_directory = work / 'limiter-directory'
    selected_directory.mkdir()
    capture = work / 'capture.pcap'
    capture.write_bytes(bytes.fromhex('d4c3b2a1020004000000000000000000ffff000001000000'))
    for tool, banner, output in [
        ('tshark', 'TShark', '[]'),
        ('capinfos', 'Capinfos', 'File type: Wireshark/tcpdump/... - pcap\nFile encapsulation: Ethernet\nPacket size limit: file hdr: 65535 bytes\nNumber of packets: 0\nCapture duration: 0.000 seconds\nEarliest packet time: n/a\nLatest packet time: n/a\n')]:
        executable = work / tool
        executable.write_text('#!/bin/sh\nif [ "$1" = "--version" ]; then echo "'+banner+' (Wireshark) 4.6.6-fixture"; exit 0; fi\necho ran >> "'+str(work / (tool+'-runs'))+'"\ncat <<\'OUTPUT\'\n'+output+'\nOUTPUT\n')
        executable.chmod(0o755)
        env['REA_'+tool.upper()+'_COMMAND'] = str(executable)
    for name, limiter in [('relative','relative-prlimit'), ('missing',str(work / 'missing')), ('directory',str(selected_directory)), ('non-limiter','/usr/bin/true'), ('control','/usr/bin/prlimit')]:
        env['REA_TSHARK_PRLIMIT_COMMAND'] = limiter
        for tool in ['tshark','capinfos']:
            (work / (tool+'-runs')).unlink(missing_ok=True)
        result = subprocess.run([node,'scripts/rea.mjs','inspect-pcap-capture',str(capture),'--json'],env=env,capture_output=True,text=True,timeout=60)
        data = json.loads(result.stdout)
        print(json.dumps({'case':name, 'exit':result.returncode, 'code':data.get('code'), 'category':data.get('category'), 'details_present':'details' in data, 'coverage':data.get('normalized_result',{}).get('coverage'), 'capinfos_data_ran':(work/'capinfos-runs').exists(), 'tshark_data_ran':(work/'tshark-runs').exists(), 'message':data.get('message'), 'stderr':result.stderr}).replace(str(work),'<work>'))
PYTHON

I ran this exact program once as uid 1000 in the environment below; both failing selections also reproduced in a preceding independent fixture run. Each run's real-prlimit control succeeded. The program replaces only the generated fixture root with <work> in printed output and removes its fixtures on exit.

Expected behavior

An unusable selected Linux limiter should receive a limiter-specific capability/configuration refusal identifying REA_TSHARK_PRLIMIT_COMMAND and the selected path, consistent with the existing relative/missing-path refusal. A directory should fail admission before capture acquisition. A non-limiter executable must not be presented as unreadable capinfos output; it should produce actionable limiter configuration guidance. Real util-linux prlimit must keep succeeding. This concerns the existing configuration and error-attribution contract.

Impact and scope

P2: callers receive the wrong recovery route, and the non-limiter case changes the machine-readable outcome from a configuration refusal to an execution/output failure with no details. The observed scope is Linux CLI saved-capture inspection with these two invalid limiter selections. The operation fails; no successful capture result, source modification or data loss was observed. Source inspection shows capture snapshot acquisition occurs after the faulty admission and before these failures, so this is not a claim that capture bytes remain unopened. Correcting the variable to /usr/bin/prlimit restored the same fixture workflow in both runs. Natural occurrence frequency, other platforms and real-Wireshark execution are NOT_ENOUGH_INFO because they were not measured or run.

REA version

Source revision 0d1a454e25; prepared checkout CLI reports 6.8.0. Live main initially matched this revision; the prepublication update changed only unrelated desktop documentation. This is a source-checkout runtime reproduction, not a published-package runtime test.

Runtime and platform

Node.js v24.22.1; Linux arm64, Debian bookworm container, uid 1000; prlimit from util-linux 2.38.1; no network access during reproduction. Wireshark commands are the shell fixtures above.

Target and artifact context

Synthetic empty pcap header with Ethernet link type and snaplen 65535; no recorded traffic or external target. Only disposable fixture state is written.

Interface

CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

  • Expected source: docs/pcap-analysis.md, Supply tools, requires Linux util-linux prlimit and documents its override; src/pcap/PcapNativeBound.ts:70-80 defines the limiter-specific capability refusal and names REA_TSHARK_PRLIMIT_COMMAND as the recovery action.
  • Failure source: the executed CLI results below; src/pcap/PcapNativeBound.ts:49-69 admits the directory/non-limiter after realpath and execute-access checks, while src/pcap/PcapCommand.ts:290-300 attributes spawn EACCES to the selected capinfos command. src/pcap/PcapOutput.ts:87-97 rejects the empty metadata resulting from /usr/bin/true.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Selected fields from actual output, with the program's <work> root normalization:

{"case":"relative","exit":1,"code":"capability_unavailable","category":"unsupported_provider","details_present":true,"capinfos_data_ran":false,"tshark_data_ran":false}
{"case":"missing","exit":1,"code":"capability_unavailable","category":"unsupported_provider","details_present":true,"capinfos_data_ran":false,"tshark_data_ran":false}
{"case":"directory","exit":1,"code":"capability_unavailable","category":"unsupported_provider","details_present":true,"capinfos_data_ran":false,"tshark_data_ran":false,"message":"Cannot run selected tool <work>/capinfos: spawn <work>/limiter-directory EACCES. Supply Wireshark 4.x tshark and capinfos on PATH or through absolute REA_TSHARK_COMMAND and REA_CAPINFOS_COMMAND; REA does not install them."}
{"case":"non-limiter","exit":1,"code":"unreadable_output","category":"execution_failure","details_present":false,"capinfos_data_ran":false,"tshark_data_ran":false,"message":"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed."}
{"case":"control","exit":0,"coverage":"complete","capinfos_data_ran":true,"tshark_data_ran":true}

Typed outcome or recovery expected

A non-retryable limiter configuration/capability refusal naming the selected limiter and its environment variable. Preserve the existing actionable refusals for relative/missing paths and successful analysis with real prlimit.

Analysis or suspected cause

Source-derived trace: src/cli/pcapCommands.ts registers the public command through PcapAnalysisService, which validates the request and calls PcapProvider. Its client phase resolves, fingerprints and version-probes both selected Wireshark fixtures successfully. In PcapProvider.executeAdmitted, native-bound preparation precedes snapshot acquisition (src/pcap/PcapProvider.ts:784-789). The limiter admission checks neither regular-file type nor whether the executable can act as util-linux prlimit. PcapCommand subsequently launches the limiter with the capinfos command appended. The directory fails at spawn and is attributed to capinfos; /usr/bin/true returns zero without starting capinfos, so the metadata parser receives empty output. These causal statements come from source inspection; the public outcomes and fixture markers above were executed.

Additional context

One defect is reported: unusable limiter admission and its resulting error attribution. The directory and non-limiter cases share the configuration boundary and restoration criteria. Preserving a producer-contradiction reason after otherwise valid tool admission is a separate requirement. NOT_ENOUGH_INFO: last known good revision and published-package reproduction.

References

  • PR #2507 established actionable host-tool and limiter guidance; this report covers selections that escape its limiter refusal path.
  • Issue #6433 is completed for directory-selected tshark/capinfos identity reads. PR #6784 was closed because main already handled that case. Neither closure covers the separate limiter selection used here.
  • Design #3403 discusses sharing TShark selection ownership; its architectural acceptance criteria differ from this concrete limiter refusal. PR #6395 concerns sigrok limiter attribution, a separate provider. Open/closed issue and PR searches found no current exact duplicate for this pcap limiter case.

Restoration check

Rerun the program: directory selection must fail with limiter-specific capability guidance before capture acquisition; /usr/bin/true must yield a limiter-specific configuration failure rather than unreadable_output. Neither failing selection should run the data commands or blame capinfos installation. Relative and missing paths must retain their limiter-specific refusals. /usr/bin/prlimit must still run both data fixtures and return complete zero-packet Evidence. These are proposed acceptance checks; no REA fix was made or tested.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded Linux configuration failure is routed to the wrong recovery action; the non-limiter selection is also misclassified as an execution/output failure without details, impairing typed caller recovery. No false success or capture corruption was observed.
  • Workaround status: available
  • Workaround basis: Select real util-linux prlimit through its absolute path; the /usr/bin/prlimit control restored the same fixture workflow in both independent runs.
Originally created by @coygeek on GitHub (Oct 26, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7292 ## Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ## Area Provider or capability discovery ## Observed behavior On Linux, `inspect-pcap-capture` admits a directory or `/usr/bin/true` selected through `REA_TSHARK_PRLIMIT_COMMAND`, then attributes the resulting failure to the capture tool or its output. Relative and missing limiter paths instead receive the existing limiter-specific configuration refusal. The same capture and controlled Wireshark fixtures succeed with real util-linux prlimit. The directory case exits 1 with `capability_unavailable`, but its message says `Cannot run selected tool <work>/capinfos: spawn <work>/limiter-directory EACCES` and recommends supplying Wireshark through `REA_TSHARK_COMMAND` or `REA_CAPINFOS_COMMAND`. The limiter path is present in the spawn diagnostic; its configuration variable and the appropriate recovery instruction are absent. The `/usr/bin/true` case exits 1 with `unreadable_output`, category `execution_failure`, no `details`, and generic doctor guidance. Neither case runs either fixture in data mode; the successful version probes do run. ## Reproduction From a prepared checkout root on Linux, with its supported Node version, Python 3 and `/usr/bin/prlimit` available, run the following program. It creates a valid empty 24-byte pcap header, two shell fixtures with Wireshark 4.x version banners, fixed zero-packet metadata and an empty TShark packet array. Marker files distinguish version probes from data commands. Writable home/config/cache/temp state is isolated. These are controlled producer fixtures, not real Wireshark. ```sh python3 - <<'PYTHON' import json, os, pathlib, shutil, subprocess, tempfile node = shutil.which('node') assert node, 'Use the Node version required by this checkout' with tempfile.TemporaryDirectory(prefix='pcap-limiter-') as directory: work = pathlib.Path(directory).resolve() env = {'PATH': os.environ['PATH']} for key, name in [('HOME','home'), ('TMPDIR','tmp'), ('XDG_CONFIG_HOME','config'), ('XDG_CACHE_HOME','cache'), ('XDG_DATA_HOME','data'), ('XDG_STATE_HOME','state')]: path = work / name path.mkdir() env[key] = str(path) selected_directory = work / 'limiter-directory' selected_directory.mkdir() capture = work / 'capture.pcap' capture.write_bytes(bytes.fromhex('d4c3b2a1020004000000000000000000ffff000001000000')) for tool, banner, output in [ ('tshark', 'TShark', '[]'), ('capinfos', 'Capinfos', 'File type: Wireshark/tcpdump/... - pcap\nFile encapsulation: Ethernet\nPacket size limit: file hdr: 65535 bytes\nNumber of packets: 0\nCapture duration: 0.000 seconds\nEarliest packet time: n/a\nLatest packet time: n/a\n')]: executable = work / tool executable.write_text('#!/bin/sh\nif [ "$1" = "--version" ]; then echo "'+banner+' (Wireshark) 4.6.6-fixture"; exit 0; fi\necho ran >> "'+str(work / (tool+'-runs'))+'"\ncat <<\'OUTPUT\'\n'+output+'\nOUTPUT\n') executable.chmod(0o755) env['REA_'+tool.upper()+'_COMMAND'] = str(executable) for name, limiter in [('relative','relative-prlimit'), ('missing',str(work / 'missing')), ('directory',str(selected_directory)), ('non-limiter','/usr/bin/true'), ('control','/usr/bin/prlimit')]: env['REA_TSHARK_PRLIMIT_COMMAND'] = limiter for tool in ['tshark','capinfos']: (work / (tool+'-runs')).unlink(missing_ok=True) result = subprocess.run([node,'scripts/rea.mjs','inspect-pcap-capture',str(capture),'--json'],env=env,capture_output=True,text=True,timeout=60) data = json.loads(result.stdout) print(json.dumps({'case':name, 'exit':result.returncode, 'code':data.get('code'), 'category':data.get('category'), 'details_present':'details' in data, 'coverage':data.get('normalized_result',{}).get('coverage'), 'capinfos_data_ran':(work/'capinfos-runs').exists(), 'tshark_data_ran':(work/'tshark-runs').exists(), 'message':data.get('message'), 'stderr':result.stderr}).replace(str(work),'<work>')) PYTHON ``` I ran this exact program once as uid 1000 in the environment below; both failing selections also reproduced in a preceding independent fixture run. Each run's real-prlimit control succeeded. The program replaces only the generated fixture root with `<work>` in printed output and removes its fixtures on exit. ## Expected behavior An unusable selected Linux limiter should receive a limiter-specific capability/configuration refusal identifying `REA_TSHARK_PRLIMIT_COMMAND` and the selected path, consistent with the existing relative/missing-path refusal. A directory should fail admission before capture acquisition. A non-limiter executable must not be presented as unreadable capinfos output; it should produce actionable limiter configuration guidance. Real util-linux prlimit must keep succeeding. This concerns the existing configuration and error-attribution contract. ## Impact and scope P2: callers receive the wrong recovery route, and the non-limiter case changes the machine-readable outcome from a configuration refusal to an execution/output failure with no details. The observed scope is Linux CLI saved-capture inspection with these two invalid limiter selections. The operation fails; no successful capture result, source modification or data loss was observed. Source inspection shows capture snapshot acquisition occurs after the faulty admission and before these failures, so this is not a claim that capture bytes remain unopened. Correcting the variable to `/usr/bin/prlimit` restored the same fixture workflow in both runs. Natural occurrence frequency, other platforms and real-Wireshark execution are NOT_ENOUGH_INFO because they were not measured or run. ## REA version Source revision 0d1a454e25db825567782e461da21530bad4b158; prepared checkout CLI reports 6.8.0. Live main initially matched this revision; the prepublication update changed only unrelated desktop documentation. This is a source-checkout runtime reproduction, not a published-package runtime test. ## Runtime and platform Node.js v24.22.1; Linux arm64, Debian bookworm container, uid 1000; prlimit from util-linux 2.38.1; no network access during reproduction. Wireshark commands are the shell fixtures above. ## Target and artifact context Synthetic empty pcap header with Ethernet link type and snaplen 65535; no recorded traffic or external target. Only disposable fixture state is written. ## Interface CLI ## Earliest failure stage Setup or provider admission ## Relevant output or evidence - Expected source: `docs/pcap-analysis.md`, Supply tools, requires Linux util-linux prlimit and documents its override; `src/pcap/PcapNativeBound.ts:70-80` defines the limiter-specific capability refusal and names `REA_TSHARK_PRLIMIT_COMMAND` as the recovery action. - Failure source: the executed CLI results below; `src/pcap/PcapNativeBound.ts:49-69` admits the directory/non-limiter after realpath and execute-access checks, while `src/pcap/PcapCommand.ts:290-300` attributes spawn EACCES to the selected capinfos command. `src/pcap/PcapOutput.ts:87-97` rejects the empty metadata resulting from `/usr/bin/true`. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete Selected fields from actual output, with the program's `<work>` root normalization: ```json {"case":"relative","exit":1,"code":"capability_unavailable","category":"unsupported_provider","details_present":true,"capinfos_data_ran":false,"tshark_data_ran":false} {"case":"missing","exit":1,"code":"capability_unavailable","category":"unsupported_provider","details_present":true,"capinfos_data_ran":false,"tshark_data_ran":false} {"case":"directory","exit":1,"code":"capability_unavailable","category":"unsupported_provider","details_present":true,"capinfos_data_ran":false,"tshark_data_ran":false,"message":"Cannot run selected tool <work>/capinfos: spawn <work>/limiter-directory EACCES. Supply Wireshark 4.x tshark and capinfos on PATH or through absolute REA_TSHARK_COMMAND and REA_CAPINFOS_COMMAND; REA does not install them."} {"case":"non-limiter","exit":1,"code":"unreadable_output","category":"execution_failure","details_present":false,"capinfos_data_ran":false,"tshark_data_ran":false,"message":"Analysis returned an unreadable result. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed."} {"case":"control","exit":0,"coverage":"complete","capinfos_data_ran":true,"tshark_data_ran":true} ``` ## Typed outcome or recovery expected A non-retryable limiter configuration/capability refusal naming the selected limiter and its environment variable. Preserve the existing actionable refusals for relative/missing paths and successful analysis with real prlimit. ## Analysis or suspected cause Source-derived trace: `src/cli/pcapCommands.ts` registers the public command through `PcapAnalysisService`, which validates the request and calls `PcapProvider`. Its client phase resolves, fingerprints and version-probes both selected Wireshark fixtures successfully. In `PcapProvider.executeAdmitted`, native-bound preparation precedes snapshot acquisition (`src/pcap/PcapProvider.ts:784-789`). The limiter admission checks neither regular-file type nor whether the executable can act as util-linux prlimit. `PcapCommand` subsequently launches the limiter with the capinfos command appended. The directory fails at spawn and is attributed to capinfos; `/usr/bin/true` returns zero without starting capinfos, so the metadata parser receives empty output. These causal statements come from source inspection; the public outcomes and fixture markers above were executed. ## Additional context One defect is reported: unusable limiter admission and its resulting error attribution. The directory and non-limiter cases share the configuration boundary and restoration criteria. Preserving a producer-contradiction reason after otherwise valid tool admission is a separate requirement. NOT_ENOUGH_INFO: last known good revision and published-package reproduction. ## References - [PR #2507](https://github.com/morluto/rea/pull/2507) established actionable host-tool and limiter guidance; this report covers selections that escape its limiter refusal path. - [Issue #6433](https://github.com/morluto/rea/issues/6433) is completed for directory-selected tshark/capinfos identity reads. [PR #6784](https://github.com/morluto/rea/pull/6784) was closed because main already handled that case. Neither closure covers the separate limiter selection used here. - [Design #3403](https://github.com/morluto/rea/issues/3403) discusses sharing TShark selection ownership; its architectural acceptance criteria differ from this concrete limiter refusal. [PR #6395](https://github.com/morluto/rea/pull/6395) concerns sigrok limiter attribution, a separate provider. Open/closed issue and PR searches found no current exact duplicate for this pcap limiter case. ## Restoration check Rerun the program: directory selection must fail with limiter-specific capability guidance before capture acquisition; `/usr/bin/true` must yield a limiter-specific configuration failure rather than `unreadable_output`. Neither failing selection should run the data commands or blame capinfos installation. Relative and missing paths must retain their limiter-specific refusals. `/usr/bin/prlimit` must still run both data fixtures and return complete zero-packet Evidence. These are proposed acceptance checks; no REA fix was made or tested. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A bounded Linux configuration failure is routed to the wrong recovery action; the non-limiter selection is also misclassified as an execution/output failure without details, impairing typed caller recovery. No false success or capture corruption was observed. - Workaround status: available - Workaround basis: Select real util-linux prlimit through its absolute path; the `/usr/bin/prlimit` control restored the same fixture workflow in both independent runs.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4327
No description provided.