如何安全地打开一个正常的文件,而没有拒绝服务的问题?

标志O_DIRECTORY可以与系统调用open(2)openat(2)以避免打开目录时出现拒绝服务问题。 但是,如何避免常规文件的相同种族条件?

一些背景信息:我正在尝试开发某种备份工具。 程序遍历目录树,读取所有常规文件,只统计其他文件。 如果我首先为每个目录条目调用fstatat(2) ,那么testing一下普通文件的结果并用openat(2)打开它们,系统调用之间就会出现争用情况。 攻击者可以使用FIFOreplace常规文件,而我的程序将挂在FIFO上。

我怎样才能避免这种竞争条件? 对于目录,有O_DIRECTORY ,对于符号链接,可以使用O_PATH 。 但是,我找不到常规文件的解决scheme。 我只需要一个适用于最新Linux版本的解决scheme。

如果你唯一的担心是fifos, O_NONBLOCK将阻止阻止,并允许你打开一个前锋,即使它没有作家(见http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html这是哪里指定)。 但是,还有一些其他的问题:

  • 设备节点
  • Linux /proc假文件具有不良属性

由于这些通常不能由非root用户在任意位置创建, O_NOFOLLOW应该足以避免跟随它们的符号链接。

因此,在现代Linux上有一个更安全的解决方案:使用O_PATH|O_NOFOLLOW执行初始open ,然后对/proc/self/fd/%d执行stat以检查文件类型。 然后你可以打开/proc/self/fd/%d并完全确定它对应于你刚才stat的同一个文件。

请注意,在足够新的Linux上,不需要使用/proc/self/fd/%d来到达使用O_PATH获取inode句柄的O_PATH 。 您可以直接使用fstatopenat来“stat”它,并分别获得一个描述符到一个真实的打开的文件描述。 然而, O_PATH文件描述符在2.6.x后期(当它们第一次被添加时)的范围内有很多这样的错误/未实现的角落案例, O_PATH 3.8个,我发现/proc方法是最可靠的。 当然,如果失败,你总是可以尝试直接的方法,并回退到/proc

使用O_RDONLY | O_NONBLOCK打开,检查结果是否为-1,然后在生成的文件描述符上执行fstat(),并将st_mode(以及可能的st_dev和st_ino)与预期值进行比较。

记得在你的fstatat上设置AT_SYMLINK_NOFOLLOW标志。