Skip to content

Commit 9b5b872

Browse files
author
Christian Brauner
committed
file: fix close_range() for unshare+cloexec
syzbot reported a bug when putting the last reference to a tasks file descriptor table. Debugging this showed we didn't recalculate the current maximum fd number for CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC after we unshared the file descriptors table. So max_fd could exceed the current fdtable maximum causing us to set excessive bits. As a concrete example, let's say the user requested everything from fd 4 to ~0UL to be closed and their current fdtable size is 256 with their highest open fd being 4. With CLOSE_RANGE_UNSHARE the caller will end up with a new fdtable which has room for 64 file descriptors since that is the lowest fdtable size we accept. But now max_fd will still point to 255 and needs to be adjusted. Fix this by retrieving the correct maximum fd value in __range_cloexec(). Reported-by: [email protected] Fixes: 582f1fb ("fs, close_range: add flag CLOSE_RANGE_CLOEXEC") Fixes: fec8a6a ("close_range: unshare all fds for CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC") Cc: Christoph Hellwig <[email protected]> Cc: Giuseppe Scrivano <[email protected]> Cc: Al Viro <[email protected]> Cc: [email protected] Cc: [email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 0d02ec6 commit 9b5b872

File tree

1 file changed

+17
-4
lines changed

1 file changed

+17
-4
lines changed

fs/file.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -629,17 +629,30 @@ int close_fd(unsigned fd)
629629
}
630630
EXPORT_SYMBOL(close_fd); /* for ksys_close() */
631631

632+
/**
633+
* last_fd - return last valid index into fd table
634+
* @cur_fds: files struct
635+
*
636+
* Context: Either rcu read lock or files_lock must be held.
637+
*
638+
* Returns: Last valid index into fdtable.
639+
*/
640+
static inline unsigned last_fd(struct fdtable *fdt)
641+
{
642+
return fdt->max_fds - 1;
643+
}
644+
632645
static inline void __range_cloexec(struct files_struct *cur_fds,
633646
unsigned int fd, unsigned int max_fd)
634647
{
635648
struct fdtable *fdt;
636649

637-
if (fd > max_fd)
638-
return;
639-
650+
/* make sure we're using the correct maximum value */
640651
spin_lock(&cur_fds->file_lock);
641652
fdt = files_fdtable(cur_fds);
642-
bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1);
653+
max_fd = min(last_fd(fdt), max_fd);
654+
if (fd <= max_fd)
655+
bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1);
643656
spin_unlock(&cur_fds->file_lock);
644657
}
645658

0 commit comments

Comments
 (0)