Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5c598b34 authored by Al Viro's avatar Al Viro
Browse files

[PATCH] fix sysctl_nr_open bugs



* if luser with root sets it to something that is not a multiple of
  BITS_PER_LONG, the system is screwed.
* if it gets decreased at the wrong time, we can get expand_files()
  returning success and _not_ increasing the size of table as asked.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 2030a42c
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -150,8 +150,16 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
	nr /= (1024 / sizeof(struct file *));
	nr = roundup_pow_of_two(nr + 1);
	nr *= (1024 / sizeof(struct file *));
	if (nr > sysctl_nr_open)
		nr = sysctl_nr_open;
	/*
	 * Note that this can drive nr *below* what we had passed if sysctl_nr_open
	 * had been set lower between the check in expand_files() and here.  Deal
	 * with that in caller, it's cheaper that way.
	 *
	 * We make sure that nr remains a multiple of BITS_PER_LONG - otherwise
	 * bitmaps handling below becomes unpleasant, to put it mildly...
	 */
	if (unlikely(nr > sysctl_nr_open))
		nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;

	fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
	if (!fdt)
@@ -199,6 +207,16 @@ static int expand_fdtable(struct files_struct *files, int nr)
	spin_lock(&files->file_lock);
	if (!new_fdt)
		return -ENOMEM;
	/*
	 * extremely unlikely race - sysctl_nr_open decreased between the check in
	 * caller and alloc_fdtable().  Cheaper to catch it here...
	 */
	if (unlikely(new_fdt->max_fds <= nr)) {
		free_fdarr(new_fdt);
		free_fdset(new_fdt);
		kfree(new_fdt);
		return -EMFILE;
	}
	/*
	 * Check again since another task may have expanded the fd table while
	 * we dropped the lock