2

唯一の入力パラメーターとしてファイル名(ファイルへのパス)を指定して、Linuxカーネル3.5でファイルの内容を完全に0または1に消去するにはどうすればよいですか?

unlinkシステムコールの構造と、多くのチェックコールの後で調べましたint vfs_unlink(struct inode *dir, struct dentry *dentry)

* dentryからファイルの内容を削除するにはどうすればよいですか?それとも私*dentryはまったく使うべきですか?

編集

答えに応えて:私はただデータを上書きしたいだけです。そして、私は完璧な結果を探していません。私はこれまでに進歩しました:

一方:vfs_unlinkを使用する

私は次のコードで混乱しています:

error = security_inode_unlink(dir, dentry);
if (!error) {
error = dir->i_op->unlink(dir, dentry);
if (!error)
   dont_mount(dentry)
 }

ここで実際のリンク解除はどこで行われていますか?

別のアプローチ:writeシステムコールを使用してデータの書き込みを進めました。

私は特にこれらの行を理解できませんでした:

 143        int size = file->f_path.dentry->d_inode->i_size;
 144        loff_t offs = *off;
 145        int count = min_t(size_t, bytes, PAGE_SIZE);

 151        if (size) {
 152                if (offs > size)
 153                        return 0;
 154                if (offs + count > size)
 155                        count = size - offs;
 156        }
 157
 158        temp = memdup_user(userbuf, count);

 162        mutex_lock(&bb->mutex);
 163
 164        memcpy(bb->buffer, temp, count);
 165
 166        count = flush_write(file, bb->buffer, offs, count);
 167        mutex_unlock(&bb->mutex);
 168
 169        if (count > 0)
 170                *off = offs + count;
 171
 172        kfree(temp);
 173        return count;

誰かが私にこれを説明できますか?ファイルにnullを書き込むことができるようにします。私の関数は次のようになります。

static void write(struct file *file)

これについて助けが必要です。私はコードを求めていませんが、現在迷っています。

ありがとう

PS:私はユーザーレベルのプログラムでこの非常に単純なことを行う方法を完全によく知っています。しかし、それは私の仕事ではありません。私はカーネル空間でそれをしなければなりません。そして、私はそれについて助けが必要です(そして、特にカーネルプログラミングに慣れていないのでコードを理解する必要があります)。

4

3 に答える 3

5

ここには良い答えはなく、確かに個々のファイルのレベルではありません。単純なファイルシステム(FAT、ext2)では、通常、ファイルを開いて上書きするだけで十分です。しかし、それはほとんどすべての最新のシステムで失敗します。最新のファイルシステムは、ほとんどの場合、データの変更をジャーナルするように構成でき(これがデフォルトになることはめったにありませんが)、そのデータは、将来上書きされるまでジャーナルに残ります。ファイルシステムがデータを「忘れた」ことがわかっている場合でも、ストレージシステムはデータを「忘れて」いない可能性があります。ライブバックアップの場合や、LVMボリュームのオフラインの場合を考えてみてください。またはドライバー:NANDドライバーは、ブロックが書き込まれるときに定期的にブロックを再マップし、「古い」コンテンツをそのまま残します。または、ハードウェア自体でさえ:SSDやMMCなどのフラッシュテクノロジーは、まったく同じ種類のブロックの再マッピングを行います。

データが永続ストレージにないことを確認したい場合、現代の世界で唯一のクリーンなソリューションは、そもそもデータをそこに書き込むことではありません。RAMにキャッシュするか、tmpfsに書き込むか(スワップによってバックアップされていません!)、またはストレージの侵害によって攻撃者が利用できないようにする何らかの暗号化スキームを考え出します...

于 2012-10-15T18:54:57.433 に答える
4

writeシステムコールで簡単にできると思います。プロセスは

  1. write特定のファイルのすべてのバイトにNULL値を書き込むを使用する
  2. を使用してファイルを削除しますunlink
于 2012-10-15T18:53:36.107 に答える
0

他の人は実際の状況についてかなりよく話し合っているので、私はそこに行きません(したがって、この答えをわざわざ改造しないでください)。OPを混乱させるコードを説明したかっただけです。

まず、このコードは次のスニペットですfs/namei.c:vfs_unlink()

error = security_inode_unlink(dir, dentry);
if (!error) {
    error = dir->i_op->unlink(dir, dentry);
    if (!error)
        dont_mount(dentry);
}

このsecurity_inode_unlink()呼び出しは、最初にcurrent(現在のユーザースペースプロセス)がディレクトリdentryからディレクトリエントリを削除するために必要な権限を持っているかどうかを確認しますdir

Linuxは多くの異なるファイルシステムをサポートしており、各ファイルシステムには独自のiノード操作があるため、これらの操作は関数ポインターとしてstruct inode(dir)のi_opメンバー構造に格納されます。(ディレクトリは、そのディレクトリに含まれるすべてのエントリのメタデータが含まれているという点で、ファイルと非常に似ていることに注意してください。したがって、操作をディレクトリに固有にすることは非常に理にかなっています。)

ディレクトリの関数を呼び出すdir->i_op->unlink(dir, entry);だけです。(上記のスニペットの前に、NULL以外のチェックが行われることに注意してください。)unlink()dirfs/inode.c:vfs_unlink()dir->i_op->unlink

最後のビットであるdont_mount(entry);、は、で定義されたヘルパー関数でinclude/linux/dcache.hあり、単にentry「マウント不可」であり、アクセスできないことを示しています。(ディレクトリエントリはdcacheにキャッシュされます。エントリをリームアウトする必要はなく、操作が遅くなる可能性があります。これにより、無効としてマークされます。将来的には、古いdcacheエントリがすべて一度に削除されます。これは非常に効率的です。方法、そしてあなたがそれについて考えるならば、非常に単純でもあります。)


ごめん。私は自分自身を助けることはできません; スプーンをスープに入れなければなりません。

問題を管理可能なステップに分割すれば、問題はかなり簡単に解決できます。これがセキュリティ目的ではなく、実験と学習のみを目的としていると仮定した場合、セキュリティのためには、コンテンツをクリアするだけでなく、スクラブする必要があります。次に、カーネル内でopen()+ lseek()+ ftruncate()+を実行する必要がありますか?close()

write()ファイルシステム固有の書き込み関数にはユーザースペースバッファーが必要なため、を使用する必要はありません。1つを割り当て(たとえば、1ページの長さ-mm/mmap.c:sys_old_mmap()アーチ固有の呼び出しを確認してくださいsys_mmap_pgoff())、データを入力し、ループでファイルに書き込んでから、ユーザースペースバッファーを解放する必要があります(を使用してmm/mmap.c:vm_munmap())。このようなビジーなカーネルループは大したことではありません。ワーカースレッドに移動する必要があります。

いいえ、ファイルの長さを単純に調べてから、長さをゼロに切り捨ててから、目的の長さに再切り捨てる方がはるかに優れています。これは、ゼロを書き込んだ場合と同じです。内容をゼロ以外のものに置き換えるのは大変な作業です、IMO。

についてopen()は、を呼び出しますfilp_open()struct file *myfileカーネル空間でファイルを操作するには、ファイル記述子ではなく、結果の記述子のみが必要であることを忘れないでください。

の場合close()は、を呼び出すだけfilp_close(myfile, current->files)です。プロセスのファイル記述子のメンテナンスを省略した場合current、それが実際に残っている唯一のものですfs/open.c:sys_close()

の場合lseek()は、を呼び出すだけloff_t file_length = vfs_lseek(myfile, (off_t)0, SEEK_END);です。あなたが見るとfs/read_write.c:sys_lseek()、結局のところ、それはそれがすることです。

についてftruncate()は、を見てくださいfs/open.c:do_sys_ftruncate()。ただし、ファイル記述子のものを省略することを忘れないでください。その関数struct file *myfileのに対応する、がすでにあります。struct file *fileああ、それを2回行う必要があることを忘れないでください。最初は長さをゼロにし、次にfile_length上記で取得したものです。

上記のすべてを組み合わせることは、これを達成するためのかなり実行可能な方法のようです-私たち全員がそれが学習と実験にのみ有用であり、実用的ではないことに同意すると仮定します。

私が見落としたロックの問題や競合状態があるかどうかを確認するために、4つのシステムコール( sys_open()、、、、)すべてを確認するために必要な時間を実際に費やしたわけではないことに注意してください。本当にそうする必要があります。そうしないと、実験でカーネルが機能しなくなる可能性があります(通常は競合状態の場合)。私がしたことを実行し、システムコールから始めて、関数(特にそのコメント)を見て、通常、その関数を呼び出すためのロック要件があるかどうかを確認します。sys_lseek()sys_ftruncate()sys_close()

于 2012-10-16T02:43:33.493 に答える