Skip to content

Commit 3a3f61c

Browse files
committed
exec: Make sure task->comm is always NUL-terminated
Using strscpy() meant that the final character in task->comm may be non-NUL for a moment before the "string too long" truncation happens. Instead of adding a new use of the ambiguous strncpy(), we'd want to use memtostr_pad() which enforces being able to check at compile time that sizes are sensible, but this requires being able to see string buffer lengths. Instead of trying to inline __set_task_comm() (which needs to call trace and perf functions), just open-code it. But to make sure we're always safe, add compile-time checking like we already do for get_task_comm(). Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Suggested-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Kees Cook <kees@kernel.org>
1 parent fa1bdca commit 3a3f61c

File tree

5 files changed

+14
-14
lines changed

5 files changed

+14
-14
lines changed

fs/exec.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,16 +1200,16 @@ char *__get_task_comm(char *buf, size_t buf_size, struct task_struct *tsk)
12001200
EXPORT_SYMBOL_GPL(__get_task_comm);
12011201

12021202
/*
1203-
* These functions flushes out all traces of the currently running executable
1204-
* so that a new one can be started
1203+
* This is unlocked -- the string will always be NUL-terminated, but
1204+
* may show overlapping contents if racing concurrent reads.
12051205
*/
1206-
12071206
void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
12081207
{
1209-
task_lock(tsk);
1208+
size_t len = min(strlen(buf), sizeof(tsk->comm) - 1);
1209+
12101210
trace_task_rename(tsk, buf);
1211-
strscpy_pad(tsk->comm, buf, sizeof(tsk->comm));
1212-
task_unlock(tsk);
1211+
memcpy(tsk->comm, buf, len);
1212+
memset(&tsk->comm[len], 0, sizeof(tsk->comm) - len);
12131213
perf_event_comm(tsk, exec);
12141214
}
12151215

include/linux/sched.h

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

19341934
extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec);
1935-
1936-
static inline void set_task_comm(struct task_struct *tsk, const char *from)
1937-
{
1938-
__set_task_comm(tsk, from, false);
1939-
}
1935+
#define set_task_comm(tsk, from) ({ \
1936+
BUILD_BUG_ON(sizeof(from) != TASK_COMM_LEN); \
1937+
__set_task_comm(tsk, from, false); \
1938+
})
19401939

19411940
extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk);
19421941
#define get_task_comm(buf, tsk) ({ \

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
@@ -271,7 +271,7 @@ static int io_sq_thread(void *data)
271271
struct io_ring_ctx *ctx;
272272
struct rusage start;
273273
unsigned long timeout = 0;
274-
char buf[TASK_COMM_LEN];
274+
char buf[TASK_COMM_LEN] = {};
275275
DEFINE_WAIT(wait);
276276

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

kernel/kthread.c

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

737737
int kthreadd(void *unused)
738738
{
739+
static const char comm[TASK_COMM_LEN] = "kthreadd";
739740
struct task_struct *tsk = current;
740741

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

0 commit comments

Comments
 (0)