From: Yu Watanabe Date: Sun, 27 Jul 2025 17:31:03 +0000 (+0900) Subject: core/exec-invoke: relax restriction for process name length X-Git-Tag: v259-rc1~244 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f03b49b079fd4ecb6407e74a116995ded906325a;p=thirdparty%2Fsystemd.git core/exec-invoke: relax restriction for process name length Previously, we limit the length of process name by 8. This relax the restriction then at least process comm or program_invocation_name contains the untrucated process name. Closes #38367. --- diff --git a/src/basic/argv-util.c b/src/basic/argv-util.c index 214c4b61f9a..c9d610b3a03 100644 --- a/src/basic/argv-util.c +++ b/src/basic/argv-util.c @@ -172,18 +172,19 @@ static int update_argv(const char name[], size_t l) { return 0; } -int rename_process(const char name[]) { +int rename_process_full(const char *comm, const char *invocation) { bool truncated = false; - /* This is a like a poor man's setproctitle(). It changes the comm field, argv[0], and also the glibc's - * internally used name of the process. For the first one a limit of 16 chars applies; to the second one in - * many cases one of 10 (i.e. length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded; - * to the third one 7 (i.e. the length of "systemd". If you pass a longer string it will likely be - * truncated. + /* This is a like a poor man's setproctitle(). It changes the comm field by the name specified by + * 'comm', and changes argv[0] and the glibc's internally used names of the process + * (program_invocation_name and program_invocation_short_name) by the name specified by 'invocation'. + * For the first one a limit of 16 chars applies; to the second one in many cases one of 10 (i.e. + * length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded; to the third one + * 7 (i.e. the length of "systemd". If you pass a longer string it will likely be truncated. * * Returns 0 if a name was set but truncated, > 0 if it was set but not truncated. */ - if (isempty(name)) + if (isempty(comm)) return -EINVAL; /* let's not confuse users unnecessarily with an empty name */ if (!is_main_thread()) @@ -191,21 +192,27 @@ int rename_process(const char name[]) { * cache things without locking, and we make assumptions that PR_SET_NAME sets the * process name that isn't correct on any other threads */ - size_t l = strlen(name); + size_t l = strlen(comm); /* First step, change the comm field. The main thread's comm is identical to the process comm. This means we * can use PR_SET_NAME, which sets the thread name for the calling thread. */ - if (prctl(PR_SET_NAME, name) < 0) + if (prctl(PR_SET_NAME, comm) < 0) log_debug_errno(errno, "PR_SET_NAME failed: %m"); if (l >= TASK_COMM_LEN) /* Linux userspace process names can be 15 chars at max */ truncated = true; + /* If nothing specified, fall back to comm. */ + if (isempty(invocation)) + invocation = comm; + + l = strlen(invocation); + /* Second step, change glibc's ID of the process name. */ if (program_invocation_name) { size_t k; k = strlen(program_invocation_name); - strncpy(program_invocation_name, name, k); + strncpy(program_invocation_name, invocation, k); if (l > k) truncated = true; @@ -217,7 +224,7 @@ int rename_process(const char name[]) { /* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but * has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at * the end. This is the best option for changing /proc/self/cmdline. */ - (void) update_argv(name, l); + (void) update_argv(invocation, l); /* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if * it still looks here */ @@ -226,7 +233,7 @@ int rename_process(const char name[]) { size_t k; k = strlen(saved_argv[0]); - strncpy(saved_argv[0], name, k); + strncpy(saved_argv[0], invocation, k); if (l > k) truncated = true; } diff --git a/src/basic/argv-util.h b/src/basic/argv-util.h index 392f7873a4a..650b00353dc 100644 --- a/src/basic/argv-util.h +++ b/src/basic/argv-util.h @@ -12,4 +12,7 @@ bool invoked_as(char *argv[], const char *token); bool invoked_by_systemd(void); bool argv_looks_like_help(int argc, char **argv); -int rename_process(const char name[]); +int rename_process_full(const char *comm, const char *invocation); +static inline int rename_process(const char *name) { + return rename_process_full(name, name); +} diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 5ea22fd429d..aaa9a0e8bd9 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -1490,35 +1490,30 @@ fail: } static void rename_process_from_path(const char *path) { - _cleanup_free_ char *buf = NULL; - const char *p; + int r; assert(path); - /* This resulting string must fit in 10 chars (i.e. the length of "/sbin/init") to look pretty in - * /bin/ps */ - - if (path_extract_filename(path, &buf) < 0) { - rename_process("(...)"); - return; + _cleanup_free_ char *buf = NULL; + r = path_extract_filename(path, &buf); + if (r < 0) { + log_debug_errno(r, "Failed to extract file name from '%s', ignoring: %m", path); + return (void) rename_process("(...)"); } - size_t l = strlen(buf); - if (l > 8) { - /* The end of the process name is usually more interesting, since the first bit might just be - * "systemd-" */ - p = buf + l - 8; - l = 8; - } else - p = buf; + size_t len = strlen(buf); + char comm[TASK_COMM_LEN], *p = comm; + *p++ = '('; + p = mempcpy(p, buf + LESS_BY(len, (size_t) (TASK_COMM_LEN - 3)), MIN(len, (size_t) (TASK_COMM_LEN - 3))); + *p++ = ')'; + *p = '\0'; - char process_name[11]; - process_name[0] = '('; - memcpy(process_name+1, p, l); - process_name[1+l] = ')'; - process_name[1+l+1] = 0; + size_t len_invocation = program_invocation_name ? strlen(program_invocation_name) : SIZE_MAX; + _cleanup_free_ char *invocation = strjoin("(", buf + LESS_BY(len, len_invocation - 2), ")"); + if (!invocation) + log_oom_debug(); - (void) rename_process(process_name); + (void) rename_process_full(comm, invocation ?: comm); } static bool context_has_address_families(const ExecContext *c) {