Commit 4e1e018e authored by Al Viro's avatar Al Viro

[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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6c5d0512
...@@ -64,11 +64,6 @@ static int locate_fd(unsigned int orig_start, int cloexec) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
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