[PATCH] fix RLIM_NOFILE handling
* dup2() should return -EBADF on exceeded sysctl_nr_open * dup() should *not* return -EINVAL even if you have rlimit set to 0; it should get -EMFILE instead. Check for orig_start exceeding rlimit taken to sys_fcntl(). Failing expand_files() in dup{2,3}() now gets -EMFILE remapped to -EBADF. Consequently, remaining checks for rlimit are taken to expand_files(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
6c5d0512a0
commit
4e1e018ecc
3 changed files with 15 additions and 21 deletions
18
fs/fcntl.c
18
fs/fcntl.c
|
@ -64,11 +64,6 @@ static int locate_fd(unsigned int orig_start, int cloexec)
|
||||||
struct fdtable *fdt;
|
struct fdtable *fdt;
|
||||||
|
|
||||||
spin_lock(&files->file_lock);
|
spin_lock(&files->file_lock);
|
||||||
|
|
||||||
error = -EINVAL;
|
|
||||||
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
repeat:
|
repeat:
|
||||||
fdt = files_fdtable(files);
|
fdt = files_fdtable(files);
|
||||||
/*
|
/*
|
||||||
|
@ -84,10 +79,6 @@ static int locate_fd(unsigned int orig_start, int cloexec)
|
||||||
newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
|
newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
|
||||||
fdt->max_fds, start);
|
fdt->max_fds, start);
|
||||||
|
|
||||||
error = -EMFILE;
|
|
||||||
if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = expand_files(files, newfd);
|
error = expand_files(files, newfd);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -141,13 +132,14 @@ asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
|
||||||
spin_lock(&files->file_lock);
|
spin_lock(&files->file_lock);
|
||||||
if (!(file = fcheck(oldfd)))
|
if (!(file = fcheck(oldfd)))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
|
||||||
goto out_unlock;
|
|
||||||
get_file(file); /* We are now finished with oldfd */
|
get_file(file); /* We are now finished with oldfd */
|
||||||
|
|
||||||
err = expand_files(files, newfd);
|
err = expand_files(files, newfd);
|
||||||
if (err < 0)
|
if (unlikely(err < 0)) {
|
||||||
|
if (err == -EMFILE)
|
||||||
|
err = -EBADF;
|
||||||
goto out_fput;
|
goto out_fput;
|
||||||
|
}
|
||||||
|
|
||||||
/* To avoid races with open() and dup(), we will mark the fd as
|
/* To avoid races with open() and dup(), we will mark the fd as
|
||||||
* in-use in the open-file bitmap throughout the entire dup2()
|
* in-use in the open-file bitmap throughout the entire dup2()
|
||||||
|
@ -328,6 +320,8 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case F_DUPFD:
|
case F_DUPFD:
|
||||||
case F_DUPFD_CLOEXEC:
|
case F_DUPFD_CLOEXEC:
|
||||||
|
if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||||
|
break;
|
||||||
get_file(filp);
|
get_file(filp);
|
||||||
err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC);
|
err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -250,9 +250,18 @@ int expand_files(struct files_struct *files, int nr)
|
||||||
struct fdtable *fdt;
|
struct fdtable *fdt;
|
||||||
|
|
||||||
fdt = files_fdtable(files);
|
fdt = files_fdtable(files);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* N.B. For clone tasks sharing a files structure, this test
|
||||||
|
* will limit the total number of files that can be opened.
|
||||||
|
*/
|
||||||
|
if (nr >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||||
|
return -EMFILE;
|
||||||
|
|
||||||
/* Do we need to expand? */
|
/* Do we need to expand? */
|
||||||
if (nr < fdt->max_fds)
|
if (nr < fdt->max_fds)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Can we expand? */
|
/* Can we expand? */
|
||||||
if (nr >= sysctl_nr_open)
|
if (nr >= sysctl_nr_open)
|
||||||
return -EMFILE;
|
return -EMFILE;
|
||||||
|
|
|
@ -972,7 +972,6 @@ int get_unused_fd_flags(int flags)
|
||||||
int fd, error;
|
int fd, error;
|
||||||
struct fdtable *fdt;
|
struct fdtable *fdt;
|
||||||
|
|
||||||
error = -EMFILE;
|
|
||||||
spin_lock(&files->file_lock);
|
spin_lock(&files->file_lock);
|
||||||
|
|
||||||
repeat:
|
repeat:
|
||||||
|
@ -980,13 +979,6 @@ int get_unused_fd_flags(int flags)
|
||||||
fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
|
fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
|
||||||
files->next_fd);
|
files->next_fd);
|
||||||
|
|
||||||
/*
|
|
||||||
* N.B. For clone tasks sharing a files structure, this test
|
|
||||||
* will limit the total number of files that can be opened.
|
|
||||||
*/
|
|
||||||
if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Do we need to expand the fd array or fd set? */
|
/* Do we need to expand the fd array or fd set? */
|
||||||
error = expand_files(files, fd);
|
error = expand_files(files, fd);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
|
@ -997,7 +989,6 @@ int get_unused_fd_flags(int flags)
|
||||||
* If we needed to expand the fs array we
|
* If we needed to expand the fs array we
|
||||||
* might have blocked - try again.
|
* might have blocked - try again.
|
||||||
*/
|
*/
|
||||||
error = -EMFILE;
|
|
||||||
goto repeat;
|
goto repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue