Skip to content

Commit fadc3ed

Browse files
committed
Merge tag 'execve-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
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
2 parents 0eb4aaa + 55cf2f4 commit fadc3ed

File tree

11 files changed

+125
-44
lines changed

11 files changed

+125
-44
lines changed

MAINTAINERS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8548,8 +8548,8 @@ F: rust/kernel/net/phy.rs
85488548
F: rust/kernel/net/phy/reg.rs
85498549

85508550
EXEC & BINFMT API, ELF
8551+
M: Kees Cook <kees@kernel.org>
85518552
R: Eric Biederman <ebiederm@xmission.com>
8552-
R: Kees Cook <kees@kernel.org>
85538553
L: linux-mm@kvack.org
85548554
S: Supported
85558555
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
85618561
F: fs/tests/exec_kunit.c
85628562
F: include/linux/binfmts.h
85638563
F: include/linux/elf.h
8564+
F: include/uapi/linux/auxvec.h
85648565
F: include/uapi/linux/binfmts.h
85658566
F: include/uapi/linux/elf.h
85668567
F: tools/testing/selftests/exec/

fs/binfmt_flat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ static int load_flat_file(struct linux_binprm *bprm,
478478
* 28 bits (256 MB) is way more than reasonable in this case.
479479
* If some top bits are set we have probable binary corruption.
480480
*/
481-
if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) {
481+
if ((text_len | data_len | bss_len | stack_len | relocs | full_data) >> 28) {
482482
pr_err("bad header\n");
483483
ret = -ENOEXEC;
484484
goto err;

fs/binfmt_misc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,7 @@ static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
10011001
/*
10021002
* If it turns out that most user namespaces actually want to
10031003
* register their own binary type handler and therefore all
1004-
* create their own separate binfm_misc mounts we should
1004+
* create their own separate binfmt_misc mounts we should
10051005
* consider turning this into a kmem cache.
10061006
*/
10071007
misc = kzalloc(sizeof(struct binfmt_misc), GFP_KERNEL);

fs/exec.c

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,16 +1194,16 @@ static int unshare_sighand(struct task_struct *me)
11941194
}
11951195

11961196
/*
1197-
* These functions flushes out all traces of the currently running executable
1198-
* so that a new one can be started
1197+
* This is unlocked -- the string will always be NUL-terminated, but
1198+
* may show overlapping contents if racing concurrent reads.
11991199
*/
1200-
12011200
void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
12021201
{
1203-
task_lock(tsk);
1202+
size_t len = min(strlen(buf), sizeof(tsk->comm) - 1);
1203+
12041204
trace_task_rename(tsk, buf);
1205-
strscpy_pad(tsk->comm, buf, sizeof(tsk->comm));
1206-
task_unlock(tsk);
1205+
memcpy(tsk->comm, buf, len);
1206+
memset(&tsk->comm[len], 0, sizeof(tsk->comm) - len);
12071207
perf_event_comm(tsk, exec);
12081208
}
12091209

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

13431343
perf_event_exec();
1344-
__set_task_comm(me, kbasename(bprm->filename), true);
1344+
1345+
/*
1346+
* If the original filename was empty, alloc_bprm() made up a path
1347+
* that will probably not be useful to admins running ps or similar.
1348+
* Let's fix it up to be something reasonable.
1349+
*/
1350+
if (bprm->comm_from_dentry) {
1351+
/*
1352+
* Hold RCU lock to keep the name from being freed behind our back.
1353+
* Use acquire semantics to make sure the terminating NUL from
1354+
* __d_alloc() is seen.
1355+
*
1356+
* Note, we're deliberately sloppy here. We don't need to care about
1357+
* detecting a concurrent rename and just want a terminated name.
1358+
*/
1359+
rcu_read_lock();
1360+
__set_task_comm(me, smp_load_acquire(&bprm->file->f_path.dentry->d_name.name),
1361+
true);
1362+
rcu_read_unlock();
1363+
} else {
1364+
__set_task_comm(me, kbasename(bprm->filename), true);
1365+
}
13451366

13461367
/* An exec changes our domain. We are no longer part of the thread
13471368
group */
@@ -1517,11 +1538,13 @@ static struct linux_binprm *alloc_bprm(int fd, struct filename *filename, int fl
15171538
if (fd == AT_FDCWD || filename->name[0] == '/') {
15181539
bprm->filename = filename->name;
15191540
} else {
1520-
if (filename->name[0] == '\0')
1541+
if (filename->name[0] == '\0') {
15211542
bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d", fd);
1522-
else
1543+
bprm->comm_from_dentry = 1;
1544+
} else {
15231545
bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d/%s",
15241546
fd, filename->name);
1547+
}
15251548
if (!bprm->fdpath)
15261549
goto out_free;
15271550

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

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

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

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

1759-
if (need_retry) {
1760-
if (printable(bprm->buf[0]) && printable(bprm->buf[1]) &&
1761-
printable(bprm->buf[2]) && printable(bprm->buf[3]))
1762-
return retval;
1763-
if (request_module("binfmt-%04x", *(ushort *)(bprm->buf + 2)) < 0)
1764-
return retval;
1765-
need_retry = false;
1766-
goto retry;
1767-
}
1768-
1769-
return retval;
1778+
return -ENOEXEC;
17701779
}
17711780

17721781
/* 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,
19041913
}
19051914

19061915
retval = count(argv, MAX_ARG_STRINGS);
1907-
if (retval == 0)
1908-
pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
1909-
current->comm, bprm->filename);
19101916
if (retval < 0)
19111917
goto out_free;
19121918
bprm->argc = retval;
@@ -1944,6 +1950,9 @@ static int do_execveat_common(int fd, struct filename *filename,
19441950
if (retval < 0)
19451951
goto out_free;
19461952
bprm->argc = 1;
1953+
1954+
pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
1955+
current->comm, bprm->filename);
19471956
}
19481957

19491958
retval = bprm_execve(bprm);

include/linux/binfmts.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ struct linux_binprm {
4242
* Set when errors can no longer be returned to the
4343
* original userspace.
4444
*/
45-
point_of_no_return:1;
45+
point_of_no_return:1,
46+
/* Set when "comm" must come from the dentry. */
47+
comm_from_dentry:1;
4648
struct file *executable; /* Executable to pass to the interpreter */
4749
struct file *interpreter;
4850
struct file *file;

include/linux/coredump.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ extern void do_coredump(const kernel_siginfo_t *siginfo);
5252
#define __COREDUMP_PRINTK(Level, Format, ...) \
5353
do { \
5454
char comm[TASK_COMM_LEN]; \
55-
\
56-
get_task_comm(comm, current); \
55+
/* This will always be NUL terminated. */ \
56+
memcpy(comm, current->comm, sizeof(comm)); \
5757
printk_ratelimited(Level "coredump: %d(%*pE): " Format "\n", \
5858
task_tgid_vnr(current), (int)strlen(comm), comm, ##__VA_ARGS__); \
5959
} while (0) \

include/linux/sched.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,11 +1944,10 @@ static inline void kick_process(struct task_struct *tsk) { }
19441944
#endif
19451945

19461946
extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec);
1947-
1948-
static inline void set_task_comm(struct task_struct *tsk, const char *from)
1949-
{
1950-
__set_task_comm(tsk, from, false);
1951-
}
1947+
#define set_task_comm(tsk, from) ({ \
1948+
BUILD_BUG_ON(sizeof(from) != TASK_COMM_LEN); \
1949+
__set_task_comm(tsk, from, false); \
1950+
})
19521951

19531952
/*
19541953
* - Why not use task_lock()?

io_uring/io-wq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ static int io_wq_worker(void *data)
634634
struct io_wq_acct *acct = io_wq_get_acct(worker);
635635
struct io_wq *wq = worker->wq;
636636
bool exit_mask = false, last_timeout = false;
637-
char buf[TASK_COMM_LEN];
637+
char buf[TASK_COMM_LEN] = {};
638638

639639
set_mask_bits(&worker->flags, 0,
640640
BIT(IO_WORKER_F_UP) | BIT(IO_WORKER_F_RUNNING));

io_uring/sqpoll.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ static int io_sq_thread(void *data)
264264
struct io_ring_ctx *ctx;
265265
struct rusage start;
266266
unsigned long timeout = 0;
267-
char buf[TASK_COMM_LEN];
267+
char buf[TASK_COMM_LEN] = {};
268268
DEFINE_WAIT(wait);
269269

270270
/* offload context creation failed, just exit */

kernel/kthread.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,10 +738,11 @@ EXPORT_SYMBOL(kthread_stop_put);
738738

739739
int kthreadd(void *unused)
740740
{
741+
static const char comm[TASK_COMM_LEN] = "kthreadd";
741742
struct task_struct *tsk = current;
742743

743744
/* Setup a clean context for our children to inherit. */
744-
set_task_comm(tsk, "kthreadd");
745+
set_task_comm(tsk, comm);
745746
ignore_signals(tsk);
746747
set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_TYPE_KTHREAD));
747748
set_mems_allowed(node_states[N_MEMORY]);

0 commit comments

Comments
 (0)