Commit 4ea51e0e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-2021-04-08' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux

Pull close_range() fix from Christian Brauner:
 "Syzbot reported a bug in close_range.

  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. As a result, 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().

  I've carried this fix for a little while but since there was no
  linux-next release over easter I waited until now.

  With this change close_range() can be further simplified but imho we
  are in no hurry to do that and so I'll defer this for the 5.13 merge
  window"

* tag 'for-linus-2021-04-08' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux:
  file: fix close_range() for unshare+cloexec
parents 035d8069 9b5b8722
......@@ -629,16 +629,29 @@ int close_fd(unsigned fd)
}
EXPORT_SYMBOL(close_fd); /* for ksys_close() */
/**
* last_fd - return last valid index into fd table
* @cur_fds: files struct
*
* Context: Either rcu read lock or files_lock must be held.
*
* Returns: Last valid index into fdtable.
*/
static inline unsigned last_fd(struct fdtable *fdt)
{
return fdt->max_fds - 1;
}
static inline void __range_cloexec(struct files_struct *cur_fds,
unsigned int fd, unsigned int max_fd)
{
struct fdtable *fdt;
if (fd > max_fd)
return;
/* make sure we're using the correct maximum value */
spin_lock(&cur_fds->file_lock);
fdt = files_fdtable(cur_fds);
max_fd = min(last_fd(fdt), max_fd);
if (fd <= max_fd)
bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1);
spin_unlock(&cur_fds->file_lock);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment