Commit b5287c55 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfs-6.13.exec.deny_write_access.revert' of...

Merge tag 'vfs-6.13.exec.deny_write_access.revert' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull deny_write_access revert from Christian Brauner:
 "It turns out that the mold linker relies on the deny_write_access()
  mechanism for executables.

  The mold linker tries to open a file for writing and if ETXTBSY is
  returned mold falls back to creating a new file"

* tag 'vfs-6.13.exec.deny_write_access.revert' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  Revert "fs: don't block i_writecount during exec"
parents aaf20f87 3b832035
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1257,6 +1257,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
		}
		reloc_func_desc = interp_load_addr;

		allow_write_access(interpreter);
		fput(interpreter);

		kfree(interp_elf_ex);
@@ -1353,6 +1354,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
	kfree(interp_elf_ex);
	kfree(interp_elf_phdata);
out_free_file:
	allow_write_access(interpreter);
	if (interpreter)
		fput(interpreter);
out_free_ph:
+4 −1
Original line number Diff line number Diff line
@@ -394,6 +394,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
			goto error;
		}

		allow_write_access(interpreter);
		fput(interpreter);
		interpreter = NULL;
	}
@@ -465,8 +466,10 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
	retval = 0;

error:
	if (interpreter)
	if (interpreter) {
		allow_write_access(interpreter);
		fput(interpreter);
	}
	kfree(interpreter_name);
	kfree(exec_params.phdrs);
	kfree(exec_params.loadmap);
+5 −2
Original line number Diff line number Diff line
@@ -247,10 +247,13 @@ static int load_misc_binary(struct linux_binprm *bprm)
	if (retval < 0)
		goto ret;

	if (fmt->flags & MISC_FMT_OPEN_FILE)
	if (fmt->flags & MISC_FMT_OPEN_FILE) {
		interp_file = file_clone_open(fmt->interp_file);
	else
		if (!IS_ERR(interp_file))
			deny_write_access(interp_file);
	} else {
		interp_file = open_exec(fmt->interpreter);
	}
	retval = PTR_ERR(interp_file);
	if (IS_ERR(interp_file))
		goto ret;
+15 −8
Original line number Diff line number Diff line
@@ -883,7 +883,8 @@ EXPORT_SYMBOL(transfer_args_to_stack);
 */
static struct file *do_open_execat(int fd, struct filename *name, int flags)
{
	struct file *file;
	int err;
	struct file *file __free(fput) = NULL;
	struct open_flags open_exec_flags = {
		.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
		.acc_mode = MAY_EXEC,
@@ -908,12 +909,14 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
	 * an invariant that all non-regular files error out before we get here.
	 */
	if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) ||
	    path_noexec(&file->f_path)) {
		fput(file);
	    path_noexec(&file->f_path))
		return ERR_PTR(-EACCES);
	}

	return file;
	err = deny_write_access(file);
	if (err)
		return ERR_PTR(err);

	return no_free_ptr(file);
}

/**
@@ -923,7 +926,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
 *
 * Returns ERR_PTR on failure or allocated struct file on success.
 *
 * As this is a wrapper for the internal do_open_execat(). Also see
 * As this is a wrapper for the internal do_open_execat(), callers
 * must call allow_write_access() before fput() on release. Also see
 * do_close_execat().
 */
struct file *open_exec(const char *name)
@@ -1465,7 +1469,9 @@ static int prepare_bprm_creds(struct linux_binprm *bprm)
/* Matches do_open_execat() */
static void do_close_execat(struct file *file)
{
	if (file)
	if (!file)
		return;
	allow_write_access(file);
	fput(file);
}

@@ -1791,6 +1797,7 @@ static int exec_binprm(struct linux_binprm *bprm)
		bprm->file = bprm->interpreter;
		bprm->interpreter = NULL;

		allow_write_access(exec);
		if (unlikely(bprm->have_execfd)) {
			if (bprm->executable) {
				fput(exec);
+23 −3
Original line number Diff line number Diff line
@@ -621,6 +621,12 @@ static void dup_mm_exe_file(struct mm_struct *mm, struct mm_struct *oldmm)

	exe_file = get_mm_exe_file(oldmm);
	RCU_INIT_POINTER(mm->exe_file, exe_file);
	/*
	 * We depend on the oldmm having properly denied write access to the
	 * exe_file already.
	 */
	if (exe_file && deny_write_access(exe_file))
		pr_warn_once("deny_write_access() failed in %s\n", __func__);
}

#ifdef CONFIG_MMU
@@ -1413,11 +1419,20 @@ int set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
	 */
	old_exe_file = rcu_dereference_raw(mm->exe_file);

	if (new_exe_file)
	if (new_exe_file) {
		/*
		 * We expect the caller (i.e., sys_execve) to already denied
		 * write access, so this is unlikely to fail.
		 */
		if (unlikely(deny_write_access(new_exe_file)))
			return -EACCES;
		get_file(new_exe_file);
	}
	rcu_assign_pointer(mm->exe_file, new_exe_file);
	if (old_exe_file)
	if (old_exe_file) {
		allow_write_access(old_exe_file);
		fput(old_exe_file);
	}
	return 0;
}

@@ -1456,6 +1471,9 @@ int replace_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
			return ret;
	}

	ret = deny_write_access(new_exe_file);
	if (ret)
		return -EACCES;
	get_file(new_exe_file);

	/* set the new file */
@@ -1464,8 +1482,10 @@ int replace_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
	rcu_assign_pointer(mm->exe_file, new_exe_file);
	mmap_write_unlock(mm);

	if (old_exe_file)
	if (old_exe_file) {
		allow_write_access(old_exe_file);
		fput(old_exe_file);
	}
	return 0;
}