inotifywaitの潜在的な回避策はNULで区切られた出力を生成しません。

inotifywaitの潜在的な回避策はNULで区切られた出力を生成しません。

現在、以下を使用するbashスクリプトを作成しています。inotifywaitユーザーが提供したファイルとディレクトリのリストに対して特定のタスクを実行します。

それが私の関心を集めました。多くのシェルツールとは異なり、inotifywait使用できません\0注入攻撃の可能性特別に設計された法的ファイル名(改行を含む)があります。

私のスクリプトが不要な脆弱性を引き起こさないように、この問題を解決したいと思います。私がする方法は次のとおりです。

  • inotifywaitウォッチに渡されたすべてのファイル/パスの末尾のバックスラッシュが削除されていることを確認してください。
  • 次のように出力を生成するように inotifywait出力形式を指定します。--format "%e %w%f//"
    • <EVENT LIST> <FILE PATH>//
  • 行末で見つかったinotifywaitすべての項目を sed にパイプ出力します。//\0
  • Bashwhile readループを使用して\0区切られたレコードを読み取る
  • これは、最初のレコード以降のすべての後続レコードに追加の先行改行文字があることを意味します。これは剥がれています。
  • その後、各レコードは最初のスペースで分割できます。スペースがイベントリスト(inotifywaitによってコンマで区切られている)になる前、スペースがイベントに関連付けられているフルパス名の後
#!/bin/bash

shopt -s extglob
watchlist=("${@}")

# Remove trailing slashes from any watchlist elements
watchlist=("${watchlist[@]%%+(/)}")

# Reduce multiple consecutive slashes to singles as per @meuh
watchlist=("${watchlist[@]//+(\/)/\/}")

printf -vnewline "\n"

inotifywait -qrm "${watchlist[@]}" --format "%e %w%f//" | \
    sed -u 's%//$%\x00%' | \
    while IFS= read -r -d '' line; do
        line="${line#${newline}}"
        events="${line%% *}"
        filepath="${line#* }"
        printf "events=%s\nfilepath=%q\n" "$events" "$filepath"
    done

私が知っている限り、これはスペース、改行、引用符などの興味深い文字を含むファイル/パス名を処理します。しかし、これはやや村のパッチワークのようです。

この質問の目的に応じて、配列${watchlist[]}はコマンドライン引数からコピーされましたが、配列はさまざまな方法で構成することができ、「興味深い」文字を含めることができます。

  1. これを破るための悪意のある道はありますか?特定のイベントについて$events、および変数の内容が正しくない場合でも同じですか?$filepath

  2. これが防水であれば、よりきれいな方法はありますか?

私は簡単に書くことができることを知っています。inotify_add_watch()この問題を解決するには、Friendプログラムを呼び出します。しかし、今は他の依存関係のためにbashで作業しています。


私はこれをここに投稿するのか、codereview.SEにもメインso.SEに投稿するのかについて紛争を経験しました。

答え1

持つクロスNULで区切られた出力はサポートされており、次のように使用できます。

#!/bin/bash

shopt -s extglob
watchlist=("${@}")

# Remove trailing slashes from any watchlist elements
watchlist=("${watchlist[@]%%+(/)}")

printf -vnewline "\n"

inotifywait -qrm "${watchlist[@]}" --format "%e %w%f%0" | \
while IFS= read -r -d '' line; do
    events="${line%% *}"
    filepath="${line#* }"
    printf "events=%s\nfilepath=%q\n" "$events" "$filepath"
done

--formatが使用されている場合、このバージョンはデフォルトで改行を追加しません。

答え2

watchlist交換するにはクリーンアップが必要です。次の名前のディレクトリを検討してください(ここでは改行文字はどこにあります)。///\nabc\n

$ mkdir t
$ mkdir t/$'\nabc'
$ touch t/$'\nabc'/x

ディレクトリを見ると、行のt//$'\nabc'末尾に偽の出力が表示されます。//

$ inotifywait -m -r t//$'\nabc' --format "%e %w%f//" 
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
OPEN t//
abc/x//
ATTRIB t//
abc/x//
CLOSE_WRITE,CLOSE t//
abc/x//

入手する-c代わりに参考にしてください。--formatデータセットスタイル出力はファイル名を改行で二重引用符で囲みましたが、解析するのはより困難です。私の場合は、上記の例のコアダンプです。

-c合計出力例touch t/$'new\nfile':

t/,CREATE,"new
file"

関連情報