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. writeNULL 值写入给定文件的所有字节
  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中删除目录条目所需的权限。dentrydir

由于 Linux 支持许多不同的文件系统,并且每个文件系统(可能)都有自己的 inode 操作,因此这些操作作为函数指针存储在 struct inode ( dir)i_op成员结构中。(请记住,目录与文件非常相似,因为它包含该目录中包含的所有条目的元数据。因此,使操作特定于目录非常有意义。)

dir->i_op->unlink(dir, entry);只需调用目录的unlink()函数dir。(请注意,在上面显示的代码段之前,fs/inode.c:vfs_unlink()它会检查dir->i_op->unlink非 NULL。)

最后一点,dont_mount(entry);是定义在 中的辅助函数include/linux/dcache.h,简单地标记entry为“不可安装”,不可访问。(目录条目被缓存在 dcache 中。不必从中取出条目,这可能是一个缓慢的操作,这只是将其标记为无效。在不久的将来,所有过时的 dcache 条目将立即被删除。这非常有效方式,而且也很简单,如果你考虑一下的话。)


对不起。我无法自拔;我必须把勺子加到汤里。

如果您将其分解为可管理的步骤,则该问题很容易解决。如果我们假设这只是为了实验和学习,而不是出于安全目的——为了安全,你需要擦洗而不仅仅是清除内容——那么你需要做++++ open(),只是在内核中,对吗?lseek()ftruncate()close()

您不想使用write(),因为特定于文件系统的写入函数需要用户空间缓冲区。您需要分配一个(例如,一页长度 - 查看mm/mmap.c:sys_old_mmap()哪个调用特定于 arch 的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于该函数中的 。哦,记住你需要做两次:首先是零长度,然后是file_length你上面得到的。

将以上所有内容结合起来似乎是实现这一目标的一种非常可行的方法——假设我们都同意它只对学习和实验有用,没有任何实际意义。

请注意,我并没有真正花费必要的时间检查所有四个系统调用(sys_open(), sys_lseek(), sys_ftruncate(), sys_close())来检查是否存在我忽略的锁定问题或竞争条件。你真的应该这样做,否则你的实验可能会导致你的内核出错(典型的竞争条件)。做我所做的,从系统调用开始,然后查看函数——尤其是他们的评论,他们通常会提到调用该函数是否有任何锁定要求——以找出答案。

于 2012-10-16T02:43:33.493 回答