Skip to content

fix(ap-mode): verify pid identity before signalling during teardown - #6203

Closed
0xacee wants to merge 1 commit into
Osmantic:public-betafrom
0xacee:fix/ap-mode-stale-pid
Closed

0xacee wants to merge 1 commit into
Osmantic:public-betafrom
0xacee:fix/ap-mode-stale-pid

Conversation

@0xacee

@0xacee 0xacee commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Summary

ap-mode.sh down runs as root (require_root) and signalled whatever PID its pidfiles named:

kill "$(cat "${HOSTAPD_PID}")" 2>/dev/null || true

Pidfiles outlive their daemons. After a hostapd/dnsmasq crash or an unclean reboot, the pidfile can name a PID since recycled by an unrelated process — a bare kill then signals an innocent process as root. The adjacent pkill -f fallback already required the conf path in the process cmdline; the pidfile path skipped any identity check.

New kill_pidfile helper verifies /proc/<pid>/comm matches the daemon name and the conf path appears in /proc/<pid>/cmdline before signalling — the same identity the pkill -f fallback uses. Stale, dead, and malformed pidfiles are still removed, and a skip is logged so an operator can see the pidfile lied.

Why this matters

  • cmd_down is invoked as root from the AP-mode systemd unit and ods flows; a recycled PID means kill lands on an arbitrary system process.
  • The failure is silent: today there is no log when the pidfile points at the wrong process.

Regression coverage

ods/tests/test-ap-mode-stale-pid.sh (10 checks) drives the real cmd_down end-to-end under stubbed pkill/iptables/ip/nmcli:

  • pidfile naming a live recycled PID (sleep) → process survives, pidfile removed, skip logged
  • pidfile naming a real matching daemon (a tail copy named hostapd/dnsmasq so /proc/<pid>/comm matches) → killed
  • dead-PID and garbage pidfiles → handled without error, removed
  • static: no bare kill "$(cat …)" remains; both daemons route through kill_pidfile

Validation

  • Fix branch: 10/10 green.
  • Clean upstream/public-beta: the recycled-PID scenario kills the innocent sleep — defect reproduced; static checks fail as expected.
  • bash -n + shellcheck -S error clean; existing tests/test-ap-mode.sh still passes.

Overlap check

ap-mode has several open PRs — #4273/#2406/#2791 (atomic state writes), #3686 (pipefail capability match), #3620 (activation rollback), #5774 (bounded iptables teardown), #6086/#5623 (netmask→prefix), #3829 (exec bits), #3119 (state file checks). None touch the pidfile kill path; this scope is disjoint.

Notes / limitations

  • Identity check is Linux /proc-based, matching the script's existing require_linux gate.
  • The pkill -f fallback is retained unchanged — it catches daemons that lost their pidfile entirely.

cmd_down runs as root and signalled whatever PID a stale pidfile named.
After a crash or reboot that PID can be recycled by an unrelated process,
so a bare kill hit an innocent process. Verify /proc/<pid>/comm matches
the daemon name and the conf path appears in cmdline — the same identity
the pkill fallback already required — before signalling. Stale, dead, and
malformed pidfiles are still cleaned up.
@0xacee 0xacee closed this Oct 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant