Bashでリダイレクトされた入力を使用してファイルに書き込む方法は何ですか?これを防ぐことはできますか?

Bashでリダイレクトされた入力を使用してファイルに書き込む方法は何ですか?これを防ぐことはできますか?

私はbashファイルのリダイレクトをかなりうまく処理していると思います。一般的に「猫の無駄な使用「しかし、スクリプトで予期しない動作が発生しましたが、なぜこれが起こるのかを知りたいです。

bashスクリプトで次のように実行します。

somecommand < file1 > file2

私の期待は、file1が安全で読み取り専用で開くことです。実際にfile1を上書きできることがわかりました。どのように/なぜこれが起こり、それに頼らずに解決することができますかcat

私が想像するように動作している場合(プロセスは直接rwファイル記述子で終わるのですか?)このようにファイルをリダイレクトすることは危険であると見なされるべきだと思われますが、以前はこれを見たことがありません。

私の場合にいくつかの詳細を追加するには、問題のコマンドは次のとおりです。標準操作手順、バックグラウンドでいくつかのGPG操作を実行します。 GPGパスワードプロンプトは、入力に使用されたファイルに上書きされることがあります。私が使用する完全なコマンドは次のとおりです。

sops --input-type json --output-type json -d /dev/stdin < ./secrets/file.json > ./secrets/file-decrypted.json

私はそれ以降に切り替えて、cat file1 | sops.. > file2すべてが期待どおりに機能しました。私はこれが「猫に役に立たない使用」と言ったでしょう。しかし、それはもはやそれほど役に立たないようです!


最初のメッセージが表示されたら、gpg-agentが実行されていないようです。

ベストアンサー1

これは、Linux(およびCygwinですが、通常他のシステムではない)で/dev/stdin(実質的に)実装されている方法によるものです。/proc/self/fd/0

Linuxで開く/dev/stdinことは、実行するのとは異なりますdup(0)。 fd 0で開いたファイルと同じファイルを再度開くだけです。共有されませんファイル説明を開くfd 0参照(読み取り専用モードを使用)、完全に無関係な新しい値を取得するファイル説明を開く、モードはで指定されたものと同じですopen()

したがって、読み取り+書き込みモードでsops -d /dev/stdin開き、fd 0が/dev/stdin読み取り専用で開くと、読み取り+書き込みモードで開きます。/some/file/some/file

実際にcmd /dev/stdin < filecmd file < file。これは/dev/stdinシンボリックリンクにすぎないことがわかりますfile

/tmp$ namei -l /dev/stdin < file
f: /dev/stdin
drwxr-xr-x root     root     /
drwxr-xr-x root     root     dev
lrwxrwxrwx root     root     stdin -> /proc/self/fd/0
drwxr-xr-x root     root       /
dr-xr-xr-x root     root       proc
lrwxrwxrwx root     root       self -> 73569
dr-xr-xr-x stephane stephane     73569
dr-x------ stephane stephane   fd
lr-x------ stephane stephane   0 -> /tmp/file
drwxr-xr-x root     root         /
drwxrwxrwt root     root         tmp
-rw-r--r-- stephane stephane     file

状況がさらに悪化する可能性があります。 O_TRUNC で開くとファイルが切り捨てられます。 fd 0がパイプの読み取り端を指して書き込み/dev/stdin専用モードで開くと、パイプのもう一方の端が得られます。

ただし、以下を使用してください。

cat file | cmd /dev/stdin

パイプがすべての人に表示されるため、適用cmdを防ぎます。書き込み専用モードで開いても再び戻ることはできず、パイプの書き込み端にのみ到達し、読み取り終了の唯一のファイル記述子はstdinです。filecmdfilecmd

他のオペレーティングシステムではこの問題は発生しません。/dev/stdinこれを開くのはaを実行するのと同じであるためdup(0)、同じ結果が得られるからです。ファイル説明を開く互換性のないモードで開くと、open()システムコールが失敗します。


1技術的に@ user414777がコメントで指摘したように/proc/<pid>/fd/<fd>魔法のシンボリックリンクたとえば、通常のシンボリックリンクが行けない場所に移動できますが、それを開くと、パスチェックステップの後に通常のシンボリックリンクのように動作し、ターゲットファイルを開くだけです。

おすすめ記事