linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/3] Add support for long task name
@ 2025-07-24 12:36 Bhupesh
  2025-07-24 12:36 ` [PATCH v6 1/3] exec: Remove obsolete comments Bhupesh
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Bhupesh @ 2025-07-24 12:36 UTC (permalink / raw)
  To: akpm
  Cc: bhupesh, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, keescook,
	ebiederm, brauner, jack, mingo, juri.lelli, bsegall, mgorman,
	vschneid, linux-trace-kernel, kees, torvalds

Changes since v5:
================
- v5 can be seen here: https://lore.kernel.org/lkml/20250716123916.511889-1-bhupesh@igalia.com/ 
- As suggested by Linus, replaced 'tsk->comm' with 'tsk->comm_str' locally, and verified basic
  thread names and then changed 'tsk->comm_str' back to 'tsk->comm'. So essentially now 'tsk->comm'
  is TASK_COMM_EXT_LEN i.e. 64-bytes long.

Changes since v4:
================
- v4 can be seen here: https://lore.kernel.org/lkml/20250521062337.53262-1-bhupesh@igalia.com/ 
- As suggested by Kees, replaced tsk->comm with tsk->comm_str, inside 'task_struct'
  where TASK_COMM_EXT_LEN is 64-bytes.

Changes since v3:
================
- v3 can be seen here: https://lore.kernel.org/lkml/20250507110444.963779-1-bhupesh@igalia.com/
- As suggested by Petr and Steven, used 'comm_ext' name instead of
  'real_comm'. Correspondingly the macro name is changed to 'TASK_COMM_EXT_LEN'
  for the 64-byte extended comm.
- Rebased this patchset on linux-next/master, which contain the following patch from
  Steven now:
       155fd6c3e2f0 ("tracing/sched: Use __string() instead of fixed lengths for task->comm")
- Accordingly, v4 drops the changes done for 'trace/sched' events in v3,
  but retains the 'safe' memcpy' changes for other kernel trace users.

Changes since v2:
================
- v2 can be seen here: https://lore.kernel.org/lkml/20250331121820.455916-1-bhupesh@igalia.com/
- As suggested by Yafang and Kees, picked Linus' suggested approach for
  this version (see: <https://lore.kernel.org/all/CAHk-=wjAmmHUg6vho1KjzQi2=psR30+CogFd4aXrThr2gsiS4g@mail.gmail.com/>).
- Dropped kthreads patch from this version. It would be sent out
  separately, if we have a consensus on this approach.

Changes since v1:
================
- v1 can be seen here: https://lore.kernel.org/lkml/20250314052715.610377-1-bhupesh@igalia.com/
- As suggested by Kees, added [PATCH 3/3] to have a consistent
  'full_name' entry inside 'task_struct' which both tasks and
  kthreads can use.
- Fixed the commit message to indicate that the existing ABI
  '/proc/$pid/task/$tid/comm' remains untouched and a parallel
  '/proc/$pid/task/$tid/full_name' ABI for new (interested) users.

While working with user-space debugging tools which work especially
on linux gaming platforms, I found that the task name is truncated due
to the limitation of TASK_COMM_LEN.

Now, during debug tracing, seeing truncated names is not very useful,
especially on gaming platforms where the number of tasks running can
be very high.

This patchset does not touch 'TASK_COMM_LEN' at all, i.e.
'TASK_COMM_LEN' and the 16-byte design remains untouched.

Via this patchset, Linus suggested 'tsk->comm' is made 64-byte long
and equal to TASK_COMM_EXT_LEN.

To avoid any surprises / bug,s I replaced 'tsk->comm' with
'tsk->comm_str' locally inside 'task_struct' and checked compilation
of code and basic working of thread names:

       struct task_struct {
	       ..............
               char    comm_str[TASK_COMM_EXT_LEN];
	       ..............
       };

       where TASK_COMM_EXT_LEN is 64-bytes.

Once done, I changed the name back to 'tsk->comm'.

To ensure that the existing ABI and userspace continues to work
as intended, we ensure that:

- Existing users of 'get_task_comm'/ 'set_task_comm' will get 'tsk->comm'
  truncated to a maximum of 'TASK_COMM_LEN' (16-bytes) to maintain ABI,
- New / Modified users of 'get_task_comm'/ 'set_task_comm' will get
 'tsk->comm' supported up to a maximum of 'TASK_COMM_EXT_LEN' (64-bytes).

Note, that the existing users have not been modified to migrate to
'TASK_COMM_EXT_LEN', in case they have hard-coded expectations of
dealing with only a 'TASK_COMM_LEN' long 'tsk->comm_str'.

After this change, gdb is able to show full name of the task, using a
simple app which generates threads with long names [see 1]:
  # gdb ./threadnames -ex "run info thread" -ex "detach" -ex "quit" > log
  # cat log

  NameThatIsTooLongForComm[4662]

[1]. https://github.com/lostgoat/tasknames

Bhupesh (3):
  exec: Remove obsolete comments
  treewide: Switch memcpy() users of 'task->comm' to a more safer
    implementation
  include: Set tsk->comm length to 64 bytes

 include/linux/coredump.h       |  3 ++-
 include/linux/sched.h          | 15 +++++++++------
 include/trace/events/block.h   |  5 +++++
 include/trace/events/oom.h     |  1 +
 include/trace/events/osnoise.h |  1 +
 include/trace/events/signal.h  |  1 +
 include/trace/events/task.h    |  2 ++
 7 files changed, 21 insertions(+), 7 deletions(-)

-- 
2.38.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v6 1/3] exec: Remove obsolete comments
  2025-07-24 12:36 [PATCH v6 0/3] Add support for long task name Bhupesh
@ 2025-07-24 12:36 ` Bhupesh
  2025-07-24 23:50   ` Kees Cook
  2025-07-24 12:36 ` [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation Bhupesh
  2025-07-24 12:36 ` [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes Bhupesh
  2 siblings, 1 reply; 12+ messages in thread
From: Bhupesh @ 2025-07-24 12:36 UTC (permalink / raw)
  To: akpm
  Cc: bhupesh, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, keescook,
	ebiederm, brauner, jack, mingo, juri.lelli, bsegall, mgorman,
	vschneid, linux-trace-kernel, kees, torvalds

Patch 3a3f61ce5e0b ("exec: Make sure task->comm is always NUL-terminated"),
replaced 'strscpy_pad()' with 'memcpy()' implementations inside
'__set_task_comm()'.

However a few left-over comments are still there, which mention
the usage of 'strscpy_pad()' inside '__set_task_comm()'.

Remove those obsolete comments.

While at it, also remove an obsolete comment regarding 'task_lock()'
usage while handing 'task->comm'.

Signed-off-by: Bhupesh <bhupesh@igalia.com>
---
 include/linux/sched.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 84449f847256..8bbd03f1b978 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1156,10 +1156,8 @@ struct task_struct {
 	 *
 	 * - normally initialized begin_new_exec()
 	 * - set it with set_task_comm()
-	 *   - strscpy_pad() to ensure it is always NUL-terminated and
+	 *   - logic inside set_task_comm() will ensure it is always NUL-terminated and
 	 *     zero-padded
-	 *   - task_lock() to ensure the operation is atomic and the name is
-	 *     fully updated.
 	 */
 	char				comm[TASK_COMM_LEN];
 
@@ -1965,7 +1963,7 @@ extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec
  *   User space can randomly change their names anyway, so locking for readers
  *   doesn't make sense. For writers, locking is probably necessary, as a race
  *   condition could lead to long-term mixed results.
- *   The strscpy_pad() in __set_task_comm() can ensure that the task comm is
+ *   The logic inside __set_task_comm() should ensure that the task comm is
  *   always NUL-terminated and zero-padded. Therefore the race condition between
  *   reader and writer is not an issue.
  *
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation
  2025-07-24 12:36 [PATCH v6 0/3] Add support for long task name Bhupesh
  2025-07-24 12:36 ` [PATCH v6 1/3] exec: Remove obsolete comments Bhupesh
@ 2025-07-24 12:36 ` Bhupesh
  2025-07-24 23:49   ` Kees Cook
  2025-07-24 12:36 ` [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes Bhupesh
  2 siblings, 1 reply; 12+ messages in thread
From: Bhupesh @ 2025-07-24 12:36 UTC (permalink / raw)
  To: akpm
  Cc: bhupesh, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, keescook,
	ebiederm, brauner, jack, mingo, juri.lelli, bsegall, mgorman,
	vschneid, linux-trace-kernel, kees, torvalds

As Linus mentioned in [1], currently we have several memcpy() use-cases
which use 'current->comm' to copy the task name over to local copies.
For an example:

 ...
 char comm[TASK_COMM_LEN];
 memcpy(comm, current->comm, TASK_COMM_LEN);
 ...

These should be modified so that we can later implement approaches
to handle the task->comm's 16-byte length limitation (TASK_COMM_LEN)
in a more modular way (follow-up patch does the same):

 ...
 char comm[TASK_COMM_LEN];
 memcpy(comm, current->comm, TASK_COMM_LEN);
 comm[TASK_COMM_LEN - 1] = '\0';
 ...

The relevant 'memcpy()' users were identified using the following search
pattern:
 $ git grep 'memcpy.*->comm\>'

[1]. https://lore.kernel.org/all/CAHk-=wjAmmHUg6vho1KjzQi2=psR30+CogFd4aXrThr2gsiS4g@mail.gmail.com/

Signed-off-by: Bhupesh <bhupesh@igalia.com>
---
 include/linux/coredump.h       | 3 ++-
 include/trace/events/block.h   | 5 +++++
 include/trace/events/oom.h     | 1 +
 include/trace/events/osnoise.h | 1 +
 include/trace/events/signal.h  | 1 +
 include/trace/events/task.h    | 2 ++
 6 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/include/linux/coredump.h b/include/linux/coredump.h
index 68861da4cf7c..988b233dcc09 100644
--- a/include/linux/coredump.h
+++ b/include/linux/coredump.h
@@ -54,7 +54,8 @@ extern void vfs_coredump(const kernel_siginfo_t *siginfo);
 	do {	\
 		char comm[TASK_COMM_LEN];	\
 		/* This will always be NUL terminated. */ \
-		memcpy(comm, current->comm, sizeof(comm)); \
+		memcpy(comm, current->comm, TASK_COMM_LEN); \
+		comm[TASK_COMM_LEN - 1] = '\0'; \
 		printk_ratelimited(Level "coredump: %d(%*pE): " Format "\n",	\
 			task_tgid_vnr(current), (int)strlen(comm), comm, ##__VA_ARGS__);	\
 	} while (0)	\
diff --git a/include/trace/events/block.h b/include/trace/events/block.h
index 6aa79e2d799c..dfc20fbe389c 100644
--- a/include/trace/events/block.h
+++ b/include/trace/events/block.h
@@ -214,6 +214,7 @@ DECLARE_EVENT_CLASS(block_rq,
 		blk_fill_rwbs(__entry->rwbs, rq->cmd_flags);
 		__get_str(cmd)[0] = '\0';
 		memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 	),
 
 	TP_printk("%d,%d %s %u (%s) %llu + %u %s,%u,%u [%s]",
@@ -352,6 +353,7 @@ DECLARE_EVENT_CLASS(block_bio,
 		__entry->nr_sector	= bio_sectors(bio);
 		blk_fill_rwbs(__entry->rwbs, bio->bi_opf);
 		memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 	),
 
 	TP_printk("%d,%d %s %llu + %u [%s]",
@@ -435,6 +437,7 @@ TRACE_EVENT(block_plug,
 
 	TP_fast_assign(
 		memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 	),
 
 	TP_printk("[%s]", __entry->comm)
@@ -454,6 +457,7 @@ DECLARE_EVENT_CLASS(block_unplug,
 	TP_fast_assign(
 		__entry->nr_rq = depth;
 		memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 	),
 
 	TP_printk("[%s] %d", __entry->comm, __entry->nr_rq)
@@ -505,6 +509,7 @@ TRACE_EVENT(block_split,
 		__entry->new_sector	= new_sector;
 		blk_fill_rwbs(__entry->rwbs, bio->bi_opf);
 		memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 	),
 
 	TP_printk("%d,%d %s %llu / %llu [%s]",
diff --git a/include/trace/events/oom.h b/include/trace/events/oom.h
index 9f0a5d1482c4..a5641ed4285f 100644
--- a/include/trace/events/oom.h
+++ b/include/trace/events/oom.h
@@ -24,6 +24,7 @@ TRACE_EVENT(oom_score_adj_update,
 	TP_fast_assign(
 		__entry->pid = task->pid;
 		memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 		__entry->oom_score_adj = task->signal->oom_score_adj;
 	),
 
diff --git a/include/trace/events/osnoise.h b/include/trace/events/osnoise.h
index 3f4273623801..0321b3f8d532 100644
--- a/include/trace/events/osnoise.h
+++ b/include/trace/events/osnoise.h
@@ -117,6 +117,7 @@ TRACE_EVENT(thread_noise,
 
 	TP_fast_assign(
 		memcpy(__entry->comm, t->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 		__entry->pid = t->pid;
 		__entry->start = start;
 		__entry->duration = duration;
diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h
index 1db7e4b07c01..7f490e553db5 100644
--- a/include/trace/events/signal.h
+++ b/include/trace/events/signal.h
@@ -68,6 +68,7 @@ TRACE_EVENT(signal_generate,
 		__entry->sig	= sig;
 		TP_STORE_SIGINFO(__entry, info);
 		memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 		__entry->pid	= task->pid;
 		__entry->group	= group;
 		__entry->result	= result;
diff --git a/include/trace/events/task.h b/include/trace/events/task.h
index af535b053033..4ddf21b69372 100644
--- a/include/trace/events/task.h
+++ b/include/trace/events/task.h
@@ -22,6 +22,7 @@ TRACE_EVENT(task_newtask,
 	TP_fast_assign(
 		__entry->pid = task->pid;
 		memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
+		__entry->comm[TASK_COMM_LEN - 1] = '\0';
 		__entry->clone_flags = clone_flags;
 		__entry->oom_score_adj = task->signal->oom_score_adj;
 	),
@@ -45,6 +46,7 @@ TRACE_EVENT(task_rename,
 
 	TP_fast_assign(
 		memcpy(entry->oldcomm, task->comm, TASK_COMM_LEN);
+		entry->oldcomm[TASK_COMM_LEN - 1] = '\0';
 		strscpy(entry->newcomm, comm, TASK_COMM_LEN);
 		__entry->oom_score_adj = task->signal->oom_score_adj;
 	),
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes
  2025-07-24 12:36 [PATCH v6 0/3] Add support for long task name Bhupesh
  2025-07-24 12:36 ` [PATCH v6 1/3] exec: Remove obsolete comments Bhupesh
  2025-07-24 12:36 ` [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation Bhupesh
@ 2025-07-24 12:36 ` Bhupesh
  2025-07-24 23:38   ` Kees Cook
  2025-07-26 11:20   ` kernel test robot
  2 siblings, 2 replies; 12+ messages in thread
From: Bhupesh @ 2025-07-24 12:36 UTC (permalink / raw)
  To: akpm
  Cc: bhupesh, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, keescook,
	ebiederm, brauner, jack, mingo, juri.lelli, bsegall, mgorman,
	vschneid, linux-trace-kernel, kees, torvalds

Historically due to the 16-byte length of TASK_COMM_LEN, the
users of 'tsk->comm' are restricted to use a fixed-size target
buffer also of TASK_COMM_LEN for 'memcpy()' like use-cases.

To fix the same, we now use a 64-byte TASK_COMM_EXT_LEN and
set the comm element inside 'task_struct' to the same length:
       struct task_struct {
	       .....
               char    comm[TASK_COMM_EXT_LEN];
	       .....
       };

       where TASK_COMM_EXT_LEN is 64-bytes.

Now, in order to maintain existing ABI, we ensure that:

- Existing users of 'get_task_comm'/ 'set_task_comm' will get 'tsk->comm'
  truncated to a maximum of 'TASK_COMM_LEN' (16-bytes) to maintain ABI,
- New / Modified users of 'get_task_comm'/ 'set_task_comm' will get
 'tsk->comm' supported up to the maximum of 'TASK_COMM_EXT_LEN' (64-bytes).

Note, that the existing users have not been modified to migrate to
'TASK_COMM_EXT_LEN', in case they have hard-coded expectations of
dealing with only a 'TASK_COMM_LEN' long 'tsk->comm'.

Signed-off-by: Bhupesh <bhupesh@igalia.com>
---
 include/linux/sched.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 8bbd03f1b978..b6abb759292c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -317,6 +317,7 @@ struct user_event_mm;
  */
 enum {
 	TASK_COMM_LEN = 16,
+	TASK_COMM_EXT_LEN = 64,
 };
 
 extern void sched_tick(void);
@@ -1159,7 +1160,7 @@ struct task_struct {
 	 *   - logic inside set_task_comm() will ensure it is always NUL-terminated and
 	 *     zero-padded
 	 */
-	char				comm[TASK_COMM_LEN];
+	char				comm[TASK_COMM_EXT_LEN];
 
 	struct nameidata		*nameidata;
 
@@ -1954,7 +1955,7 @@ extern void kick_process(struct task_struct *tsk);
 
 extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec);
 #define set_task_comm(tsk, from) ({			\
-	BUILD_BUG_ON(sizeof(from) != TASK_COMM_LEN);	\
+	BUILD_BUG_ON(sizeof(from) < TASK_COMM_LEN);	\
 	__set_task_comm(tsk, from, false);		\
 })
 
@@ -1974,6 +1975,10 @@ extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec
 #define get_task_comm(buf, tsk) ({			\
 	BUILD_BUG_ON(sizeof(buf) < TASK_COMM_LEN);	\
 	strscpy_pad(buf, (tsk)->comm);			\
+	if ((sizeof(buf)) == TASK_COMM_LEN)		\
+		buf[TASK_COMM_LEN - 1] = '\0';		\
+	else						\
+		buf[TASK_COMM_EXT_LEN - 1] = '\0';	\
 	buf;						\
 })
 
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes
  2025-07-24 12:36 ` [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes Bhupesh
@ 2025-07-24 23:38   ` Kees Cook
  2025-07-26 11:20   ` kernel test robot
  1 sibling, 0 replies; 12+ messages in thread
From: Kees Cook @ 2025-07-24 23:38 UTC (permalink / raw)
  To: Bhupesh
  Cc: akpm, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, ebiederm,
	brauner, jack, mingo, juri.lelli, bsegall, mgorman, vschneid,
	linux-trace-kernel, torvalds

On Thu, Jul 24, 2025 at 06:06:12PM +0530, Bhupesh wrote:
> Historically due to the 16-byte length of TASK_COMM_LEN, the
> users of 'tsk->comm' are restricted to use a fixed-size target
> buffer also of TASK_COMM_LEN for 'memcpy()' like use-cases.
> 
> To fix the same, we now use a 64-byte TASK_COMM_EXT_LEN and
> set the comm element inside 'task_struct' to the same length:
>        struct task_struct {
> 	       .....
>                char    comm[TASK_COMM_EXT_LEN];
> 	       .....
>        };
> 
>        where TASK_COMM_EXT_LEN is 64-bytes.
> 
> Now, in order to maintain existing ABI, we ensure that:
> 
> - Existing users of 'get_task_comm'/ 'set_task_comm' will get 'tsk->comm'
>   truncated to a maximum of 'TASK_COMM_LEN' (16-bytes) to maintain ABI,
> - New / Modified users of 'get_task_comm'/ 'set_task_comm' will get
>  'tsk->comm' supported up to the maximum of 'TASK_COMM_EXT_LEN' (64-bytes).
> 
> Note, that the existing users have not been modified to migrate to
> 'TASK_COMM_EXT_LEN', in case they have hard-coded expectations of
> dealing with only a 'TASK_COMM_LEN' long 'tsk->comm'.
> 
> Signed-off-by: Bhupesh <bhupesh@igalia.com>
> ---
>  include/linux/sched.h | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 8bbd03f1b978..b6abb759292c 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -317,6 +317,7 @@ struct user_event_mm;
>   */
>  enum {
>  	TASK_COMM_LEN = 16,
> +	TASK_COMM_EXT_LEN = 64,
>  };
>  
>  extern void sched_tick(void);
> @@ -1159,7 +1160,7 @@ struct task_struct {
>  	 *   - logic inside set_task_comm() will ensure it is always NUL-terminated and
>  	 *     zero-padded
>  	 */
> -	char				comm[TASK_COMM_LEN];
> +	char				comm[TASK_COMM_EXT_LEN];
>  
>  	struct nameidata		*nameidata;
>  
> @@ -1954,7 +1955,7 @@ extern void kick_process(struct task_struct *tsk);
>  
>  extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec);
>  #define set_task_comm(tsk, from) ({			\
> -	BUILD_BUG_ON(sizeof(from) != TASK_COMM_LEN);	\
> +	BUILD_BUG_ON(sizeof(from) < TASK_COMM_LEN);	\
>  	__set_task_comm(tsk, from, false);		\
>  })
>  
> @@ -1974,6 +1975,10 @@ extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec
>  #define get_task_comm(buf, tsk) ({			\
>  	BUILD_BUG_ON(sizeof(buf) < TASK_COMM_LEN);	\
>  	strscpy_pad(buf, (tsk)->comm);			\
> +	if ((sizeof(buf)) == TASK_COMM_LEN)		\
> +		buf[TASK_COMM_LEN - 1] = '\0';		\
> +	else						\
> +		buf[TASK_COMM_EXT_LEN - 1] = '\0';	\

strscpy_pad() will already make sure buf is NUL-terminated, so I don't
see why there is a need for explicit final byte termination? (And even
if we do need it, then it should just be buf[sizeof(buf) - 1] otherwise
using a buf that is < TASK_COMM_EXT_LEN but > TASK_COMM_LEN will have
a spurious NUL byte write beyond its buffer.)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation
  2025-07-24 12:36 ` [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation Bhupesh
@ 2025-07-24 23:49   ` Kees Cook
  2025-07-26 17:50     ` Linus Torvalds
  0 siblings, 1 reply; 12+ messages in thread
From: Kees Cook @ 2025-07-24 23:49 UTC (permalink / raw)
  To: Bhupesh
  Cc: akpm, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, ebiederm,
	brauner, jack, mingo, juri.lelli, bsegall, mgorman, vschneid,
	linux-trace-kernel, torvalds

On Thu, Jul 24, 2025 at 06:06:11PM +0530, Bhupesh wrote:
> As Linus mentioned in [1], currently we have several memcpy() use-cases
> which use 'current->comm' to copy the task name over to local copies.
> For an example:
> 
>  ...
>  char comm[TASK_COMM_LEN];
>  memcpy(comm, current->comm, TASK_COMM_LEN);
>  ...
> 
> These should be modified so that we can later implement approaches
> to handle the task->comm's 16-byte length limitation (TASK_COMM_LEN)
> in a more modular way (follow-up patch does the same):
> 
>  ...
>  char comm[TASK_COMM_LEN];
>  memcpy(comm, current->comm, TASK_COMM_LEN);
>  comm[TASK_COMM_LEN - 1] = '\0';
>  ...

Why not switch all of these to get_task_comm()? It will correctly handle
the size check and NUL termination.

In an earlier thread[1], I pointed out that since __set_task_comm() always
keeps a final NUL byte, we're always safe to use strscpy(). (We want to
block over-reads and over-writes but don't care about garbled reads.)

In the new case of copying into a smaller buffer, strscpy() will always
handle writing the final NUL byte.

The only special cases I can think of would be non-fixed-sized
destination buffers, which get_task_comm() doesn't like since it can't
validate how to safely terminate the buffer. The example you give above
isn't that, though.

-Kees

[1] https://lore.kernel.org/all/202411301244.381F2B8D17@keescook/

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 1/3] exec: Remove obsolete comments
  2025-07-24 12:36 ` [PATCH v6 1/3] exec: Remove obsolete comments Bhupesh
@ 2025-07-24 23:50   ` Kees Cook
  0 siblings, 0 replies; 12+ messages in thread
From: Kees Cook @ 2025-07-24 23:50 UTC (permalink / raw)
  To: Bhupesh
  Cc: akpm, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, ebiederm,
	brauner, jack, mingo, juri.lelli, bsegall, mgorman, vschneid,
	linux-trace-kernel, torvalds

On Thu, Jul 24, 2025 at 06:06:10PM +0530, Bhupesh wrote:
> Patch 3a3f61ce5e0b ("exec: Make sure task->comm is always NUL-terminated"),
> replaced 'strscpy_pad()' with 'memcpy()' implementations inside
> '__set_task_comm()'.
> 
> However a few left-over comments are still there, which mention
> the usage of 'strscpy_pad()' inside '__set_task_comm()'.
> 
> Remove those obsolete comments.
> 
> While at it, also remove an obsolete comment regarding 'task_lock()'
> usage while handing 'task->comm'.
> 
> Signed-off-by: Bhupesh <bhupesh@igalia.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes
  2025-07-24 12:36 ` [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes Bhupesh
  2025-07-24 23:38   ` Kees Cook
@ 2025-07-26 11:20   ` kernel test robot
  1 sibling, 0 replies; 12+ messages in thread
From: kernel test robot @ 2025-07-26 11:20 UTC (permalink / raw)
  To: Bhupesh, akpm
  Cc: oe-kbuild-all, bhupesh, kernel-dev, linux-kernel, bpf,
	linux-perf-users, linux-fsdevel, linux-mm, oliver.sang, lkp,
	laoar.shao, pmladek, rostedt, mathieu.desnoyers, arnaldo.melo,
	alexei.starovoitov, andrii.nakryiko, mirq-linux, peterz, willy,
	david, viro, keescook, ebiederm, brauner, jack, mingo, juri.lelli,
	bsegall, mgorman

Hi Bhupesh,

kernel test robot noticed the following build warnings:

[auto build test WARNING on trace/for-next]
[also build test WARNING on tip/sched/core akpm-mm/mm-everything linus/master v6.16-rc7 next-20250725]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bhupesh/exec-Remove-obsolete-comments/20250724-203927
base:   https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace for-next
patch link:    https://lore.kernel.org/r/20250724123612.206110-4-bhupesh%40igalia.com
patch subject: [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes
config: sparc64-randconfig-001-20250725 (https://download.01.org/0day-ci/archive/20250726/202507261841.Z2C9RmTJ-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250726/202507261841.Z2C9RmTJ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202507261841.Z2C9RmTJ-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/nouveau/nouveau_chan.c: In function 'nouveau_channel_ctor':
>> drivers/gpu/drm/nouveau/nouveau_chan.c:336:51: warning: '%s' directive output may be truncated writing up to 63 bytes into a region of size 32 [-Wformat-truncation=]
     snprintf(args->name, __member_size(args->name), "%s[%d]",
                                                      ^~
   drivers/gpu/drm/nouveau/nouveau_chan.c:336:2: note: 'snprintf' output between 4 and 77 bytes into a destination of size 32
     snprintf(args->name, __member_size(args->name), "%s[%d]",
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       current->comm, task_pid_nr(current));
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
   drivers/gpu/drm/nouveau/nouveau_drm.c: In function 'nouveau_drm_open':
>> drivers/gpu/drm/nouveau/nouveau_drm.c:1202:32: warning: '%s' directive output may be truncated writing up to 63 bytes into a region of size 32 [-Wformat-truncation=]
     snprintf(name, sizeof(name), "%s[%d]",
                                   ^~
   drivers/gpu/drm/nouveau/nouveau_drm.c:1202:2: note: 'snprintf' output between 4 and 77 bytes into a destination of size 32
     snprintf(name, sizeof(name), "%s[%d]",
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       current->comm, pid_nr(rcu_dereference(fpriv->pid)));
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +336 drivers/gpu/drm/nouveau/nouveau_chan.c

ebb945a94bba2c Ben Skeggs          2012-07-20  246  
5b8a43aeb9cbf6 Marcin Slusarz      2012-08-19  247  static int
5cca41ac70e587 Ben Skeggs          2024-07-26  248  nouveau_channel_ctor(struct nouveau_cli *cli, bool priv, u64 runm,
06db7fded6dec8 Ben Skeggs          2022-06-01  249  		     struct nouveau_channel **pchan)
ebb945a94bba2c Ben Skeggs          2012-07-20  250  {
152be54224de18 Danilo Krummrich    2023-10-02  251  	const struct nvif_mclass hosts[] = {
284ad706ad2f50 Ben Skeggs          2025-02-04  252  		{ BLACKWELL_CHANNEL_GPFIFO_B, 0 },
32cb1cc358ffed Ben Skeggs          2024-11-25  253  		{ BLACKWELL_CHANNEL_GPFIFO_A, 0 },
44f93b209e2afd Ben Skeggs          2024-11-25  254  		{    HOPPER_CHANNEL_GPFIFO_A, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  255  		{    AMPERE_CHANNEL_GPFIFO_B, 0 },
7f4f35ea5b080e Ben Skeggs          2022-06-01  256  		{    AMPERE_CHANNEL_GPFIFO_A, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  257  		{    TURING_CHANNEL_GPFIFO_A, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  258  		{     VOLTA_CHANNEL_GPFIFO_A, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  259  		{    PASCAL_CHANNEL_GPFIFO_A, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  260  		{   MAXWELL_CHANNEL_GPFIFO_A, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  261  		{    KEPLER_CHANNEL_GPFIFO_B, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  262  		{    KEPLER_CHANNEL_GPFIFO_A, 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  263  		{     FERMI_CHANNEL_GPFIFO  , 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  264  		{       G82_CHANNEL_GPFIFO  , 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  265  		{      NV50_CHANNEL_GPFIFO  , 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  266  		{      NV40_CHANNEL_DMA     , 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  267  		{      NV17_CHANNEL_DMA     , 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  268  		{      NV10_CHANNEL_DMA     , 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  269  		{      NV03_CHANNEL_DMA     , 0 },
06db7fded6dec8 Ben Skeggs          2022-06-01  270  		{}
06db7fded6dec8 Ben Skeggs          2022-06-01  271  	};
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  272  	DEFINE_RAW_FLEX(struct nvif_chan_v0, args, name, TASK_COMM_LEN + 16);
5cca41ac70e587 Ben Skeggs          2024-07-26  273  	struct nvif_device *device = &cli->device;
ebb945a94bba2c Ben Skeggs          2012-07-20  274  	struct nouveau_channel *chan;
06db7fded6dec8 Ben Skeggs          2022-06-01  275  	const u64 plength = 0x10000;
06db7fded6dec8 Ben Skeggs          2022-06-01  276  	const u64 ioffset = plength;
06db7fded6dec8 Ben Skeggs          2022-06-01  277  	const u64 ilength = 0x02000;
06db7fded6dec8 Ben Skeggs          2022-06-01  278  	int cid, ret;
06db7fded6dec8 Ben Skeggs          2022-06-01  279  	u64 size;
06db7fded6dec8 Ben Skeggs          2022-06-01  280  
06db7fded6dec8 Ben Skeggs          2022-06-01  281  	cid = nvif_mclass(&device->object, hosts);
06db7fded6dec8 Ben Skeggs          2022-06-01  282  	if (cid < 0)
06db7fded6dec8 Ben Skeggs          2022-06-01  283  		return cid;
06db7fded6dec8 Ben Skeggs          2022-06-01  284  
06db7fded6dec8 Ben Skeggs          2022-06-01  285  	if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO)
06db7fded6dec8 Ben Skeggs          2022-06-01  286  		size = plength;
06db7fded6dec8 Ben Skeggs          2022-06-01  287  	else
06db7fded6dec8 Ben Skeggs          2022-06-01  288  		size = ioffset + ilength;
ebb945a94bba2c Ben Skeggs          2012-07-20  289  
ebb945a94bba2c Ben Skeggs          2012-07-20  290  	/* allocate dma push buffer */
5cca41ac70e587 Ben Skeggs          2024-07-26  291  	ret = nouveau_channel_prep(cli, size, &chan);
ebb945a94bba2c Ben Skeggs          2012-07-20  292  	*pchan = chan;
ebb945a94bba2c Ben Skeggs          2012-07-20  293  	if (ret)
ebb945a94bba2c Ben Skeggs          2012-07-20  294  		return ret;
ebb945a94bba2c Ben Skeggs          2012-07-20  295  
ebb945a94bba2c Ben Skeggs          2012-07-20  296  	/* create channel object */
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  297  	args->version = 0;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  298  	args->namelen = __member_size(args->name);
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  299  	args->runlist = __ffs64(runm);
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  300  	args->runq = 0;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  301  	args->priv = priv;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  302  	args->devm = BIT(0);
06db7fded6dec8 Ben Skeggs          2022-06-01  303  	if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO) {
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  304  		args->vmm = 0;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  305  		args->ctxdma = nvif_handle(&chan->push.ctxdma);
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  306  		args->offset = chan->push.addr;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  307  		args->length = 0;
bbf8906b2cad17 Ben Skeggs          2014-08-10  308  	} else {
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  309  		args->vmm = nvif_handle(&chan->vmm->vmm.object);
06db7fded6dec8 Ben Skeggs          2022-06-01  310  		if (hosts[cid].oclass < FERMI_CHANNEL_GPFIFO)
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  311  			args->ctxdma = nvif_handle(&chan->push.ctxdma);
06db7fded6dec8 Ben Skeggs          2022-06-01  312  		else
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  313  			args->ctxdma = 0;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  314  		args->offset = ioffset + chan->push.addr;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  315  		args->length = ilength;
06db7fded6dec8 Ben Skeggs          2022-06-01  316  	}
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  317  	args->huserd = 0;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  318  	args->ouserd = 0;
06db7fded6dec8 Ben Skeggs          2022-06-01  319  
06db7fded6dec8 Ben Skeggs          2022-06-01  320  	/* allocate userd */
06db7fded6dec8 Ben Skeggs          2022-06-01  321  	if (hosts[cid].oclass >= VOLTA_CHANNEL_GPFIFO_A) {
06db7fded6dec8 Ben Skeggs          2022-06-01  322  		ret = nvif_mem_ctor(&cli->mmu, "abi16ChanUSERD", NVIF_CLASS_MEM_GF100,
06db7fded6dec8 Ben Skeggs          2022-06-01  323  				    NVIF_MEM_VRAM | NVIF_MEM_COHERENT | NVIF_MEM_MAPPABLE,
06db7fded6dec8 Ben Skeggs          2022-06-01  324  				    0, PAGE_SIZE, NULL, 0, &chan->mem_userd);
06db7fded6dec8 Ben Skeggs          2022-06-01  325  		if (ret)
ebb945a94bba2c Ben Skeggs          2012-07-20  326  			return ret;
ebb945a94bba2c Ben Skeggs          2012-07-20  327  
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  328  		args->huserd = nvif_handle(&chan->mem_userd.object);
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  329  		args->ouserd = 0;
ebb945a94bba2c Ben Skeggs          2012-07-20  330  
06db7fded6dec8 Ben Skeggs          2022-06-01  331  		chan->userd = &chan->mem_userd.object;
06db7fded6dec8 Ben Skeggs          2022-06-01  332  	} else {
06db7fded6dec8 Ben Skeggs          2022-06-01  333  		chan->userd = &chan->user;
06db7fded6dec8 Ben Skeggs          2022-06-01  334  	}
ebb945a94bba2c Ben Skeggs          2012-07-20  335  
e270b3665f8321 Gustavo A. R. Silva 2025-04-16 @336  	snprintf(args->name, __member_size(args->name), "%s[%d]",
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  337  		 current->comm, task_pid_nr(current));
ebb945a94bba2c Ben Skeggs          2012-07-20  338  
06db7fded6dec8 Ben Skeggs          2022-06-01  339  	ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, hosts[cid].oclass,
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  340  			       args, __struct_size(args), &chan->user);
06db7fded6dec8 Ben Skeggs          2022-06-01  341  	if (ret) {
06db7fded6dec8 Ben Skeggs          2022-06-01  342  		nouveau_channel_del(pchan);
ebb945a94bba2c Ben Skeggs          2012-07-20  343  		return ret;
bbf8906b2cad17 Ben Skeggs          2014-08-10  344  	}
ebb945a94bba2c Ben Skeggs          2012-07-20  345  
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  346  	chan->runlist = args->runlist;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  347  	chan->chid = args->chid;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  348  	chan->inst = args->inst;
e270b3665f8321 Gustavo A. R. Silva 2025-04-16  349  	chan->token = args->token;
06db7fded6dec8 Ben Skeggs          2022-06-01  350  	return 0;
ebb945a94bba2c Ben Skeggs          2012-07-20  351  }
ebb945a94bba2c Ben Skeggs          2012-07-20  352  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation
  2025-07-24 23:49   ` Kees Cook
@ 2025-07-26 17:50     ` Linus Torvalds
  2025-07-26 23:19       ` Kees Cook
  0 siblings, 1 reply; 12+ messages in thread
From: Linus Torvalds @ 2025-07-26 17:50 UTC (permalink / raw)
  To: Kees Cook
  Cc: Bhupesh, akpm, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, ebiederm,
	brauner, jack, mingo, juri.lelli, bsegall, mgorman, vschneid,
	linux-trace-kernel

, but

On Thu, 24 Jul 2025 at 16:49, Kees Cook <kees@kernel.org> wrote:
>
> Why not switch all of these to get_task_comm()? It will correctly handle
> the size check and NUL termination.

I'd rather aim to get rid of get_task_comm() entirely.

I don't think it has ever made much sense, except in the "guarantee
NUL termination" sense, but since we have basically agreed to always
guarantee that natively in ->comm[] itself (by *never* writing non-NUL
characters to the last byte, rather than "write something, then
overwrite it") the whole concept is broken.

The alleged other reason for get_task_comm() is to get a stable
result, but since the source can be modified by users, there's no
"stable". If you get some half-way state, that *could* have been a
user just writing odd names.

So the other reason to use get_task_comm() is pretty much pointless too.

And several of the existing users are just pointless overhead, copying
the comm[] to a local copy only to print it out, and making it much
more complex than just using "%s" with tsk->comm.

End result: all get_task_comm() does now is to verify the size of the
result buffer, and that is *BAD*. We shouldn't care. If the result
buffer is smaller than the string, we should just have truncated it.
And if the buffer is bigger, we should zero-pad or not depending on
the use case.

And guess what? We *have* that function. It's called "strscpy()". It
already does the right thing, including passing in the size of a fixed
array and just dealing with it the RightWay(tm). Add '_pad()' if that
is the behavior you want, and now you *document* the fact that the
result is padded.

So I claim that get_task_comm() is bad, and we should feel bad about
ever having introduced it.

Now, the tracing code may actually care about *performance*, and what
it probably wants is that "just copy things and NUL-terminate it", but
I don't think we should use get_task_comm() for that because of all
the horrid bad history it has.

In other words, if "strscpy()" is too expensive (because it's being
careful and returns the size), I think we should look at maybe
optimizing strscpy() further. It already does word-at-a-time stuff,
but what strscpy() does *not* do is the "inline at call site for small
constant sizes".

We could inline sized_strscpy() for small constant sizes, but the real
problem is that it returns the length, and there's no way to do
"inline for small constant sizes when nobody cares about the result"
that I can think of. You can use _Generic() on the arguments, but not
on the "people don't look at the return value".

So we do probably want something for that "just copy comm to a
constant-sized array" case if people care about performance for it
(and tracing probably does), but I still think get_task_comm() has too
much baggage (and takes a size that it shouldn't take).

"get_task_array()" might be more palatable, and is certainly simple to
implement using something like

   static __always_inline void
       __cstr_array_copy(char *dst,
            const char *src, __kernel_size_t size)
   {
        memcpy(dst, src, size);
        dst[size] = 0;
   }

   #define get_task_array(a,b) \
      __cstr_array_copy(dst, src, __must_be_array(dst))

(Entirely untested, hasn't seen a compiler, is written for email, you
get the idea..).

But I think that should be a separate thing (and it should be
documented to be data-racy in the destination and *not* be the kind of
"stable NUL at the end" that strscpy and friends are.

               Linus

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation
  2025-07-26 17:50     ` Linus Torvalds
@ 2025-07-26 23:19       ` Kees Cook
  2025-07-26 23:37         ` Linus Torvalds
  0 siblings, 1 reply; 12+ messages in thread
From: Kees Cook @ 2025-07-26 23:19 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Bhupesh, akpm, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, ebiederm,
	brauner, jack, mingo, juri.lelli, bsegall, mgorman, vschneid,
	linux-trace-kernel



On July 26, 2025 10:50:55 AM PDT, Linus Torvalds <torvalds@linux-foundation.org> wrote:
>, but
>
>On Thu, 24 Jul 2025 at 16:49, Kees Cook <kees@kernel.org> wrote:
>>
>> Why not switch all of these to get_task_comm()? It will correctly handle
>> the size check and NUL termination.
>
>I'd rather aim to get rid of get_task_comm() entirely.

That works for me! I just get twitchy around seeing memcpy used for strings. :) if we're gonna NUL after the memcpy, just use strscpy_pad().

>And guess what? We *have* that function. It's called "strscpy()". It
>already does the right thing, including passing in the size of a fixed
>array and just dealing with it the RightWay(tm). Add '_pad()' if that
>is the behavior you want, and now you *document* the fact that the
>result is padded.

Exactly. Let's see how much we can just replace with strscpy_pad(). It we have other use cases, we can handle those separately.

-Kees

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation
  2025-07-26 23:19       ` Kees Cook
@ 2025-07-26 23:37         ` Linus Torvalds
  2025-08-05 11:13           ` Bhupesh Sharma
  0 siblings, 1 reply; 12+ messages in thread
From: Linus Torvalds @ 2025-07-26 23:37 UTC (permalink / raw)
  To: Kees Cook
  Cc: Bhupesh, akpm, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, ebiederm,
	brauner, jack, mingo, juri.lelli, bsegall, mgorman, vschneid,
	linux-trace-kernel

On Sat, 26 Jul 2025 at 16:19, Kees Cook <kees@kernel.org> wrote:
>
> That works for me! I just get twitchy around seeing memcpy used for strings. :) if we're gonna NUL after the memcpy, just use strscpy_pad().

I do worry a tiny bit about performance.

Because 'memcpy+set last byte to NUL' really is just a couple of
instructions when we're talking small constant-sized arrays.

strscpy_pad() isn't horrible, but it's still at another level. And
most of the cost is that "return the length" which people often don't
care about.

Dang, I wish we had some compiler trick to say "if the value isn't
used, do X, if it _is_ used do Y".

It's such a trivial thing in the compiler itself, and the information
is there, but I don't think it is exposed in any useful way.

In fact, it *is* exposed in one way I can think of:

   __attribute__((__warn_unused_result__))

but not in a useful form for actually generating different code.

Some kind of "__builtin_if_used(x,y)" where it picks 'x' if the value
is used, and 'y' if it isn't would be lovely for this.

Then you could do things like

    #define my_helper(x) \
        __builtin_if_used( \
                full_semantics(x), \
                simpler_version(x))

when having a return value means extra work and most people don't care.

Maybe it exists in some form that I haven't thought of?

Any compiler people around?

                 Linus

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation
  2025-07-26 23:37         ` Linus Torvalds
@ 2025-08-05 11:13           ` Bhupesh Sharma
  0 siblings, 0 replies; 12+ messages in thread
From: Bhupesh Sharma @ 2025-08-05 11:13 UTC (permalink / raw)
  To: Linus Torvalds, Kees Cook
  Cc: Bhupesh, akpm, kernel-dev, linux-kernel, bpf, linux-perf-users,
	linux-fsdevel, linux-mm, oliver.sang, lkp, laoar.shao, pmladek,
	rostedt, mathieu.desnoyers, arnaldo.melo, alexei.starovoitov,
	andrii.nakryiko, mirq-linux, peterz, willy, david, viro, ebiederm,
	brauner, jack, mingo, juri.lelli, bsegall, mgorman, vschneid,
	linux-trace-kernel


On 7/27/25 5:07 AM, Linus Torvalds wrote:
> On Sat, 26 Jul 2025 at 16:19, Kees Cook <kees@kernel.org> wrote:
>> That works for me! I just get twitchy around seeing memcpy used for strings. :) if we're gonna NUL after the memcpy, just use strscpy_pad().
> I do worry a tiny bit about performance.
>
> Because 'memcpy+set last byte to NUL' really is just a couple of
> instructions when we're talking small constant-sized arrays.
>
> strscpy_pad() isn't horrible, but it's still at another level. And
> most of the cost is that "return the length" which people often don't
> care about.
>
> Dang, I wish we had some compiler trick to say "if the value isn't
> used, do X, if it _is_ used do Y".
>
> It's such a trivial thing in the compiler itself, and the information
> is there, but I don't think it is exposed in any useful way.
>
> In fact, it *is* exposed in one way I can think of:
>
>     __attribute__((__warn_unused_result__))
>
> but not in a useful form for actually generating different code.
>
> Some kind of "__builtin_if_used(x,y)" where it picks 'x' if the value
> is used, and 'y' if it isn't would be lovely for this.
>
> Then you could do things like
>
>      #define my_helper(x) \
>          __builtin_if_used( \
>                  full_semantics(x), \
>                  simpler_version(x))
>
> when having a return value means extra work and most people don't care.
>
> Maybe it exists in some form that I haven't thought of?
>
> Any compiler people around?
>

Sorry for the delay in reply, but I was checking with some *compiler* 
folks and unfortunately couldn't find an equivalent of the above 
*helper* support.
I am not a compiler expert though and relied mostly on my digging of the 
'gcc' code and advise from folks working in compiler world.

In case there are no new suggestions, I think we can go ahead with 
"strscpy_pad()" or "get_task_array()" in place of "get_task_comm()" 
which is implement in the following manner:

    static __always_inline void
        __cstr_array_copy(char *dst,
             const char *src, __kernel_size_t size)
    {
         memcpy(dst, src, size);
         dst[size] = 0;
    }

    #define get_task_array(a,b) \
       __cstr_array_copy(dst, src, __must_be_array(dst))

Please let me know.

Thanks,
Bhupesh


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2025-08-05 11:14 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-24 12:36 [PATCH v6 0/3] Add support for long task name Bhupesh
2025-07-24 12:36 ` [PATCH v6 1/3] exec: Remove obsolete comments Bhupesh
2025-07-24 23:50   ` Kees Cook
2025-07-24 12:36 ` [PATCH v6 2/3] treewide: Switch memcpy() users of 'task->comm' to a more safer implementation Bhupesh
2025-07-24 23:49   ` Kees Cook
2025-07-26 17:50     ` Linus Torvalds
2025-07-26 23:19       ` Kees Cook
2025-07-26 23:37         ` Linus Torvalds
2025-08-05 11:13           ` Bhupesh Sharma
2025-07-24 12:36 ` [PATCH v6 3/3] include: Set tsk->comm length to 64 bytes Bhupesh
2025-07-24 23:38   ` Kees Cook
2025-07-26 11:20   ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).