]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/exec-invoke: relax restriction for process name length
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 27 Jul 2025 17:31:03 +0000 (02:31 +0900)
committerMike Yuan <me@yhndnzj.com>
Sat, 25 Oct 2025 16:50:32 +0000 (18:50 +0200)
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.

src/basic/argv-util.c
src/basic/argv-util.h
src/core/exec-invoke.c

index 214c4b61f9a6a4d714d091c4f91c7eda58cf113f..c9d610b3a037d0458649e526a2df47214cf02cf6 100644 (file)
@@ -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;
                 }
index 392f7873a4a7a052fd8e131a9fa0211da7ddcda5..650b00353dc0894ab6b8f7c1f68a9b9b059291ed 100644 (file)
@@ -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);
+}
index 5ea22fd429db0e35b9645373758b0f24953dafd4..aaa9a0e8bd98b551b4858a4a4b5f08c4b3aadb13 100644 (file)
@@ -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) {