予想される動作は、結果が予測できないことです。 sendfile()
はアトミックではありません。それは、ファイルディスクリプタからread()
を、ソケットディスクリプタからwrite()
を呼び出す独自のループを書くことと事実上同じです。これが行われている間に他のプロセスがファイルに書き込むと、古いコンテンツと新しいコンテンツが混在します。これは主に便利な機能ですが、複数のシステムコールを必要とせず、アプリケーションバッファ間でのやりとりではなく、ファイルバッファとソケットバッファ間の直接コピーが可能であるため、はるかに効率的です。このため、脆弱性のウィンドウはread/write
ループを実行するよりも小さくなるはずですが、まだそこにあります。
この問題を回避するには、書き込みを行うプロセスとsendfile()
を呼び出すプロセスの間でファイルロックを使用する必要があります。だから、シーケンスは次のようになります。
lock the file
call sendfile()
unlock the file
と書き込み処理を行う必要があります。
lock the file
write to the file
unlock the file
EDIT:それはこの単純ではないようsendfile()
ソケットを結ぶため
は実際に、それは、見えますカーネルにコピーするのではなく、ファイルバッファキャッシュにバッファリングします。 sendfile()
はデータが送信されるのを待たず、返った後にファイルを変更すると送信される内容に影響を与える可能性があります。データがすべてアプリケーションレイヤの肯定応答で受信されたことを確認する必要があります。これらの詳細について説明している記事の抜粋については、Minimizing copies when writing large data to a socketを参照してください。
オープンファイルを削除しても、カーネルのファイルハンドル(およびプロセスの 'fd')は、ファイルが閉じられるまでファイルを「生きている」状態に保ちます。これはまた、 'fd'ハンドルに影響を与えずに開いているファイルを"移動 "できる理由です。編集によって引き起こされる競争条件については...まあ、それはレースです。 sendfileが編集後に動作する場合、編集されたバージョンで動作します。 – Myst
書き込みは、実行中のプログラム、OS、さらにはHDコントローラによってバッファされることがあります。おそらく3つの連続した全てであろう。ベスト・プラクティスは、マルチスレッド・プログラムで同じファイルを読み書きするときにアトミック・ガードを追加することです。 – usr2564301
@ usr2564301 HDコントローラはアプリケーションとは無関係です。 Linuxには統一バッファキャッシュがあり、すべてのプロセスが同じカーネルファイルバッファを使用します。 – Barmar