Skip to content

Commit 4dec4f9

Browse files
mjguzikbrauner
authored andcommitted
fs: sort out fd allocation vs dup2 race commentary, take 2
fd_install() has a questionable comment above it. While it correctly points out a possible race against dup2(), it states: > 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. I have difficulty parsing the above. The first sentence would suggest fd_install() tries to detect and recover from the race (it does not), the next one claims the race needs to be dealt with (it is, by dup2()). Given that fd_install() does not suffer the burden, this patch removes the above and instead expands on the race in dup2() commentary. While here tidy up the docs around fd_install(). Signed-off-by: Mateusz Guzik <mjguzik@gmail.com> Link: https://lore.kernel.org/r/20250320102637.1924183-1-mjguzik@gmail.com Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent c918f15 commit 4dec4f9

1 file changed

Lines changed: 26 additions & 14 deletions

File tree

fs/file.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -621,22 +621,14 @@ void put_unused_fd(unsigned int fd)
621621

622622
EXPORT_SYMBOL(put_unused_fd);
623623

624-
/*
625-
* Install a file pointer in the fd array.
626-
*
627-
* The VFS is full of places where we drop the files lock between
628-
* setting the open_fds bitmap and installing the file in the file
629-
* array. At any such point, we are vulnerable to a dup2() race
630-
* installing a file in the array before us. We need to detect this and
631-
* fput() the struct file we are about to overwrite in this case.
632-
*
633-
* It should never happen - if we allow dup2() do it, _really_ bad things
634-
* will follow.
624+
/**
625+
* fd_install - install a file pointer in the fd array
626+
* @fd: file descriptor to install the file in
627+
* @file: the file to install
635628
*
636629
* This consumes the "file" refcount, so callers should treat it
637630
* as if they had called fput(file).
638631
*/
639-
640632
void fd_install(unsigned int fd, struct file *file)
641633
{
642634
struct files_struct *files = current->files;
@@ -1249,8 +1241,28 @@ __releases(&files->file_lock)
12491241
struct fdtable *fdt;
12501242

12511243
/*
1252-
* We need to detect attempts to do dup2() over allocated but still
1253-
* not finished descriptor.
1244+
* dup2() is expected to close the file installed in the target fd slot
1245+
* (if any). However, userspace hand-picking a fd may be racing against
1246+
* its own threads which happened to allocate it in open() et al but did
1247+
* not populate it yet.
1248+
*
1249+
* Broadly speaking we may be racing against the following:
1250+
* fd = get_unused_fd_flags(); // fd slot reserved, ->fd[fd] == NULL
1251+
* file = hard_work_goes_here();
1252+
* fd_install(fd, file); // only now ->fd[fd] == file
1253+
*
1254+
* It is an invariant that a successfully allocated fd has a NULL entry
1255+
* in the array until the matching fd_install().
1256+
*
1257+
* If we fit the window, we have the fd to populate, yet no target file
1258+
* to close. Trying to ignore it and install our new file would violate
1259+
* the invariant and make fd_install() overwrite our file.
1260+
*
1261+
* Things can be done(tm) to handle this. However, the issue does not
1262+
* concern legitimate programs and we only need to make sure the kernel
1263+
* does not trip over it.
1264+
*
1265+
* The simplest way out is to return an error if we find ourselves here.
12541266
*
12551267
* POSIX is silent on the issue, we return -EBUSY.
12561268
*/

0 commit comments

Comments
 (0)