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

Commit fd8328be authored by Al Viro's avatar Al Viro
Browse files

[PATCH] sanitize handling of shared descriptor tables in failing execve()



* unshare_files() can fail; doing it after irreversible actions is wrong
  and de_thread() is certainly irreversible.
* since we do it unconditionally anyway, we might as well do it in do_execve()
  and save ourselves the PITA in binfmt handlers, etc.
* while we are at it, binfmt_som actually leaked files_struct on failure.

As a side benefit, unshare_files(), put_files_struct() and reset_files_struct()
become unexported.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6b335d9c
Loading
Loading
Loading
Loading
+1 −22
Original line number Diff line number Diff line
@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
	unsigned long interp_load_addr = 0;
	unsigned long start_code, end_code, start_data, end_data;
	unsigned long reloc_func_desc = 0;
	struct files_struct *files;
	int executable_stack = EXSTACK_DEFAULT;
	unsigned long def_flags = 0;
	struct {
@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
		goto out_free_ph;
	}

	files = current->files;	/* Refcounted so ok */
	retval = unshare_files();
	if (retval < 0)
		goto out_free_ph;
	if (files == current->files) {
		put_files_struct(files);
		files = NULL;
	}

	/* exec will make our files private anyway, but for the a.out
	   loader stuff we need to do it earlier */
	retval = get_unused_fd();
	if (retval < 0)
		goto out_free_fh;
		goto out_free_ph;
	get_file(bprm->file);
	fd_install(elf_exec_fileno = retval, bprm->file);

@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
	if (retval)
		goto out_free_dentry;

	/* Discard our unneeded old files struct */
	if (files) {
		put_files_struct(files);
		files = NULL;
	}

	/* OK, This is the point of no return */
	current->flags &= ~PF_FORKNOEXEC;
	current->mm->def_flags = def_flags;
@@ -1016,9 +998,6 @@ out_free_interp:
	kfree(elf_interpreter);
out_free_file:
	sys_close(elf_exec_fileno);
out_free_fh:
	if (files)
		reset_files_struct(current, files);
out_free_ph:
	kfree(elf_phdata);
	goto out;
+1 −17
Original line number Diff line number Diff line
@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
	char *iname_addr = iname;
	int retval;
	int fd_binary = -1;
	struct files_struct *files = NULL;

	retval = -ENOEXEC;
	if (!enabled)
@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)

	if (fmt->flags & MISC_FMT_OPEN_BINARY) {

		files = current->files;
		retval = unshare_files();
		if (retval < 0)
			goto _ret;
		if (files == current->files) {
			put_files_struct(files);
			files = NULL;
		}
		/* if the binary should be opened on behalf of the
		 * interpreter than keep it open and assign descriptor
		 * to it */
 		fd_binary = get_unused_fd();
 		if (fd_binary < 0) {
 			retval = fd_binary;
 			goto _unshare;
 			goto _ret;
 		}
 		fd_install(fd_binary, bprm->file);

@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
	if (retval < 0)
		goto _error;

	if (files) {
		put_files_struct(files);
		files = NULL;
	}
_ret:
	return retval;
_error:
@@ -216,9 +203,6 @@ _error:
		sys_close(fd_binary);
	bprm->interp_flags = 0;
	bprm->interp_data = 0;
_unshare:
	if (files)
		reset_files_struct(current, files);
	goto _ret;
}

+0 −10
Original line number Diff line number Diff line
@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
	unsigned long som_entry;
	struct som_hdr *som_ex;
	struct som_exec_auxhdr *hpuxhdr;
	struct files_struct *files;

	/* Get the exec-header */
	som_ex = (struct som_hdr *) bprm->buf;
@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
		goto out_free;
	}

	files = current->files; /* Refcounted so ok */
	retval = unshare_files();
	if (retval < 0)
		goto out_free;
	if (files == current->files) {
		put_files_struct(files);
		files = NULL;
	}

	retval = get_unused_fd();
	if (retval < 0)
		goto out_free;
+18 −16
Original line number Diff line number Diff line
@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm)
{
	char * name;
	int i, ch, retval;
	struct files_struct *files;
	char tcomm[sizeof(current->comm)];

	/*
@@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm)
	if (retval)
		goto out;

	/*
	 * Make sure we have private file handles. Ask the
	 * fork helper to do the work for us and the exit
	 * helper to do the cleanup of the old one.
	 */
	files = current->files;		/* refcounted so safe to hold */
	retval = unshare_files();
	if (retval)
		goto out;
	/*
	 * Release all of the old mmap stuff
	 */
	retval = exec_mmap(bprm->mm);
	if (retval)
		goto mmap_failed;
		goto out;

	bprm->mm = NULL;		/* We're using it now */

	/* This is the point of no return */
	put_files_struct(files);

	current->sas_ss_sp = current->sas_ss_size = 0;

	if (current->euid == current->uid && current->egid == current->gid)
@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm)

	return 0;

mmap_failed:
	reset_files_struct(current, files);
out:
	return retval;
}
@@ -1283,12 +1269,23 @@ int do_execve(char * filename,
	struct linux_binprm *bprm;
	struct file *file;
	unsigned long env_p;
	struct files_struct *files;
	int retval;

	files = current->files;
	retval = unshare_files();
	if (retval)
		goto out_ret;

	if (files == current->files) {
		put_files_struct(files);
		files = NULL;
	}

	retval = -ENOMEM;
	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
	if (!bprm)
		goto out_ret;
		goto out_files;

	file = open_exec(filename);
	retval = PTR_ERR(file);
@@ -1343,6 +1340,8 @@ int do_execve(char * filename,
		security_bprm_free(bprm);
		acct_update_integrals(current);
		kfree(bprm);
		if (files)
			put_files_struct(files);
		return retval;
	}

@@ -1363,6 +1362,9 @@ out_file:
out_kfree:
	kfree(bprm);

out_files:
	if (files)
		reset_files_struct(current, files);
out_ret:
	return retval;
}
+0 −3
Original line number Diff line number Diff line
@@ -507,8 +507,6 @@ void put_files_struct(struct files_struct *files)
	}
}

EXPORT_SYMBOL(put_files_struct);

void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
{
	struct files_struct *old;
@@ -519,7 +517,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
	task_unlock(tsk);
	put_files_struct(old);
}
EXPORT_SYMBOL(reset_files_struct);

void exit_files(struct task_struct *tsk)
{
Loading