Skip to content

[security][tools] Bash でオプションにより作業ディレクトリを変える形(tar -C・git -C など)と、- で始まる pushd の行き先が検査されない(#613・#635 のレビューで発見) #637

Closed

Description

@Kewton

背景

#613 の merge 前レビュー(H-10)、#628 と #635 の着手前調査(H-11)、#635 の merge 前レビュー(H-12)で見つけた、Bash の閉じ込めの検査の既存の見逃しをまとめた Issue です(2026-10-09、利用者承認で起票)。着手前調査(H-14、2026-10-09)で、#635 と #628 の merge 後の develop(b506fbdf)でも同じ値であることを確かめ、設計を決めました。元の本文の 4(引用した字どおりの括弧の行き先の誤拒否)は、誤拒否を減らす変更で設計の幅が大きいため、別の Issue に分けます(「後続の候補」)。どの調査も、判定の関数を tempdir の fixture に対して呼び、結果を見ただけです。shell は、外の読み書きを伴わない pushd と echo を、作業用の一時ディレクトリで確かめただけです。

問題

R:2 段目の閉じ込めの判定、A:書き込みと認識、W:書き込み側の拒否、V:bash:verify の自動許可。fixture:ワークスペースの中の sub は普通のディレクトリで、その中の lf2 は外のファイルを指す symlink。-s2 も普通のディレクトリで、中に外向きの lf7 があります。

1. オプションで作業ディレクトリを変える形

プログラムのオプションで作業ディレクトリを変えると、作業ディレクトリの検査を通らず、その後の / のない相対パスが確かめられません。

入力(例) develop の値 期待
tar -C sub -cf - lf2、tar -cf - -C sub lf2、tar -Csub -cf - lf2、tar --directory=sub -cf - lf2、tar --directory sub -cf - lf2、tar -xf a.tar -C sub lf2 R=0・V=1 R=1
git -C sub log lf2、git -C sub -C deep log lf3、make -C sub lf2、make --directory=sub lf2 R=0・V=1 R=1
env -C sub cat lf2、env --chdir=sub cat lf2、nice env -C sub cat lf2 R=0・V=1 R=1
sudo -D sub cat lf2、sudo --chdir=sub cat lf2 R=0 R=1
ninja -C sub lf2、pnpm -C sub exec cat lf2、yarn --cwd sub cat lf2、npm --prefix sub exec cat lf2、go -C sub run lf2、uv --directory sub run cat lf2、poetry -C sub run cat lf2、just -d sub cat lf2、cargo -C sub run lf2、patch -d sub lf2 < x.patch R=0 R=1
tar -C s2* -cf - lf4、git -C s? log lf4、make -C {s2,x} lf4(値が glob・brace) R=0・V=1 R=1
cd sub && tar -C deep -cf - lf3、tar -C sub -cf - deep/lf3 R=0 R=1

比較:値が / を含む形(git -C sub/link status)、値そのものが外向き symlink の形(tar -C linked-outside …)、値が ..・~・$ の形は、今も R=1 です。

2. - で始まる pushd の行き先

pushd -- -s2 && cat lf7・pushd -- -s* && cat lf7・pushd -n -- -s2 && cat lf7 は R=0、pushd -- -s2 && echo x > lf7 は A=1・W=0 です。同じ形の cd -- -s2 && cat lf7 は R=1 です。shell は -- の後の語を、- で始まっても行き先として扱います(作業用の一時ディレクトリで sh -c 'pushd -- -s2' が -s2 に移ることと、pushd -- -1 が番号ではなく -1 という名前のディレクトリを探すことを確かめた)。

3. 拒否の理由の文

引用した glob の行き先(cd 's2*' && cat lf4)、引用した括弧の行き先(cd 's[2]' && cat lf5、cd "s[2]" && ls)の拒否で、理由の path が行き先ではなく後のコマンドの名前(cat・ls)になります。拒否はされますが、案内が分かりにくい形です。

原因

  • 作業ディレクトリの検査は、cd・pushd・popd の行き先だけを候補にします。プログラムのオプションの値は見ません。
  • env -C・sudo -D は、前置きの解決で「決められない」になり、書き込み側では拒否されますが、作業ディレクトリの検査はその segment を読み飛ばします。読み取りの形は検査されません。
  • pushd の位置引数は、-- を外した後で +・- で始まるかを見て、スタックの番号として読み飛ばします。-- があったかを見ていません。
  • 「決められない」の拒否の理由は、行き先の語ではなく、後に残った最初の相対の語を使います。

設計(決定)

  • 1. 作業ディレクトリを変えるオプションの表を、新しい leaf module に置く。 各 segment の語を見て、表のプログラム(語の basename が一致するもの。前置きの nice・timeout・command・sudo・env の後も含む)のオプションの値を取り出し、cd の行き先と同じ扱いで作業ディレクトリの候補に足し、行き先として閉じ込めを確かめます(extend と targets)。候補は足すだけで、置き換えません([security][tools] Bash の書き込み検査が同じコマンドの cd・pushd の後の cwd を追わず、symlink を通ってワークスペース外へ書き込める(#509 の調査で発見) #568 の設計)。
    • 表(プログラム:短いオプション/長いオプション):tar・gtar・bsdtar:-C/--directory。make・gmake:-C/--directory。git:-C(サブコマンドより前の全体のオプションだけ)。env:-C/--chdir。sudo:-D/--chdir。ninja・go・cargo:-C。pnpm:-C/--dir。poetry:-C/--directory。yarn・bun:--cwd。npm:--prefix。uv:--directory。just:-d/--working-directory。patch:-d/--directory。
    • 値の形:-C dir、-Cdir(短いオプションのまとまりの最後なら次の語、途中なら残り)、--directory=dir、--directory dir。-- の後は見ません。
    • 値が glob・brace の文字、$・バッククォート、~、.. の成分、空を含むときは、[security][tools] Bash の cd・pushd の行き先が 1 つに一致する glob だと作業ディレクトリが検査されず、外を読み書きできる(#613 のレビューで発見) #635 の glob の行き先の印を立て、その後の相対の語を「決められない」で拒否します。
    • 表に無いプログラム:今のまま(オプションの値を作業ディレクトリとしては見ない)。値が / を含む形や、値そのものが外向き symlink の形は、今どおり読み取りの検査で拒否されます。find -execdir は仕組みが違うので、この Issue の範囲の外です(「後続の候補」)。
    • for・関数の中の cd を「決められない」にする規則(has_cd)は、オプションの値には当てません(オプションの作業ディレクトリは、そのコマンドの中だけで、繰り返しても積み重ならないため)。
    • 足した候補は、cd と同じく後の segment にも残ります(足すだけの設計に合わせる)。
  • 2. pushd の -- の後の語は、番号の判定に回さない。 -- を含む pushd は、最初の位置引数を、+・- で始まっても行き先として扱います。pushd -1・pushd +0(-- なし)は今どおり読み飛ばします。
  • 3. 理由の path を行き先の語にする。 glob の行き先の印を立てたときに、その語(行き先、またはオプションの値)を Inspection に記録し、/ のない語の分岐の「決められない」の理由で、後の相対の語の代わりにその語を使います。event の名前や schema は変えません。
  • 試作(約 120 行。表の module 約 60 行、作業ディレクトリの検査の配線約 25 行、理由 1 行)で、上の表の形と 2 の形がすべて R=1 に、2 の書き込みの形が W=1 に、3 の理由の path が s2*・s[2] になりました。

誤拒否の見積り

  • 記録(dev-reports と workspace/management の jsonl から取った agent の Bash コマンド、重複なし 436 件):表のオプションを使う形と pushd -- は 0 件です。試作で 436 件の値は 1 件も変わりませんでした。
  • 参考(このリポジトリで動いた Claude Code の Bash コマンド、重複なし約 5.9 万件。正規表現で数えただけ):git -C 1,745 件(値の大半は $ を含むか絶対パスで、今も拒否されるか、足した候補を確かめるだけ)、tar -C・--directory 108 件、env -C 28 件、sudo -D 11 件、npm 系 54 件、cargo -C 8 件、make -C 1 件。どれも候補を足すだけなので、拒否になるのは、足した先に外向き symlink があるときか、値が glob・$ などのときだけです。値が glob の形は git -C 3 件・tar -C 2 件・env -C 1 件で、どれも試験の文書の中か、$ を含んで今も拒否される形でした。pushd -- は 0 件です。
  • 試作で新しく拒否された、ワークスペースの中に留まる形:git -C sub status; cat lf2(root に lf2 は無いが sub/lf2 が外向き symlink。足した候補が後の segment に残るため)の 1 件だけです。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、git -C sub -C deep status、npm --prefix sub test、git -C . status は変わりませんでした。

受け入れ条件

対象ファイル

  • src/tools/bash_write_guard/option_directory.rs
  • src/tools/bash_write_guard/working_directory.rs
  • src/tools/bash_write_guard.rs
  • src/tools/bash.rs
  • tests/issue637_bash_option_working_directory.rs

参照

根拠(develop b506fbdf)

  • 作業ディレクトリの候補は cd・pushd の行き先だけ:src/tools/bash_write_guard/working_directory.rs:180-241
  • 前置きが解決できない segment(env -C・sudo -D)は読み飛ばす:src/tools/bash_write_guard/working_directory.rs:196-201、前置きの判定は src/tools/bash_write_guard/command_prefix.rs:324・:459
  • pushd の番号の判定は -- を見ない:src/tools/bash_write_guard/working_directory.rs:224
  • 理由の path は後の最初の相対の語:src/tools/bash.rs:835-841

後続の候補(この Issue の範囲の外)

関連(参考)

Activity

  1. Kewton commented on Oct 9, 2026

    @Kewton
    OwnerAuthor

    2026-10-09:元の本文の 4(引用した字どおりの括弧の行き先の誤拒否)は、着手前調査(H-14)で設計が大きいと分かったため、#643 に分けました(利用者承認)。この Issue では 1〜3 を扱います。

  2. added a commit that references this issue on Oct 10, 2026
  3. Kewton commented on Oct 10, 2026

    @Kewton
    OwnerAuthor

    PR #646 で develop に merge しました(merge commit c98bdc7、CI・acceptance・Next.js domain oracles success)。オプションで作業ディレクトリを変える形(tar -C・git -C・make -C・env -C・sudo -D など)を表にして検査し、pushd -- の行き先と拒否の理由の語も直しました。merge 前レビュー(H-16)は blocker 0。綴りの変種は #645、引用した括弧の誤拒否は #643 で扱います。

  4. added a commit that references this issue on Oct 17, 2026
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