如何在替换原子文件时保留所有权和权限?

Dan*_*den 5 c posix chmod file-rename chown

因此,正常的POSIX方式安全地,原子地替换文件的内容是:

  • fopen(3) 同一卷上的临时文件
  • fwrite(3) 临时文件的新内容
  • fflush(3)/ fsync(2)确保将内容写入磁盘
  • fclose(3) 临时文件
  • rename(2) 用于替换目标文件的临时文件

但是,在我的Linux系统(Ubuntu 16.04 LTS)上,此过程的一个后果是目标文件的所有权和权限更改为临时文件的所有权和权限,默认为uid/ gid和当前umask.

我想我会stat(2)在覆盖之前将代码添加到目标文件中,并且在调用之前将fchown(2)//fchmod(2)临时文件添加到目标文件中rename,但是由于这个原因可能会失败EPERM.

是唯一的解决方案,以确保文件的uid/ gid匹配当前用户和进程组覆盖文件?在这种情况下是否有一种安全的方法可以退回,还是我们必然会失去原子保证?

Nom*_*mal 5

确保文件的 uid/gid 与覆盖文件的进程的当前用户和组匹配的唯一解决方案吗?

不。

在 Linux 中,具有该功能的进程CAP_LEASE可以获得该文件的独占租约,这会阻止其他进程打开该文件长达几/proc/sys/fs/lease-break-time秒钟。这意味着从技术上讲,您可以获取独占租约,替换文件内容,然后释放租约,以原子方式修改文件(从其他进程的角度来看)。

此外,具有该功能的进程CAP_CHOWN可以任意更改文件所有权(用户和组)。

有没有一种安全的方法来[处理 uid 或 gid 与当前进程不匹配的情况],或者我们一定会失去原子保证?

考虑到一般情况下,文件可能具有ACLxattr,创建一个帮助程序可能很有用,该程序将包括 ACL 和扩展属性在内的所有权从现有文件克隆到同一目录中的新文件(可能使用如果允许真实用户 ( , , ) 修改原始文件,则为固定名称模式,例如,.new-################其中表示随机字母数字字符。该帮助程序至少具有该功能,并且必须考虑各种安全方面(尤其是它可以被利用的方式)。(但是,如果调用者可以覆盖内容,并在目标目录中创建新文件——调用者必须具有对目标目录的写访问权限,以便他们可以进行重命名/硬链接替换——在他们的空内容代表应该是安全的。不过,我个人会排除 root 用户或组拥有的目标文件。)#getuid()getgid()getgroups()CAP_CHOWN

本质上,帮助程序的行为与mktemp命令非常相似,只是它将现有目标文件的路径作为参数。fork()然后,使用例如/和管道或套接字将其包装到库函数中将相对简单exec()

我个人通过使用基于组的访问控制来避免这个问题:每组都有专用的(本地)组。文件所有者字段基本上只是一个信息字段,指示最后重新创建(或负责)所述文件的用户,访问控制完全基于组。这意味着更改模式和组 ID 以匹配原始文件就足够了。(不过,复制 ACL 会更好。)如果用户是目标组的成员,他们可以更改fchown()其拥有的任何文件的组,fchmod()也可以设置模式。


bol*_*lov 2

我绝不是这方面的专家,但我认为这是不可能的。这个答案似乎支持了这一点。必须有一个妥协。

以下是一些可能的解决方案。每一种都有优点和缺点,并根据用例和场景进行权衡和选择。

  • 使用原子重命名

    优点:原子操作

    缺点:可能无法保留所有者/权限

  • 创建备份。就地写入文件

    这就是一些文本编辑器所做的。

    优点:将保留所有者/权限

    缺点:没有原子性。可能会损坏文件。其他应用程序可能会获得该文件的“草稿”版本。

  • 设置文件夹的权限,以便可以使用原始所有者和属性创建新文件。

    优点:保留原子性和所有者/权限

    缺点:只能在某些特定场景中使用(创建要编辑的文件时的知识,安全模型必须允许并允许这样做)。会降低安全性。

  • 创建一个负责编辑文件的守护进程/服务。此进程将具有创建具有各自所有者和权限的文件所需的权限。它将接受编辑文件的请求。

    优点:保留原子性和所有者/权限。对编辑内容和编辑方式进行更高、更精细的控制。

    缺点。仅在特定情况下才可能。实施起来比较复杂。可能需要部署和安装。添加攻击面。添加可能的(安全)错误的另一个来源。由于添加的中间层可能会影响性能。