3

我的程序按时间顺序执行以下操作

  1. 该程序以 root 权限启动。
  2. 在其他任务中,编辑了一个只有 root 权限才能读取的文件open()
  3. 根权限被删除。
  4. 子进程生成clone()CLONE_FILES | CLONE_FS | CLONE_IO设置了标志,这意味着虽然它们使用不同的虚拟内存区域,但它们共享相同的文件描述符表(和其他 IO 内容)。
  5. 所有子进程execve()自己的程序(FD_CLOEXEC不使用该标志)。
  6. 原程序终止。

现在我希望每个生成的程序都读取上述文件的内容,但是在他们都读取了文件之后,我希望它被关闭(出于安全原因)。

我现在正在考虑的一种可能的解决方案是有一个步骤 3a,其中文件的 fddup()为每个子进程分配一次,每个子进程都有自己的 fd(作为argv)。然后每个子程序都会简单地close()使用他们的 fd,以便在所有指向文件的 fd 都是close()d 之后,“实际文件”被关闭。

但它是这样工作的吗?这样做是否安全(即文件是否真的关闭了)?如果没有,是否有另一种/更好的方法?

4

1 回答 1

2

虽然dup()按照我上面的建议使用可能还不错,但我现在——在问了这个 SO 问题的第二天——意识到有一种更好的方法可以做到这一点,至少从线程安全的角度来看是这样。

所有dup()licated 文件描述符都指向相同的文件位置指示器,这当然意味着当多个线程/进程可能在读取操作期间同时尝试更改文件位置时您会遇到麻烦(即使您自己的代码以线程安全的方式这样做) ,您所依赖的库不一定如此)。

所以等等,为什么不在open()删除根目录之前在所需文件上多次调用(每个孩子一次)?从手册open()

对 open() 的调用会创建一个新的打开文件描述,即系统范围的打开文件表中的一个条目。此条目记录文件偏移量和文件状态标志(可通过 fcntl(2) F_SETFL 操作修改)。文件描述符是对这些条目之一的引用;如果随后删除或修改路径名以引用不同的文件,则此引用不受影响。新的打开文件描述最初不与任何其他进程共享,但可以通过 fork(2) 进行共享。

可以这样使用:

int fds[CHILD_C];
for (int i = 0; i < CHILD_C; i++) {
    fds[i] = open("/foo/bar", O_RDONLY);
    // check for errors here
}
drop_privileges();
// etc

然后每个孩子都会通过其中一个 fd 获得参考,argv并执行以下操作:

  1. FILE *stream = fdopen(atoi(argv[FD_STRING_I]), "r")
  2. stream
  3. fclose(stream)(这也关闭了底层文件描述符)

免责声明:根据我运行的一系列测试,这确实是安全可靠的。然而,我只open()O_RDONLY测试过。使用 O_RDWR 或 O_WRONLY 可能安全也可能不安全

于 2013-06-03T03:48:25.913 回答