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

Commit 8280d161 authored by Al Viro's avatar Al Viro
Browse files

new helper: replace_fd()



analog of dup2(), except that it takes struct file * as source.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent fe17f22d
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -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};

+62 −29
Original line number Diff line number Diff line
@@ -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
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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 *);