【问题标题】:How to replace contents of a file with null/0s/1s in linux kernel 3.5 programming如何在linux内核3.5编程中用null/0s/1s替换文件的内容
【发布时间】:2012-10-05 19:13:19
【问题描述】:

如果将文件名(路径)作为唯一的输入参数,如何在 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:我非常清楚如何在用户级程序中做这个非常简单的事情。但这不是我的任务。我必须在内核空间中进行。我需要这方面的帮助(尤其是在我刚接触内核编程时理解代码)。

【问题讨论】:

  • 你为什么要问?将文件管理留给内核文件子系统和内核文件系统实现。他们做得很好。 (他们也做磁盘缓冲!)。
  • @BasileStarynkevitch 我在问,因为我必须做一个任务,这是它的一部分。我被卡住了
  • 您是在编写 Linux 用户级应用程序(例如 C 语言)还是内核模块???如果编写应用程序,您不应该关心内核内部的实现细节,因为您只能通过系统调用使用内核。
  • @BasileStarynkevitch 我正在为内核 v3.5 编写代码......它在 VFS 层中
  • @footy -- 简而言之:没有办法 100% 完全删除所有数据痕迹,除非将设备变成灰尘。现在,一个简单的覆盖和取消链接将阻止大多数人看到数据,这对于个人文档等来说通常已经足够了。但是,如果有足够的时间和金钱,您会惊讶于坚定的数据恢复专家可以做什么。如果您在设备上存储绝密数据,那么我建议您使用铝热剂。我已经学会了将驱动器放在带式砂光机上,直到除了灰尘什么也没有。

标签: c linux filesystems kernel system-calls


【解决方案1】:

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

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

【讨论】:

  • 如有疑问,degauss
  • @Andy 我已经扩展了我的问题以包含更多信息。请看一看。
【解决方案2】:

我认为您可以使用write 系统调用轻松做到这一点。过程是

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

【讨论】:

  • 这可能足以阻止“随便”的外观,但它远非安全。
  • @JeremyJStarcher 你能详细说明它的安全问题吗?这怎么不能回答 OP 的问题?
  • 安迪的回答说得很好。 OP 要求提供erased completely,我将其翻译为erased to the point of unrecoverable. 用 0 覆盖的文件通常仍然可以使用日志跟踪、硬盘驱动器轨道“边缘”上的磁性残余物、块重新映射等任何东西来恢复。这甚至不包括内置版本控制和卷影副本的文件系统。
  • @shiplu.mokadd.im 好吧,伙计们,让我们把它调低一点:P 我是这里的菜鸟。您能否详细说明我如何完成第二个任务?
  • write(2)unlink(2) 是系统调用,可从用户级应用程序中使用;显然,OP 想要在内核领域实现这一点(IMNSHO,这很疯狂)。
【解决方案3】:

其他人已经很好地讨论了实际情况,所以我不会去那里(因此请不要费心修改这个答案)。我只是想描述一下混淆OP的代码。

首先,这段代码是来自fs/namei.c:vfs_unlink()的sn-p:

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

security_inode_unlink() 调用首先检查current(当前用户空间进程)是否具有从目录dir 中删除目录条目dentry 所需的权限。

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

dir->i_op->unlink(dir, entry); 只是为目录dir 调用unlink() 函数。 (请注意,fs/inode.c:vfs_unlink() 在上面显示的 sn-p 之前会检查 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(),它调用了特定于架构的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())来检查是否存在任何我忽略的锁定问题或竞争条件。你真的应该这样做,否则你的实验可能会导致你的内核出错(典型的竞争条件)。做我所做的,从系统调用开始,然后查看函数——尤其是他们的 cmets,他们通常会提到调用该函数是否有任何锁定要求——以找出答案。

【讨论】:

    猜你喜欢
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 2010-09-25
    • 2019-02-11
    • 1970-01-01
    • 1970-01-01
    • 2017-08-10
    相关资源
    最近更新 更多