因此,安全地、原子地替换文件内容的正常 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
与覆盖文件的进程的当前用户和组相匹配的解决方案是唯一的吗?在这种情况下是否有安全的回退方式,或者我们是否必然会失去原子保证?
最佳答案
Is the only solution to ensure that the uid/gid of the file matches the current user and group of the process overwriting the file?
没有。
在 Linux 中,具有 CAP_LEASE
能力的进程可以获得文件的独占租约,这会阻止其他进程打开文件,最多 /proc/sys/fs/lease -break-time
秒。这意味着从技术上讲,您可以采取独占租约、替换文件内容并释放租约,以原子方式修改文件(从其他进程的角度来看)。
此外,具有CAP_CHOWN
功能的进程可以任意更改文件所有权(用户和组)。
Is there a safe way to [handle the case where the uid or gid does not match the current process], or do we necessarily lose the atomic guarantee?
考虑到一般情况下,文件可能有ACL s 和 xattr s,创建一个帮助程序可能很有用,它将包括 ACL 和扩展属性在内的所有权从现有文件克隆到同一目录中的新文件(可能具有固定的名称模式,比如 .new- ################
,其中#
表示随机字母数字字符),如果真实用户(getuid()
, getgid()
, getgroups()
) 允许修改原文件。此帮助程序至少具有 CAP_CHOWN
功能,并且必须考虑各种安全方面(尤其是它可能被利用的方式)。 (但是,如果调用者可以覆盖内容,并在目标目录中创建新文件——调用者必须对目标目录具有写访问权限,以便他们可以进行重命名/硬链接(hard link)替换——创建一个克隆文件他们代表空内容应该是安全的。不过,我个人会排除 root 用户或组拥有的目标文件。)
从本质上讲,辅助程序的行为很像 mktemp
命令,只是它将现有目标文件的路径作为参数。然后将它包装到库函数中会相对简单,例如使用fork()
/exec()
和管道或套接字。
我个人通过使用基于组的访问控制来避免这个问题:每个组都有专用的(本地)组。文件所有者字段基本上只是一个信息字段,指示最后重新创建(或负责)所述文件的用户,访问控制完全基于组。这意味着更改模式和组 ID 以匹配原始文件就足够了。 (不过,复制 ACL 会更好。)如果用户是目标组的成员,他们可以执行 fchown()
来更改他们拥有的任何文件的组,以及fchmod()
也可以设置模式。
关于c - 进行原子文件替换时如何保留所有权和权限?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49031335/