mkstemp() - 关闭描述符并重新打开它是否安全?

3
使用mkstemp()生成临时文件名后,立即调用close()关闭mkstemp()返回的文件描述符,将由mkstemp()生成的文件名存储在某处,并在以后的某个时间再次打开该文件进行临时写入,是否安全?或者当我调用close()时,这个临时文件名会立即变为可用状态?
我询问的原因是我想知道为什么mkstemp()会返回一个文件描述符。如果可以安全地立即关闭描述符,为什么它还要返回一个描述符呢?mkstemp()可以自行关闭它并只给我一个文件名。
2个回答

6

在使用mkstemp()创建文件和重新打开它之间的时间内,对手可能会删除您创建的文件并放置一个符号链接指向完全不同的位置。这是TOCTOU(Time of Check, Time of Use)漏洞,使用mkstemp()可以大大避免,前提是保持文件描述符处于打开状态。

一旦关闭文件描述符,在足够敌对的环境中所有赌注都没有了。

请注意,即使保持文件描述符打开,对手也可能会删除文件或重命名文件,然后创建自己的文件(符号链接、目录)代替它。文件描述符仍然有效。您可以使用stat()获取名称信息和fstat()获取文件描述符信息,如果两者匹配(st_devst_ino字段),那么您可能仍然没问题。如果它们不同,有人已经在使用该文件——如果您重命名它,您可能正在重命名他们的文件而不是您创建的文件。

虽然mkstemp()创建的原始文件仍然存在,但名称不会重新生成。通常,连续调用mkstemp()将创建不同的名称,但是在创建时名称保证是唯一的(请参见open()O_EXCL标志)。

以防万一,您可能会想知道,没有一种方法可以将名称与文件描述符关联起来(没有假设的int flink(int fd, const char *name)系统调用)。之前在Stack Exchange网站上有一个问题,答案绝对是否定的,并提供了Linux Kernel邮件列表等参考资料。其中一个问题是Is it possible to recreate a file from an opened file descriptor?,但我认为还有一个更详尽的版本的问题。


好的,这是一个安全问题。但是如果前一次调用mkstemp()的文件名已经被close()关闭,那么连续调用mkstemp()会返回完全相同的文件名吗? - Andreas
如果原始文件已被删除,mkstemp() 可能会两次返回相同的名称;如果它仍然存在,则不会再次返回相同的名称。 - Jonathan Leffler
好的,谢谢。这基本上就是我想知道的 :) - Andreas

4
mkstemp函数专门使用描述符而不是文件名来避免与其前身(如mktemp)常见的竞态条件。事实上,“mkstemp”中的“s”表示“安全”,因为竞态条件可能成为漏洞的源头(例如,如果您使用临时文件来存储JIT代码,并且在您打开它之前某个人猜测/覆盖该文件,则可能导致您的应用程序加载/运行所提供的代码而不是程序生成的代码)。

一旦您关闭了描述符,另一个应用程序就可以写入具有相同名称的文件,因此请不要这样做。您应该保留描述符,只要临时文件仍然被程序需要使用(并在临时文件不再被程序使用时关闭描述符)。


谢谢。当然,我知道另一个程序在关闭文件后可以更改文件的风险,但我可以接受这种风险。我只是想知道是否可能发生mkstemp()再次返回相同的名称,但似乎不是这种情况。 - Andreas

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