open()函数没有设置O_CLOEXEC标志

12

我试图使用open()设置O_CLOEXEC标志,但没有成功。

考虑以下微型测试:

#include <stdio.h>
#include <fcntl.h>

int main() {
  int fd = open("test.c", O_RDONLY | O_CLOEXEC);
  int ret = fcntl(fd, F_GETFL);
  if(ret & O_CLOEXEC) {
    printf("OK!\n");
  } else {
    printf("FAIL!\n");
  }
  printf("fd = %d\n", fd);
  printf("ret = %x, O_CLOEXEC = %x\n", ret, O_CLOEXEC);
  return 0;
} 

在 Linux 内核版本为 2.6 上运行测试会成功并打印“OK!”,但在 3.8 或 3.9 内核上失败。

出了什么问题? 谢谢!


请注意,在2.6.38中即使没有O_CLOEXEC支持,标志位也可能为真。 - Antti Haapala -- Слава Україні
3个回答

13

决定将O_CLOEXEC标志暴露给fcntl(fd, F_GETFL)是一种安全漏洞。在内核3.6-rc7中通过此次提交进行了更改:

commit c6f3d81115989e274c42a852222b80d2e14ced6f
Author: Al Viro <viro@zeniv.linux.org.uk>
Date:   Sun Aug 26 11:01:04 2012 -0400

don't leak O_CLOEXEC into ->f_flags

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

换句话说,你不应该依赖于O_CLOEXEC一开始就能被看到。

2

fcntl调用参数F_GETFD,标志是FD_CLOEXEC,并且O_CLOEXEC支持出现在2.6.23。请阅读手册:

 File descriptor flags
   The following commands manipulate the flags associated with a file descriptor.
   Currently,  only one such flag is defined: FD_CLOEXEC, the close-on-exec flag.
   If the FD_CLOEXEC bit is 0, the file descriptor will  remain  open  across  an
   execve(2), otherwise it will be closed.

   F_GETFD (void)
          Read the file descriptor flags; arg is ignored.

   F_SETFD (int)
          Set the file descriptor flags to the value specified by arg.

1
测试在运行支持O_CLOEXEC的内核3.8上失败。请仔细阅读问题。 - Ivan Efremov
1
这个答案是正确的,因为获取CLOEXEC状态的正确方法是使用F_GETFD并测试FD_CLOEXEC,因为CLOEXEC是适用于每个文件描述符而不是底层打开文件的标志。但这并不能解释为什么F_GETFL的ABI显然发生了变化。 - caf
请问您能引用描述“正确”的规范吗?从手册中我看到测试是完全“正确”的。 - Ivan Efremov
2
不,从来没有这样记录。 F_GETFL 只是文件的打开标志;有人决定将该位移除,因为它不影响已打开的文件,而仅影响文件描述符。这就是为什么它没有被记录在文档中的原因。 - Antti Haapala -- Слава Україні
此外,F_GETFL 似乎返回传递给 open 的所有标志,减去过滤后的标志,甚至包括被忽略的标志。 - Antti Haapala -- Слава Україні
显示剩余2条评论

2
你做错了,你应该这样做:
int ret = fcntl(fd, F_GETFD);
if (ret & FD_CLOEXEC) {
...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接