UNIX環境での高度なプログラミングによると、openat()
は、TOCTTOU(time-of-use-time-of-use)エラーを回避する方法を提供します。TOCTTOUのエラーをopenatで回避する方法はありますか?
私は方法について混乱しています。私の知る限り、openat
はファイル記述子に依存しているので、このファイル記述子を最初に開く必要があります。これはTOCTTOUを紹介していますか?
UNIX環境での高度なプログラミングによると、openat()
は、TOCTTOU(time-of-use-time-of-use)エラーを回避する方法を提供します。TOCTTOUのエラーをopenatで回避する方法はありますか?
私は方法について混乱しています。私の知る限り、openat
はファイル記述子に依存しているので、このファイル記述子を最初に開く必要があります。これはTOCTTOUを紹介していますか?
openat()
のためのPOSIX仕様は言う:
int openat(int
fd
, const char *
path
, int
oflag
, ...);
[定期
open()
に...長い熱弁...]
openat()
機能はpath
相対パスを指定する場合を除いopen()
関数と等価でなければなりません。この場合、開かれるファイルは、現在の作業ディレクトリの代わりにファイル記述子fd
に関連付けられたディレクトリに関連して決定されます。ファイルディスクリプタがO_SEARCH
なしで開かれた場合、ファイルディスクリプタの基礎となるディレクトリの現在のアクセス権を使用してディレクトリ検索が許可されているかどうかをチェックします。ファイルディスクリプタがO_SEARCH
で開かれた場合、関数はチェックを実行してはならない。
oflag
パラメータとオプションの第4のパラメータは、open()
のパラメータに正確に対応しています。openat()
がfd
パラメータに特別な値AT_FDCWD
を渡された場合、現在の作業ディレクトリが使用されなければならないと動作が
open()
への呼び出しと同一でなければなりません。
これは、あなたがファイルを配置したい場合、または特定のディレクトリへの相対的な、あなたは(おそらくO_SEARCH
オプションで)そのディレクトリにファイルディスクリプタを開き、それに相対パス名を指定することができることを意味しディレクトリにあるopenat()
システムコールのディレクトリ。
その他*at()
fstatat()
のような機能も同様です。
最初に、ファイルディスクリプタはディレクトリのファイルディスクリプタであることに注意してください。ディレクトリが(読み込みのために)開かれた時点で存在し、プロセスはそのディレクトリとその中のファイルにアクセスするためのアクセス許可を持っていました。さらに、このプロセスはディレクトリをオープンしているので、そのディレクトリへの最後の参照は、プロセスがディレクトリファイル記述子を閉じるまで消えません。マウントされたファイルシステム上にある場合、そのファイルシステムは、プロセスがディレクトリを開いているので、プログラムが終了するまでアンマウントできません。ディレクトリが(同じファイルシステム上で)移動されると、ファイルシステム内の現在の位置にあるそのディレクトリに関連してファイルが作成され続けます。
ここからはもっと推測的なことがあります - 私は正式にこれらの観測をテストしていません。
ディレクトリが削除されても、それに関連してファイルを作成できるように見えます。名前が単純な名前("new_file"
または"./new_file"
)の場合、それは問題ありません。名前のパスが多い場合("subdir/new_file"
)、すべてのサブディレクトリも削除されているため、ディレクトリが削除されているとファイルの作成またはオープンが失敗します。
もちろん、サブディレクトリを作成するにはmkdirat()
があります。
おそらく、ファイルシステムはこれ以降すべてをクリーンアップする必要がありますが、それはかなり複雑になる可能性があります。つまり、ファイル記述子が開いているが名前が削除されているディレクトリにファイルを作成できない可能性があります。しかし、同じディレクトリであると仮定するのではなく、これはもはや不可能であることがわかります。
どちらの場合でも、正しい*at()
機能を使用する上で慎重かつ一貫している限り、攻撃者はあなたのプログラムを間違ったディレクトリに作成することを混乱させることは困難です。
TOCTOU攻撃の1つのセットが削除されました。名前が変更された(または削除される)ディレクトリに依存する攻撃や、新しい名前(たとえば、他の場所へのシンボリックリンク)を使用する攻撃は、元のディレクトリに対してファイルが作成され続け、ディレクトリ。
openat()
のためのPOSIX仕様の根拠セクションは言う:
openat()
機能の目的は、条件をレースに触れることなく、現在の作業ディレクトリ以外のディレクトリにあるファイルを開くを有効にすることです。ファイルのパスの一部は、open()
への呼び出しと並行して変更することができ、その結果、不特定の動作が発生します。ターゲットディレクトリのファイル記述子を開き、openat()
関数を使用すると、開いているファイルが目的のディレクトリからの相対位置にあることが保証されます。実装によっては、openat()
関数を他の目的にも使用します。場合によっては、oflagパラメータにO_XATTR
ビットが設定されている場合、返されたファイル記述子は拡張属性へのアクセスを提供します。この機能はここでは標準化されていません。
ファイル記述子を使用すると、すべての操作が正確に同じファイルにあることが保証されます。代わりにファイル名を使用した場合、filenameが参照するファイルは、他のプロセスによって実行される操作のために変更される可能性があります。
これは 'openat()'のポイントが間違っていると思います。ファイルの記述子ではないファイル記述子の意味については言及していません。 –
"ファイル"とは単にファイル記述子が何を参照しているかを意味し、バイトストリームの意味でのファイルは意味しません。私は簡単な質問に簡単な答えを出そうとしています - なぜファイル名ではなくファイル記述子を取るとTOCTOUの問題に影響するのですか?あなたの答えに感謝します。 –
あなたの答えは簡単ですが、前の文章を読むまで、答えの最初の文を理解できませんでした。とにかく、ありがとう。 – Sherwin
ありがとうございます! – Sherwin
@Jonathan Leffler、「間違ったディレクトリにファイルを作成することにあなたのプログラムを混乱させる」とはどういう意味ですか?私たちに例を示してください。 – cong
それは複雑です。私が過ごすとは思っていない合理的な例を作るのに時間と労力がかかります。基本的には、あなたのプログラムが '/ some/where'ディレクトリを作成し、' open( "/ some/where/filename"、...)でファイルを置こうとしますが、攻撃者が元の '/ some/where'を削除して独自の代替プログラムを作成すると、プログラムはあなたのものではなくそのディレクトリにファイルを作成します。弱者の攻撃者は元の '/ some/where'を元に戻すこともでき、パスワードや重要な情報を取得した可能性があります。 'openat()'を使用することは慎重に避けます。 –