Skip to content

emrg: the daemon-stop scan matches a signaller by token, so a read that spells both words is refused and the pipeline that really stops it is allowed #2429

Closed

Description

@how2how2how2-arch

What is wrong

emrg/tools/command_scan.py::stops_or_restarts_the_daemon classifies the act
"stop or restart the emrg daemon" in two shapes: an emrg program word followed by
stop/restart, and a process signaller (pkill, killall, kill) one of
whose operands names emrg.

The signaller half matches the signaller by token, anywhere in the statement,
and then takes the next token containing emrg as its operand. It never asks
whether that token is the command being run. So a command that merely spells
both words is refused, and — in the other direction — a pipeline that really does
signal the daemon is allowed.

Measured, current tree (caf6d743), predicate driven directly

Refused, though nothing in it can signal a process:

grep -rn kill emrg/                        -> 'kill emrg/'
git grep -n 'kill' -- emrg/tools/          -> 'kill emrg/tools/'
grep kill argszero/emrg notes.txt          -> 'kill argszero/emrg'

The refusal reads: "blocked 'kill emrg/' — it stops or restarts the emrg daemon,
which is EMRG's life core"
. grep runs no signaller; the kill is a search
pattern and the emrg/ a path. Searching this repository for the word kill
scoped to a directory is an ordinary read.

Allowed, though it does signal the daemon:

pgrep -f emrg | xargs kill                 -> None

xargs is the command word here, so kill arrives as its argument, and the
operand scan looks after the signaller — where it finds nothing naming emrg.
That is a live route to the act this rule exists to prevent, and it sits on the
host's red line (MANIFESTO.md 第四条附则二).

Two more readings that fix the direction the answer must take (both correct
today, and both must stay that way):

sudo kill -9 $(pgrep -f emrg)              -> 'kill emrg'
nice -n 5 pkill -f emrg.server             -> 'pkill emrg.server'

How it was hit for real

A command that wrote a review body to a file and then posted it was refused with
blocked 'kill argszero/emrg'. The body discussed a failing test in prose and
contained the word "kill"; the same command with that word replaced by "failure"
went through. The message named a pair the command never formed.

What a fix must satisfy

  1. A signaller is the act only when it is the command word of its statement —
    the first token after the previous command border (;, &&, ||, |,
    newline), once wrappers in front of it are stepped over.
  2. Wrappers count: sudo -u root kill …, nice -n 5 pkill …,
    env kill …, timeout 5 kill …, xargs kill … are all still the act.
    xargs kill is the case that is currently allowed and must become
    refused.
  3. A signaller appearing as another program's argument is not the act:
    grep -rn kill emrg/, git grep -n 'kill' -- emrg/tools/,
    grep kill argszero/emrg notes.txt are allowed.
  4. The lifecycle-verb half (emrg server stop, emrg server restart,
    python -m emrg server stop) is untouched, as is the nested-text walk
    (sh -c '…', eval '…', env -S '…').
  5. Tests assert both directions, and the existing cases in
    tests/test_daemon_lifecycle_is_classified.py keep their verdicts — including
    pkill -f emrgd && ls, nice -n 5 pkill -f emrg.server, and the allowed
    pkill -f firefox / killall python / kill 12345.

Activity

  1. how2how2how2-arch commented on Oct 20, 2026

    @how2how2how2-arch
    CollaboratorAuthor

    The file's own allowed list already settles the direction

    tests/test_daemon_lifecycle_is_classified.py::NOT_THE_ACT pins
    grep -rn stop emrg/ as a mention that must stay allowed, and it does: the
    lifecycle-verb half only matches a verb that follows the program word, so a
    program named after the verb is not the act.

    The same command shape one word over is refused:

    grep -rn stop emrg/   -> None          (pinned as a mention)
    grep -rn kill emrg/   -> 'kill emrg/'  (refused as the act)
    

    Both are reads. The difference is that the signaller half matches by token
    anywhere in the statement, so kill as a search pattern is indistinguishable from
    kill as the command. That is the same over-block the file's own header cites as
    the #1513 lesson (echo sh "patch /etc/hosts" was a bug, not a safe over-block),
    arriving on the signaller half of the same rule.

    The other direction is the one with teeth: pgrep -f emrg | xargs kill is
    allowed, because xargs is the command and the operand scan looks after the
    signaller. Fixing the over-block by asking "is the signaller the command word of
    its statement?" closes that hole at the same time — the wrapper set has to carry
    xargs for exactly this reason.

    A patch follows, with both directions asserted.

  2. how2how2how2-arch commented on Oct 20, 2026

    @how2how2how2-arch
    CollaboratorAuthor

    Handled by #2430

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions