Skip to content

#637 [security][tools] Bash でオプションにより作業ディレクトリを変える形と、- で始まる pushd の行き先を検査する - #646

Merged
Kewton merged 3 commits into
developfrom
feature/issue-637-security-tools-bash-tar-c-git-c-pushd-613-635
Oct 10, 2026
Merged

Kewton merged 3 commits into
developfrom
feature/issue-637-security-tools-bash-tar-c-git-c-pushd-613-635

Conversation

@Kewton

@Kewton Kewton commented Oct 10, 2026

Copy link
Copy Markdown
Owner

概要

Bash の閉じ込めの検査に、既存の見逃しが 3 つありました(#613・#635 のレビューと、着手前調査 H-14 で発見)。

  1. オプションで作業ディレクトリを変える形:tar -C sub -cf - lf2、git -C sub log lf2、env -C sub cat lf2、sudo -D sub cat lf2 などは、作業ディレクトリの検査を通らず、その後の / のない相対パスが確かめられていませんでした。値のディレクトリの中に外向きの symlink があると、それを通して外を読めました。
  2. - で始まる pushd の行き先:pushd -- -s2 && cat lf7 で、-- の後の -s2 がスタックの番号として読み飛ばされていました。
  3. 拒否の理由の文:glob の行き先(cd 's2*' && cat lf4)の拒否で、理由の path が行き先ではなく、後のコマンドの名前(cat)になっていました。

この PR は、Issue 本文の設計 1〜3 どおりに直します。

変更(5 ファイル、+584/−11)

検証

  • commandmate verify の 15 ゲート:develop 88d5a0db を取り込んだ HEAD で 15/15 pass(b654b236、scope 5 本、違反 0)。
  • TMPDIR=/tmp cargo test --test issue637_bash_option_working_directory --test issue635_bash_glob_cd_destination --test issue568_bash_cwd_write_targets --test issue582_bash_read_candidates --test issue641_bash_brace_home(CI と同じ条件を作るため):exit 0、7 passed・0 failed、28 passed・0 failed、7 passed・0 failed、6 passed・0 failed、4 passed・0 failed(issue568・issue582・issue635・issue637・issue641 の順)。
  • 二点測定(develop b506fbdf の src に、この PR のテストを足した)
    • 新しい形のテスト 4 本だけが FAIL した。
      • tar -C sub -cf - lf2 が拒否されない。
      • pushd -- -s2 && cat lf7 が拒否されない。
      • その書き込みの形が拒否されない。
      • cd 's2*' && cat lf4 の理由の path が cat になる。
    • 許可のままの形と、表に無いプログラムの扱いを確かめる 2 本は、develop でも pass した。
  • 変異テスト(cargo mutants --jobs 1、--in-diff、--lib と結合テスト 4 本)
    • 1 回目は 69 件:caught 50・missed 3・timeout 10・unviable 6。
    • 許可が増える向きの missed は 1 件だった。候補の上限の比較 > を == にしても通った(候補の数が 64 を踏まずに超えると、上限の印が立たない)。テストを足して直し、2 回目で caught になった。
    • 残る missed 2 件は、どちらも厳しくする向き。
      • 上限の比較の > を >= にする変異:ちょうど 64 で印が立つだけ。
      • - 1 文字の語をオプションとして読み進める変異:-C を余分に拾うだけ。
    • timeout 10 件は、走査の index の変異が無限ループになったもので、検出扱い。
  • merge 前レビュー(H-16):merge 可、blocker 0。

意図した誤拒否

  • 足した候補は、cd と同じく後の segment にも残る。git -C sub status; cat lf2 は拒否される。root に lf2 は無いが、sub/lf2 が外向き symlink のため。本文の見積りで、記録の 436 件のうち新しく拒否されるのはこの型だけ。
  • 表のプログラムの名前の語はどこにあっても走査するので、echo tar -C sub; cat lf2 も拒否される。どちらも、足した候補の先に外向き symlink があるときだけ起きる。
  • git -C sub status、make -C sub test、tar -C sub -cf - f、tar -C sub -xf a.tar、env -C sub cat f、git commit -C HEAD、npm --prefix sub test、cargo -C sub test は許可のまま。grep -C 3、diff -C 3、git log -C sub も変わらない。

この PR では直していない既存の穴(どれも #637 の前から R=0 で、この PR で緩んではいない)

Refs #637

🤖 Generated with Claude Code

Kewton and others added 3 commits October 9, 2026 20:44
Read a table program's working-directory option value (tar -C, git -C,
make -C, env -C, sudo -D, ninja/go/cargo/pnpm/poetry/yarn/bun/npm/uv/just/
patch, and the tar/gmake aliases) as a working-directory candidate, exactly
like a cd destination, through the new leaf module
src/tools/bash_write_guard/option_directory.rs. A glob/brace or otherwise
unreadable value raises the #635 glob-destination mark so the relative
words after it are still refused. Read the word after `pushd --` as a
destination even when it starts with `+`/`-`, and name the destination word
(option value included) as the undecidable refusal path instead of the
following command word.

判断: option values are read from each segment's raw words rather than the
resolved program, because env -C / sudo -D never resolve to a Program and a
table program can sit behind a prefix (`nice env -C DIR`).
判断: an option value that cannot be read from its spelling (a glob or
brace, `$`, a backtick, `~`, a `..` component, or an empty value) raises
the #635 mark and adds no candidate, per the issue's design; the mark only
ever adds refusals.
本文に無い指摘: `find -execdir` and the options of unlisted programs stay out
of scope and keep their existing handling, as the module doc records.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Add working_directory_caps_an_option_growth_that_skips_the_bound, the
option-value analogue of working_directory_caps_a_growth_that_skips_the_bound
(#635): forty `git -C sub` values add one candidate each, then a single
`git -C r` doubles the set past MAX_CANDIDATES without landing on it, so the
inspection must still be undecidable. This catches the `>` → `==` mutation in
collect_option_directories' cap check, which would leave the mark clear and
allow more. Test-only; no production decision changes.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…issue-637-security-tools-bash-tar-c-git-c-pushd-613-635
@Kewton
Kewton merged commit c98bdc7 into develop Oct 10, 2026
5 checks passed
@Kewton
Kewton deleted the feature/issue-637-security-tools-bash-tar-c-git-c-pushd-613-635 branch October 10, 2026 06:36
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