mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
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>
This commit is contained in:
parent
fa1bdca98d
commit
3a3f61ce5e
12
fs/exec.c
12
fs/exec.c
@ -1200,16 +1200,16 @@ char *__get_task_comm(char *buf, size_t buf_size, struct task_struct *tsk)
|
|||||||
EXPORT_SYMBOL_GPL(__get_task_comm);
|
EXPORT_SYMBOL_GPL(__get_task_comm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These functions flushes out all traces of the currently running executable
|
* This is unlocked -- the string will always be NUL-terminated, but
|
||||||
* so that a new one can be started
|
* may show overlapping contents if racing concurrent reads.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
|
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);
|
trace_task_rename(tsk, buf);
|
||||||
strscpy_pad(tsk->comm, buf, sizeof(tsk->comm));
|
memcpy(tsk->comm, buf, len);
|
||||||
task_unlock(tsk);
|
memset(&tsk->comm[len], 0, sizeof(tsk->comm) - len);
|
||||||
perf_event_comm(tsk, exec);
|
perf_event_comm(tsk, exec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1932,11 +1932,10 @@ static inline void kick_process(struct task_struct *tsk) { }
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec);
|
extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec);
|
||||||
|
#define set_task_comm(tsk, from) ({ \
|
||||||
static inline void set_task_comm(struct task_struct *tsk, const char *from)
|
BUILD_BUG_ON(sizeof(from) != TASK_COMM_LEN); \
|
||||||
{
|
__set_task_comm(tsk, from, false); \
|
||||||
__set_task_comm(tsk, from, false);
|
})
|
||||||
}
|
|
||||||
|
|
||||||
extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk);
|
extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk);
|
||||||
#define get_task_comm(buf, tsk) ({ \
|
#define get_task_comm(buf, tsk) ({ \
|
||||||
|
@ -634,7 +634,7 @@ static int io_wq_worker(void *data)
|
|||||||
struct io_wq_acct *acct = io_wq_get_acct(worker);
|
struct io_wq_acct *acct = io_wq_get_acct(worker);
|
||||||
struct io_wq *wq = worker->wq;
|
struct io_wq *wq = worker->wq;
|
||||||
bool exit_mask = false, last_timeout = false;
|
bool exit_mask = false, last_timeout = false;
|
||||||
char buf[TASK_COMM_LEN];
|
char buf[TASK_COMM_LEN] = {};
|
||||||
|
|
||||||
set_mask_bits(&worker->flags, 0,
|
set_mask_bits(&worker->flags, 0,
|
||||||
BIT(IO_WORKER_F_UP) | BIT(IO_WORKER_F_RUNNING));
|
BIT(IO_WORKER_F_UP) | BIT(IO_WORKER_F_RUNNING));
|
||||||
|
@ -271,7 +271,7 @@ static int io_sq_thread(void *data)
|
|||||||
struct io_ring_ctx *ctx;
|
struct io_ring_ctx *ctx;
|
||||||
struct rusage start;
|
struct rusage start;
|
||||||
unsigned long timeout = 0;
|
unsigned long timeout = 0;
|
||||||
char buf[TASK_COMM_LEN];
|
char buf[TASK_COMM_LEN] = {};
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT(wait);
|
||||||
|
|
||||||
/* offload context creation failed, just exit */
|
/* offload context creation failed, just exit */
|
||||||
|
@ -736,10 +736,11 @@ EXPORT_SYMBOL(kthread_stop_put);
|
|||||||
|
|
||||||
int kthreadd(void *unused)
|
int kthreadd(void *unused)
|
||||||
{
|
{
|
||||||
|
static const char comm[TASK_COMM_LEN] = "kthreadd";
|
||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
|
|
||||||
/* Setup a clean context for our children to inherit. */
|
/* Setup a clean context for our children to inherit. */
|
||||||
set_task_comm(tsk, "kthreadd");
|
set_task_comm(tsk, comm);
|
||||||
ignore_signals(tsk);
|
ignore_signals(tsk);
|
||||||
set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_TYPE_KTHREAD));
|
set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_TYPE_KTHREAD));
|
||||||
set_mems_allowed(node_states[N_MEMORY]);
|
set_mems_allowed(node_states[N_MEMORY]);
|
||||||
|
Loading…
Reference in New Issue
Block a user