2016-04-19 21 views
5

UNIX環境での高度なプログラミングによると、openat()は、TOCTTOU(time-of-use-time-of-use)エラーを回避する方法を提供します。TOCTTOUのエラーをopenatで回避する方法はありますか?

私は方法について混乱しています。私の知る限り、openatはファイル記述子に依存しているので、このファイル記述子を最初に開く必要があります。これはTOCTTOUを紹介していますか?

答えて

3

openat()のためのPOSIX仕様は言う:

int openat(intfd, const char *path, intoflag, ...);

[定期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ビットが設定されている場合、返されたファイル記述子は拡張属性へのアクセスを提供します。この機能はここでは標準化されていません。

+0

ありがとうございます! – Sherwin

+0

@Jonathan Leffler、「間違ったディレクトリにファイルを作成することにあなたのプログラムを混乱させる」とはどういう意味ですか?私たちに例を示してください。 – cong

+0

それは複雑です。私が過ごすとは思っていない合理的な例を作るのに時間と労力がかかります。基本的には、あなたのプログラムが '/ some/where'ディレクトリを作成し、' open( "/ some/where/filename"、...)でファイルを置こうとしますが、攻撃者が元の '/ some/where'を削除して独自の代替プログラムを作成すると、プログラムはあなたのものではなくそのディレクトリにファイルを作成します。弱者の攻撃者は元の '/ some/where'を元に戻すこともでき、パスワードや重要な情報を取得した可能性があります。 'openat()'を使用することは慎重に避けます。 –

1

ファイル記述子を使用すると、すべての操作が正確に同じファイルにあることが保証されます。代わりにファイル名を使用した場合、filenameが参照するファイルは、他のプロセスによって実行される操作のために変更される可能性があります。

+0

これは 'openat()'のポイントが間違っていると思います。ファイルの記述子ではないファイル記述子の意味については言及していません。 –

+0

"ファイル"とは単にファイル記述子が何を参照しているかを意味し、バイトストリームの意味でのファイルは意味しません。私は簡単な質問に簡単な答えを出そうとしています - なぜファイル名ではなくファイル記述子を取るとTOCTOUの問題に影響するのですか?あなたの答えに感謝します。 –

+0

あなたの答えは簡単ですが、前の文章を読むまで、答えの最初の文を理解できませんでした。とにかく、ありがとう。 – Sherwin

関連する問題