如何在linux kernel 3.5编程中用null / 0s / 1s替换文件的内容

时间:2012-10-15 18:43:09

标签: c linux filesystems kernel system-calls

如果文件名(路径为)作为唯一的输入参数,如何在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:我非常清楚在用户级程序中如何做到这一点非常简单。但这不是我的任务。我必须在内核空间中完成它。我需要帮助(特别是在我熟悉内核编程时理解代码)。

3 个答案:

答案 0 :(得分:5)

这里没有好的答案,当然也不是单个文件的级别。在简单的文件系统(FAT,ext2)上,通常只需打开文件并覆盖它就足够了。但是几乎所有的现代系统都失败了。现代文件系统几乎总是可以配置为记录数据更改(尽管这很少是默认设置),并且数据将保留在日志中,直到它将来恰好被覆盖。即使您知道文件系统已“忘记”存储系统可能没有的数据 - 考虑实时备份或脱机LVM卷的情况。或驱动程序:NAND驱动程序会在写入时常规重新映射块,从而留下“陈旧”内容。甚至是硬件本身:像SSD或MMC这样的闪存技术完全执行相同类型的块重映射,让旧数据通过JTAG等进行读取......

如果您想确保您的数据不在持久存储上,那么现代世界中唯一一个干净的解决方案就是永远不要在那里写它。将其缓存在RAM中,或将其写入tmpfs(不支持swap!),或者提出某种加密方案,以确保存储泄露不会使攻击者可以使用...

答案 1 :(得分:4)

我认为您可以使用write系统调用轻松完成。这个过程是

  1. 使用write将NULL值写入给定文件的所有字节
  2. 使用unlink删除文件。

答案 2 :(得分: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支持许多不同的文件系统,并且每个文件系统(可能)都有自己的inode操作,因此这些操作作为函数指针存储在struct inode(dir),i_op成员结构中。 (请记住,目录与文件非常相似,因为它包含该目录中包含的所有条目的元数据。因此,将操作特定于目录非常有意义。)

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

最后一位dir->i_op->unlinkdont_mount(entry);中定义的辅助函数,只是将include/linux/dcache.h标记为“不可安装”,无法访问。 (目录条目缓存在dcache中。而不是必须重新输入它,可能是一个缓慢的操作,这只是标记它无效。将来很快,所有陈旧的dcache条目将立即被删除。这是非常有效的如果你考虑的话,也很简单。)


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

如果将问题分解为可管理的步骤,问题就很容易解决。如果我们假设这仅用于实验和学习,而不是出于安全目的 - 为了安全起见,您需要清理,而不仅仅是清除内容 - 然后您需要执行entry + { {1}} + open() + lseek(),只是在内核中,对吧?

您不想使用ftruncate(),因为特定于文件系统的写入函数需要用户空间缓冲区。你需要分配一个(比如一个页面长度 - 看close()调用特定于arch的{​​{1}}),用数据填充它,在循环中将它写入文件,然后释放用户空间缓冲区(使用write())。这样一个繁忙的内核循环是一个很大的禁忌;你需要将它移动到工作线程中..

不,简单地找出文件的长度,然后将其截断为零长度,并将其重新截断为所需的长度要好得多。这就像你在其中写入零一样。用除了零之外的任何内容替换内容只是太多的工作,IMO。

对于mm/mmap.c:sys_old_mmap(),请致电sys_mmap_pgoff()。请记住,您只需要生成mm/mmap.c:vm_munmap()而不是文件descritor来操作内核空间中的文件。

对于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 *myfilestruct file *filefile_lengthsys_open())以检查是否存在锁定我忽略了问题或竞争条件。你真的应该这样做,因为否则你的实验可能会破坏你的内核(典型的竞争条件)。做我做的,从系统调用开始,然后查看函数 - 特别是他们的注释,他们通常会提到调用该函数是否有任何锁定要求 - 找出来。