Skip to content

[security][tools] Bash の閉じ込めの検査が、.. と ~ だけの語を確かめず、dd の of= を書き込みとして認識しない(#613 の調査で発見) #628

Closed

Description

@Kewton

背景

#613 の着手前調査(H-09、2026-10-08)で、#613 の範囲の外として見つけた、Bash の閉じ込めの検査の既存の見逃しです。#613 の merge 前レビュー(H-10)で tar -C の形を追記しました。着手前調査(H-11、2026-10-09)で、#613 の merge 後の develop(2a078deb)の値を確かめ、範囲と設計を決めました。どの調査も、判定の関数を tempdir の fixture に対して呼び、結果を見ただけです。shell は起動しておらず、ワークスペースの外の実際の読み書きは試していません。

範囲(H-11 で決定):この Issue は ..・~ だけの語と、dd of= を扱います。tar -C sub … のように、オプションで作業ディレクトリを変える形は、別の Issue に分けます(下の「分けたもの」)。ただし tar -C ..・git -C .. のように値が ..・~ の形は、この Issue の 1 で止まります。

問題

R:2 段目の閉じ込めの判定、A:書き込みと認識、W:書き込み側の拒否、P:保護 path の書き込みの検出、V:bash:verify の自動許可。

1. .. と ~ だけの語

ls ..・ls ~・cat ~ が R=0 です。ワークスペースの親ディレクトリや home の一覧を読めます。.. と ~ で始まる語は、/ を含まない語の検査(#613 の設計 2)の対象から外していて、/ を含まないので字どおりのパスの候補にもならないためです。/ を含む形(ls ../、cat ../x、ls ~/、cat ~/x、ls sub/..)は、今も R=1 です。

入力(例) develop の値 期待
ls ..、ls -la ..、du -sh ..、find .. -name x、grep -r foo ..、cat .. R=0・V=1 R=1
ls '..'(引用しても親ディレクトリ) R=0・V=1 R=1
ls ~、cat ~、ls ~root、ls ~+、ls ~- R=0・V=1 R=1
make PREFIX=~、cat --file=~、cat --file=..(= の右側) R=0・V=1 R=1
tar -C .. -cf - x、git -C .. status R=0・V=1 R=1
cd ..、cd ~、cd ~root && ls R=1・W=1 変わらない

2. dd of=… が書き込みとして認識されない

dd if=in of=out が A=0・V=1 です。dd の of= は書き込み先なのに書き込みとして認識されず、bash:verify で自動許可されます。保護 path への書き込みも検出できません(H-11 で確認)。

入力(例) develop の値 期待
dd if=in of=out(どちらも中) A=0・V=1 A=1・V=0(R・W は 0 のまま)
dd で of= に保護ファイル(conv=notrunc 付き、引用付きも) A=0・P=0・V=1 A=1・P=1・V=0
保護ファイルのあるディレクトリへ cd して dd … of= にそのファイル A=0・P=0 A=1・P=1
dd of= に外向き symlink、../x、~/f、外の絶対パス R=1・A=0・W=0・V=1 R=1・A=1・W=1・V=0
dd if=in of=/dev/null A=0・V=1 A=1・W=0・V=0
dd if=in(of= なし)、dd if=in > out 今の値 変わらない

外向き symlink を通る形が R=1 なのは、= の右側を読み取りの候補として確かめる既存の検査(#603)によるもので、書き込み側では認識していません。

影響

  • 1:ワークスペースの外の一覧(ファイル名)を読めます。
  • 2:書き込みのコマンドが自動許可の対象になり、保護 path の検出から漏れます。

設計(決定)

  • 1. .. と ~ だけの語を、字どおりのパスの候補にする。 先頭の代入(NAME=value)より後の語が .. ちょうど、または ~ で始まり / を含まないとき、その語を字どおりの読み取りの候補にします。既存の字どおりのパスの検査が .. と ~ を拒否します。= の右側(make PREFIX=~、cat --file=..)も同じです。/ を含む形は今の扱いのままです。
    • echo の区切り(echo ~、echo ..)は、今の「echo で $HOME を表示する」例外と揃えて、候補にしません。
    • 先頭の代入(X=~ cargo test)は、今どおり変数として扱い、候補にしません。
    • cd .. の扱いとの関係:行き先の ..・~ は、今も書き込み側で拒否されています(W=1)。変えません。cd sub && ls .. は、bash では中に留まりますが、作業ディレクトリの候補には root も残るので、拒否されます。cd sub && cat ../f(/ を含む)が今も R=1 なのと同じ扱いです(.. の成分は、作業ディレクトリによらず拒否する方針)。
  • 2. dd の of= を書き込み先として認識する。 dd の引数のうち of= で始まり値が空でないものを、操作名 dd の書き込み先にします。書き込みの閉じ込め、作業ディレクトリの候補、保護 path の検出、自動許可の判定に、ほかの書き込み先と同じく渡ります。of=/dev/null は、出力のリダイレクトや tee と同じく許可します。
  • 3. corpus の表を更新する。 [security][tools] Bash の 2 段目の path 検査が、$・glob・動的な値で静的な相対パスや展開先を確かめず、ワークスペース外を読める(#571 を統合) #582 の decision の表の allow-dd-nonpath の行(dd で中から中へ書く形)は A=0・V=1 を期待しています。これを A=1・V=0 に改め、上の表の形の行を足します。厳しくなる向きの変更で、表の他の行の期待は変えません。
  • event の名前や schema は変えません。拒否は既存の理由の文を使います。

誤拒否の見積り

  • 記録(dev-reports と workspace/management の jsonl から取った agent の Bash コマンド、重複なし 436 件):..・~ だけの語、dd、tar、-C を含むものは 0 件です。試作で 436 件の値は 1 件も変わりませんでした。
  • 参考(このリポジトリで動いた Claude Code の Bash コマンド、重複なし約 5.9 万件。agent の記録とは別の母集団):.. だけの語は 93 件(多くはコメントや文字列の中で、実際のコマンドの引数は ls .. | grep …・cd .. など)、~ だけの語は ls -A ~ などです。どちらもワークスペースの外を読む形で、拒否するのが閉じ込めの約束どおりです。dd は 5 件で、of= を中に書く形はありません。
  • 新しく拒否される形と、書き直し方:
    • cd sub && ls ..:root から ls で書けば通ります。
    • ls "~"(~ という名前のファイル):字句の読み方が引用を区別しないため、拒否されます。先頭に ./ を付ければ通ります。
    • make PREFIX=~ のような、home を値に渡す形:閉じ込めの外を指すので、拒否のままとします。
  • 自動許可から外れる形:dd … of=…(中に書く形も)。書き込みのコマンドなので、自動許可の対象でないのが正しい扱いです。

受け入れ条件

対象ファイル

  • src/tools/bash/read_guard.rs
  • src/tools/bash_write_guard.rs
  • tests/corpus/apps/issue582-bash-read-candidates/fixtures/decision-cases.jsonl
  • tests/issue582_bash_read_candidates.rs
  • tests/issue628_bash_parent_home_dd.rs

参照

  • 着手前調査の記録:ローカルの workspace/tmp/1007/wave1/results/H-11/report.md(試作の差分は SSD の wave1-20261007/h11/proto.diff)
  • 発見の記録:ローカルの workspace/tmp/1007/wave1/results/H-09/report.md の「範囲外で見つけたもの」、H-10/report.md の「後続の候補 F2」
  • src/tools/bash/read_guard.rs の単体試験は、同じ corpus の表を読みます。表の allow-dd-nonpath の行を改めないと、その試験と tests/issue582_bash_read_candidates.rs の表の試験が落ちます(H-11 の試作で確認)。

根拠(develop 2a078deb)

  • ..・~ を / のない語の検査から外す:src/tools/bash/read_guard.rs:174-176(is_relative_target)
  • / のない語は字どおりのパスの候補にならない:src/tools/bash/read_guard.rs:243-271(push_static)、src/tools/bash/path_tokens.rs:376-394(is_literal_path は / を要する)
  • echo の例外:src/tools/bash/read_guard.rs:102-111
  • 書き込み先の一覧に dd がない:src/tools/bash_write_guard.rs:447-541(collect_program_targets)
  • /dev/null の例外:src/tools/bash_write_guard.rs:137-141
  • 自動許可は「書き込みと認識しない」ことを条件にする:src/tools/allow_policy.rs:129-131
  • corpus の表の行:tests/corpus/apps/issue582-bash-read-candidates/fixtures/decision-cases.jsonl:42

関連(参考)

Activity

  1. Kewton commented on Oct 9, 2026

    @Kewton
    OwnerAuthor

    2026-10-09 追記:#613 の merge 前レビュー(H-10)で、同じ種類の見逃しをもう 1 つ確かめました。tar -C sub -cf - lf2・tar -cf - -C sub lf2 が R=0・V=1 です(sub の中の lf2 は外のファイルを指す symlink)。オプションで作業ディレクトリを変える形で、git -C と同じ種類です。#613 の前の develop からあります。この Issue で、..・~・dd of= と一緒に扱います(対象ファイルは着手前調査で確かめます)。

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

    @Kewton
    OwnerAuthor

    PR #642 で develop に merge しました(merge commit b506fbd、CI・acceptance・Next.js domain oracles success)。.. と ~ だけの語を字どおりのパスの候補にし、dd の of= を書き込み先として認識するようにしました。merge 前レビュー(H-13)は blocker 0。-C の形は #637、brace の展開から出る ~ は #641 で扱います。

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