使用 dup2 时的竞争条件

2024-03-18

这个联机帮助页 http://linux.die.net/man/2/dup2为了dup2系统调用说:

EBUSY(仅限 Linux)这可能会在执行期间由 dup2() 或 dup3() 返回 open(2) 和 dup() 的竞争条件。

它谈论什么竞争条件以及如果我该怎么办dup2 gives EBUSY错误?我应该像下面的情况一样重试吗EINTR?


中有一个解释fs/file.c, do_dup2() https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/fs/file.c?id=refs/tags/v3.14.4#n759:

/*
 * We need to detect attempts to do dup2() over allocated but still
 * not finished descriptor.  NB: OpenBSD avoids that at the price of
 * extra work in their equivalent of fget() - they insert struct
 * file immediately after grabbing descriptor, mark it larval if
 * more work (e.g. actual opening) is needed and make sure that
 * fget() treats larval files as absent.  Potentially interesting,
 * but while extra work in fget() is trivial, locking implications
 * and amount of surgery on open()-related paths in VFS are not.
 * FreeBSD fails with -EBADF in the same situation, NetBSD "solution"
 * deadlocks in rather amusing ways, AFAICS.  All of that is out of
 * scope of POSIX or SUS, since neither considers shared descriptor
 * tables and this condition does not arise without those.
 */
fdt = files_fdtable(files);
tofree = fdt->fd[fd];
if (!tofree && fd_is_open(fd, fdt))
    goto Ebusy;

好像EBUSY当要释放的描述符仍在打开时处于某种不完整状态时返回(fd_is_open但不存在于fdtable).

编辑(更多信息并且确实想要赏金)

为了了解如何!tofree && fd_is_open(fd, fdt)可能会发生,让我们看看文件是如何打开的。这里有一个简化版本sys_open :

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
    /* ... irrelevant stuff */
    /* allocate the fd, uses a lock */
    fd = get_unused_fd_flags(flags);
    /* HERE the race condition can arise if another thread calls dup2 on fd */
    /* do the real VFS stuff for this fd, also uses a lock */
    fd_install(fd, f);
    /* ... irrelevant stuff again */
    return fd;
}

基本上发生了两件非常重要的事情:分配文件描述符,然后 VFS 才实际打开它。这两个操作修改了fdt的过程。它们都使用锁,所以在这两个调用中没有什么不好的。

为了记住哪个fds已分配了一个名为的位向量open_fds被使用的是fdt. After get_unused_fd_flags(), the fd已分配并设置了相应的位open_fds。锁在fdt已经发布了,但是真正的VFS工作还没有完成。

就在此时,另一个线程(或者在共享的情况下是另一个进程)fdt) 可以调用 dup2,它不会阻塞,因为锁已被释放。如果dup2在这里走上了正常的道路fd会被替换,但是fd_install仍将为旧文件运行。因此检查并返回Ebusy.

我在评论中找到了有关此竞争条件的更多信息fd_install()这证实了我的解释:

/* The VFS is full of places where we drop the files lock between
 * setting the open_fds bitmap and installing the file in the file
 * array.  At any such point, we are vulnerable to a dup2() race
 * installing a file in the array before us.  We need to detect this and
 * fput() the struct file we are about to overwrite in this case.
 *
 * It should never happen - if we allow dup2() do it, _really_ bad things
 * will follow. */
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 dup2 时的竞争条件 的相关文章

随机推荐