Loading fs/exec.c +1 −10 Original line number Diff line number Diff line Loading @@ -2041,23 +2041,14 @@ static void wait_for_dump_helpers(struct file *file) static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) { struct file *files[2]; struct fdtable *fdt; struct coredump_params *cp = (struct coredump_params *)info->data; struct files_struct *cf = current->files; int err = create_pipe_files(files, 0); if (err) return err; cp->file = files[1]; sys_close(0); fd_install(0, files[0]); spin_lock(&cf->file_lock); fdt = files_fdtable(cf); __set_open_fd(0, fdt); __clear_close_on_exec(0, fdt); spin_unlock(&cf->file_lock); replace_fd(0, files[0], 0); /* and disallow core files too */ current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; Loading fs/file.c +62 −29 Original line number Diff line number Diff line Loading @@ -821,29 +821,12 @@ bool get_close_on_exec(unsigned int fd) return res; } SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) static int do_dup2(struct files_struct *files, struct file *file, unsigned fd, unsigned flags) { int err = -EBADF; struct file * file, *tofree; struct files_struct * files = current->files; struct file *tofree; struct fdtable *fdt; if ((flags & ~O_CLOEXEC) != 0) return -EINVAL; if (newfd >= rlimit(RLIMIT_NOFILE)) return -EMFILE; spin_lock(&files->file_lock); err = expand_files(files, newfd); file = fcheck(oldfd); if (unlikely(!file)) goto Ebadf; if (unlikely(err < 0)) { if (err == -EMFILE) goto Ebadf; goto out_unlock; } /* * We need to detect attempts to do dup2() over allocated but still * not finished descriptor. NB: OpenBSD avoids that at the price of Loading @@ -858,24 +841,74 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) * scope of POSIX or SUS, since neither considers shared descriptor * tables and this condition does not arise without those. */ err = -EBUSY; fdt = files_fdtable(files); tofree = fdt->fd[newfd]; if (!tofree && fd_is_open(newfd, fdt)) goto out_unlock; tofree = fdt->fd[fd]; if (!tofree && fd_is_open(fd, fdt)) goto Ebusy; get_file(file); rcu_assign_pointer(fdt->fd[newfd], file); __set_open_fd(newfd, fdt); rcu_assign_pointer(fdt->fd[fd], file); __set_open_fd(fd, fdt); if (flags & O_CLOEXEC) __set_close_on_exec(newfd, fdt); __set_close_on_exec(fd, fdt); else __clear_close_on_exec(newfd, fdt); __clear_close_on_exec(fd, fdt); spin_unlock(&files->file_lock); if (tofree) filp_close(tofree, files); return newfd; return fd; Ebusy: spin_unlock(&files->file_lock); return -EBUSY; } int replace_fd(unsigned fd, struct file *file, unsigned flags) { int err; struct files_struct *files = current->files; if (!file) return __close_fd(files, fd); if (fd >= rlimit(RLIMIT_NOFILE)) return -EMFILE; spin_lock(&files->file_lock); err = expand_files(files, fd); if (unlikely(err < 0)) goto out_unlock; return do_dup2(files, file, fd, flags); out_unlock: spin_unlock(&files->file_lock); return err; } SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) { int err = -EBADF; struct file *file; struct files_struct *files = current->files; if ((flags & ~O_CLOEXEC) != 0) return -EINVAL; if (newfd >= rlimit(RLIMIT_NOFILE)) return -EMFILE; spin_lock(&files->file_lock); err = expand_files(files, newfd); file = fcheck(oldfd); if (unlikely(!file)) goto Ebadf; if (unlikely(err < 0)) { if (err == -EMFILE) goto Ebadf; goto out_unlock; } return do_dup2(files, file, newfd, flags); Ebadf: err = -EBADF; Loading include/linux/file.h +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ extern struct file *fget_light(unsigned int fd, int *fput_needed); extern struct file *fget_raw(unsigned int fd); extern struct file *fget_raw_light(unsigned int fd, int *fput_needed); extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); extern int replace_fd(unsigned fd, struct file *file, unsigned flags); extern void set_close_on_exec(unsigned int fd, int flag); extern bool get_close_on_exec(unsigned int fd); extern void put_filp(struct file *); Loading Loading
fs/exec.c +1 −10 Original line number Diff line number Diff line Loading @@ -2041,23 +2041,14 @@ static void wait_for_dump_helpers(struct file *file) static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) { struct file *files[2]; struct fdtable *fdt; struct coredump_params *cp = (struct coredump_params *)info->data; struct files_struct *cf = current->files; int err = create_pipe_files(files, 0); if (err) return err; cp->file = files[1]; sys_close(0); fd_install(0, files[0]); spin_lock(&cf->file_lock); fdt = files_fdtable(cf); __set_open_fd(0, fdt); __clear_close_on_exec(0, fdt); spin_unlock(&cf->file_lock); replace_fd(0, files[0], 0); /* and disallow core files too */ current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; Loading
fs/file.c +62 −29 Original line number Diff line number Diff line Loading @@ -821,29 +821,12 @@ bool get_close_on_exec(unsigned int fd) return res; } SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) static int do_dup2(struct files_struct *files, struct file *file, unsigned fd, unsigned flags) { int err = -EBADF; struct file * file, *tofree; struct files_struct * files = current->files; struct file *tofree; struct fdtable *fdt; if ((flags & ~O_CLOEXEC) != 0) return -EINVAL; if (newfd >= rlimit(RLIMIT_NOFILE)) return -EMFILE; spin_lock(&files->file_lock); err = expand_files(files, newfd); file = fcheck(oldfd); if (unlikely(!file)) goto Ebadf; if (unlikely(err < 0)) { if (err == -EMFILE) goto Ebadf; goto out_unlock; } /* * We need to detect attempts to do dup2() over allocated but still * not finished descriptor. NB: OpenBSD avoids that at the price of Loading @@ -858,24 +841,74 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) * scope of POSIX or SUS, since neither considers shared descriptor * tables and this condition does not arise without those. */ err = -EBUSY; fdt = files_fdtable(files); tofree = fdt->fd[newfd]; if (!tofree && fd_is_open(newfd, fdt)) goto out_unlock; tofree = fdt->fd[fd]; if (!tofree && fd_is_open(fd, fdt)) goto Ebusy; get_file(file); rcu_assign_pointer(fdt->fd[newfd], file); __set_open_fd(newfd, fdt); rcu_assign_pointer(fdt->fd[fd], file); __set_open_fd(fd, fdt); if (flags & O_CLOEXEC) __set_close_on_exec(newfd, fdt); __set_close_on_exec(fd, fdt); else __clear_close_on_exec(newfd, fdt); __clear_close_on_exec(fd, fdt); spin_unlock(&files->file_lock); if (tofree) filp_close(tofree, files); return newfd; return fd; Ebusy: spin_unlock(&files->file_lock); return -EBUSY; } int replace_fd(unsigned fd, struct file *file, unsigned flags) { int err; struct files_struct *files = current->files; if (!file) return __close_fd(files, fd); if (fd >= rlimit(RLIMIT_NOFILE)) return -EMFILE; spin_lock(&files->file_lock); err = expand_files(files, fd); if (unlikely(err < 0)) goto out_unlock; return do_dup2(files, file, fd, flags); out_unlock: spin_unlock(&files->file_lock); return err; } SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) { int err = -EBADF; struct file *file; struct files_struct *files = current->files; if ((flags & ~O_CLOEXEC) != 0) return -EINVAL; if (newfd >= rlimit(RLIMIT_NOFILE)) return -EMFILE; spin_lock(&files->file_lock); err = expand_files(files, newfd); file = fcheck(oldfd); if (unlikely(!file)) goto Ebadf; if (unlikely(err < 0)) { if (err == -EMFILE) goto Ebadf; goto out_unlock; } return do_dup2(files, file, newfd, flags); Ebadf: err = -EBADF; Loading
include/linux/file.h +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ extern struct file *fget_light(unsigned int fd, int *fput_needed); extern struct file *fget_raw(unsigned int fd); extern struct file *fget_raw_light(unsigned int fd, int *fput_needed); extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); extern int replace_fd(unsigned fd, struct file *file, unsigned flags); extern void set_close_on_exec(unsigned int fd, int flag); extern bool get_close_on_exec(unsigned int fd); extern void put_filp(struct file *); Loading