3

これに対するフォローアップの質問として、ファイルに追加して、存在しない場合は作成したい場合の@cafの回答から構築される別のアプローチを考えましたname

これが私が思いついたものです:

  1. file と同じファイルシステムのシステム一時ディレクトリに、モード 0700 の一時ディレクトリを作成しますname
  2. ファイルnameを読み取り専用で開きますO_CREATnameシンボリックリンクであればOSが追従する場合があります。一時ディレクトリに一時ファイルを作成し、 to fileによって作成された一時ファイルを試行するために

    使用します。mkstemprenamemkstempname

    ファイルnameを読み取り専用で開きますO_CREAT | O_EXCL
  3. name一時ディレクトリ内の一時的な名前へのハード リンクの作成を繰り返し試みます。link「リンクターゲットが存在します」(errno) 以外のエラーが原因で呼び出しが失敗した場合EEXISTは、終了します。(誰かがやってきて、 のファイルを削除したのかもしれません。誰nameにもわかりません)。
  4. (ハードリンク)で使用lstatします。temp_nameの場合S_ISLNK(lst.st_mode)、終了します。
  5. open temp_name書き込みおよび追加用 ( O_WRONLY | O_APPEND)。
  6. すべて書き出す。ファイル記述子を閉じます。
  7. unlinkハードリンク。
  8. 一時ディレクトリを削除します。

(ちなみに、これはすべて、私が取り組んでいるオープン ソース プロジェクトのものです。このアプローチの実装のソースは、ここで確認できます。)

この手順は、シンボリック リンク攻撃に対して安全ですか? たとえば、悪意のあるプロセスが、チェックname中に inode が通常のファイルを表していることを確認し、その inode を、ハード リンクが新しいシンボリック リンクを指しているシンボリック リンクにすることは可能ですか?lstattemp_name

悪意のあるプロセスが影響を与えることはできないと想定していますtemp_name

編集: linkターゲットを上書きしないため、「プレースホルダー」の一時ファイルを作成することは、私がやりたかったことではありません。その後、コードを更新し、上記の手順を更新しました。

EDIT2:この問題nameの影響を受けやすいとは思わないファイルが存在しない場合は、ステップ 2 の代替手順を使用してファイルを作成しています。

EDIT3:一時的な空の通常のファイルの名前を に変更するよりもさらに優れています。これには、リンクを解除してからname名前を変更する効果もあります。nameO_RDONLY | O_CREAT | O_EXCL

状態の POSIX 標準open:

O_EXCLO_CREATが設定され、pathシンボリック リンクに名前が付けられている場合、シンボリック リンクの内容に関係なく、open()失敗して に設定さerrnoれます。EEXIST

4

1 に答える 1

1

さて、ステップ 2 には 1 つの問題があります (「ファイルnameを読み取り専用で開きますO_CREAT。シンボリック リンクの場合、OS が追従する可能性がありますname。」)。これを完全に悪用できる場合、特権のないプロセスがtouchファイル システム内の基本的に任意のパスにアクセスできる可能性があります。これの結果には、次の再起動時にディスク チェックを強制すること ( をタッチすることによって/forcefsck) や、その他のより破壊的なことが含まれます。たとえば、Debian Lenny から Squeeze にアップグレードする場合、dbus とカーネル イメージの両方を同時にアップグレードする必要があります。これは、対応する各パッケージが互いに依存しているためです (新しい dbus は古いカーネルでは機能せず、古いカーネル イメージでは機能しません)。 dbus は新しいカーネルでは動作しません)。管理者がこの循環依存を回避する方法は、touchこれにより、次の再起動前にカーネル イメージがアップグレードされることが新しい dbus パッケージに通知されます。touchただし、 Lenny から Squeeze へのアップグレード中に、最初のアップグレードと再起動の前に、悪意のあるプロセスがそのパスを管理している場合、システムが起動できない可能性があります。私の記憶が正しければ、最初のアップグレードで新しい dbus がインストールされますが、新しいカーネル イメージをインストールするには、明示的に再度アップグレードする必要があります。1 回のアップグレードの後に​​再起動すると、システムが壊れる可能性があります。

GNU Coreutils のソースをtouch見ると、ファイルのタイムスタンプのみを設定しているように見えますが、オプションtouchが渡されたときにファイルが存在しない場合はファイルを作成しません。Linux の をラップする gnulib--no-dereferenceのユーティリティ関数を使用してこれを行い、シンボリック リンク ファイル自体のタイムスタンプを、Linux >= 2.6.22 のときに更新できるようにします。lutimensutimensat

于 2010-05-31T12:17:09.547 に答える