Commit fadc3ed9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull execve updates from Kees Cook:

 - fix up /proc/pid/comm in the execveat(AT_EMPTY_PATH) case (Tycho
   Andersen, Kees Cook)

 - binfmt_misc: Fix comment typos (Christophe JAILLET)

 - move empty argv[0] warning closer to actual logic (Nir Lichtman)

 - remove legacy custom binfmt modules autoloading (Nir Lichtman)

 - Make sure set_task_comm() always NUL-terminates

 - binfmt_flat: Fix integer overflow bug on 32 bit systems (Dan
   Carpenter)

 - coredump: Do not lock when copying "comm"

 - MAINTAINERS: add auxvec.h and set myself as maintainer

* tag 'execve-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  binfmt_flat: Fix integer overflow bug on 32 bit systems
  selftests/exec: add a test for execveat()'s comm
  exec: fix up /proc/pid/comm in the execveat(AT_EMPTY_PATH) case
  exec: Make sure task->comm is always NUL-terminated
  exec: remove legacy custom binfmt modules autoloading
  exec: move warning of null argv to be next to the relevant code
  fs: binfmt: Fix a typo
  MAINTAINERS: exec: Mark Kees as maintainer
  MAINTAINERS: exec: Add auxvec.h UAPI
  coredump: Do not lock during 'comm' reporting
parents 0eb4aaa2 55cf2f4b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -8548,8 +8548,8 @@ F: rust/kernel/net/phy.rs
F:	rust/kernel/net/phy/reg.rs
EXEC & BINFMT API, ELF
M:	Kees Cook <kees@kernel.org>
R:	Eric Biederman <ebiederm@xmission.com>
R:	Kees Cook <kees@kernel.org>
L:	linux-mm@kvack.org
S:	Supported
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/execve
@@ -8561,6 +8561,7 @@ F: fs/tests/binfmt_*_kunit.c
F:	fs/tests/exec_kunit.c
F:	include/linux/binfmts.h
F:	include/linux/elf.h
F:	include/uapi/linux/auxvec.h
F:	include/uapi/linux/binfmts.h
F:	include/uapi/linux/elf.h
F:	tools/testing/selftests/exec/
+1 −1
Original line number Diff line number Diff line
@@ -478,7 +478,7 @@ static int load_flat_file(struct linux_binprm *bprm,
	 * 28 bits (256 MB) is way more than reasonable in this case.
	 * If some top bits are set we have probable binary corruption.
	*/
	if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) {
	if ((text_len | data_len | bss_len | stack_len | relocs | full_data) >> 28) {
		pr_err("bad header\n");
		ret = -ENOEXEC;
		goto err;
+1 −1
Original line number Diff line number Diff line
@@ -1001,7 +1001,7 @@ static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
		/*
		 * If it turns out that most user namespaces actually want to
		 * register their own binary type handler and therefore all
		 * create their own separate binfm_misc mounts we should
		 * create their own separate binfmt_misc mounts we should
		 * consider turning this into a kmem cache.
		 */
		misc = kzalloc(sizeof(struct binfmt_misc), GFP_KERNEL);
+36 −27
Original line number Diff line number Diff line
@@ -1194,16 +1194,16 @@ static int unshare_sighand(struct task_struct *me)
}

/*
 * These functions flushes out all traces of the currently running executable
 * so that a new one can be started
 * This is unlocked -- the string will always be NUL-terminated, but
 * may show overlapping contents if racing concurrent reads.
 */

void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
{
	task_lock(tsk);
	size_t len = min(strlen(buf), sizeof(tsk->comm) - 1);

	trace_task_rename(tsk, buf);
	strscpy_pad(tsk->comm, buf, sizeof(tsk->comm));
	task_unlock(tsk);
	memcpy(tsk->comm, buf, len);
	memset(&tsk->comm[len], 0, sizeof(tsk->comm) - len);
	perf_event_comm(tsk, exec);
}

@@ -1341,7 +1341,28 @@ int begin_new_exec(struct linux_binprm * bprm)
		set_dumpable(current->mm, SUID_DUMP_USER);

	perf_event_exec();

	/*
	 * If the original filename was empty, alloc_bprm() made up a path
	 * that will probably not be useful to admins running ps or similar.
	 * Let's fix it up to be something reasonable.
	 */
	if (bprm->comm_from_dentry) {
		/*
		 * Hold RCU lock to keep the name from being freed behind our back.
		 * Use acquire semantics to make sure the terminating NUL from
		 * __d_alloc() is seen.
		 *
		 * Note, we're deliberately sloppy here. We don't need to care about
		 * detecting a concurrent rename and just want a terminated name.
		 */
		rcu_read_lock();
		__set_task_comm(me, smp_load_acquire(&bprm->file->f_path.dentry->d_name.name),
				true);
		rcu_read_unlock();
	} else {
		__set_task_comm(me, kbasename(bprm->filename), true);
	}

	/* An exec changes our domain. We are no longer part of the thread
	   group */
@@ -1517,11 +1538,13 @@ static struct linux_binprm *alloc_bprm(int fd, struct filename *filename, int fl
	if (fd == AT_FDCWD || filename->name[0] == '/') {
		bprm->filename = filename->name;
	} else {
		if (filename->name[0] == '\0')
		if (filename->name[0] == '\0') {
			bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d", fd);
		else
			bprm->comm_from_dentry = 1;
		} else {
			bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d/%s",
						  fd, filename->name);
		}
		if (!bprm->fdpath)
			goto out_free;

@@ -1719,13 +1742,11 @@ int remove_arg_zero(struct linux_binprm *bprm)
}
EXPORT_SYMBOL(remove_arg_zero);

#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
/*
 * cycle the list of binary formats handler, until one recognizes the image
 */
static int search_binary_handler(struct linux_binprm *bprm)
{
	bool need_retry = IS_ENABLED(CONFIG_MODULES);
	struct linux_binfmt *fmt;
	int retval;

@@ -1737,8 +1758,6 @@ static int search_binary_handler(struct linux_binprm *bprm)
	if (retval)
		return retval;

	retval = -ENOENT;
 retry:
	read_lock(&binfmt_lock);
	list_for_each_entry(fmt, &formats, lh) {
		if (!try_module_get(fmt->module))
@@ -1756,17 +1775,7 @@ static int search_binary_handler(struct linux_binprm *bprm)
	}
	read_unlock(&binfmt_lock);

	if (need_retry) {
		if (printable(bprm->buf[0]) && printable(bprm->buf[1]) &&
		    printable(bprm->buf[2]) && printable(bprm->buf[3]))
			return retval;
		if (request_module("binfmt-%04x", *(ushort *)(bprm->buf + 2)) < 0)
			return retval;
		need_retry = false;
		goto retry;
	}

	return retval;
	return -ENOEXEC;
}

/* binfmt handlers will call back into begin_new_exec() on success. */
@@ -1904,9 +1913,6 @@ static int do_execveat_common(int fd, struct filename *filename,
	}

	retval = count(argv, MAX_ARG_STRINGS);
	if (retval == 0)
		pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
			     current->comm, bprm->filename);
	if (retval < 0)
		goto out_free;
	bprm->argc = retval;
@@ -1944,6 +1950,9 @@ static int do_execveat_common(int fd, struct filename *filename,
		if (retval < 0)
			goto out_free;
		bprm->argc = 1;

		pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
			     current->comm, bprm->filename);
	}

	retval = bprm_execve(bprm);
+3 −1
Original line number Diff line number Diff line
@@ -42,7 +42,9 @@ struct linux_binprm {
		 * Set when errors can no longer be returned to the
		 * original userspace.
		 */
		point_of_no_return:1;
		point_of_no_return:1,
		/* Set when "comm" must come from the dentry. */
		comm_from_dentry:1;
	struct file *executable; /* Executable to pass to the interpreter */
	struct file *interpreter;
	struct file *file;
Loading