]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib: (pidutils.c) allow zero and negative numbers for PIDs
authorChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Sun, 5 Apr 2026 02:15:04 +0000 (22:15 -0400)
committerChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Wed, 8 Apr 2026 13:44:08 +0000 (09:44 -0400)
kill(1) and kill(2) man pages clearly state that 0 and negative
numbers can be used. Therefore let us adapt the internal helper
function ul_parse_pid_str() to permit this value range, as the
previous behavior regressed the kill(1) PID parsing behavior.

The uncommon value range can be controlled with two new flags
UL_PID_ZERO and UL_PID_NEGATIVE, ORed together they will allow
0 and negative values down to INT_MIN. Otherwise they can be
passed individually to only allow either. If 0 is passed only
1 upto INT_MAX values are allowed.

Closes: #4194
Closes: #4195
Signed-off-by: Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
include/c.h
include/pidutils.h
lib/pidutils.c
misc-utils/getino.c
misc-utils/kill.c
misc-utils/waitpid.c
sys-utils/nsenter.c
sys-utils/prlimit.c

index 991048dbd17bc1f7d6c3879d5a609fc4cfba0249..49616389b5c382f8899e57e82381f15f9b148005 100644 (file)
@@ -652,6 +652,7 @@ static inline int fputsln(const char *s, FILE *stream) {
 #endif
 
 #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2)))
+#define SINT_MIN(t) (-SINT_MAX(t) - (t)1)
 #define MAX_OF_UINT_TYPE(t) ~((t)0)
 
 #ifndef HAVE_REALLOCARRAY
index 979ec0590e8e65862f7c85da1d8c6713f987fddb..633dd049b1022f1b3466e1e94ebe14b52b834a04 100644 (file)
@@ -9,7 +9,10 @@
 
 #include <sys/types.h>
 
-extern int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino);
-extern void ul_parse_pid_str_or_err(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino);
+#define UL_PID_ZERO    (1 << 1)
+#define UL_PID_NEGATIVE        (1 << 2)
+
+extern int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino, int flags);
+extern void ul_parse_pid_str_or_err(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino, int flags);
 
 #endif /* UTIL_LINUX_PIDUTILS_H */
index e1a474d96028dce7a5f644e25e5a1370d5f27410..ea4156cfa9dd29e232af7ae3603616d37040afd6 100644 (file)
 #include "pidutils.h"
 
 /*
- * ul_parse_pid_str() - Parse a string and store the found pid and/or pidfd inode.
+ * ul_parse_pid_str() - Parse a string and store the found pid and pidfd inode.
  *
- * @pidstr:  string in format `pid:pidfd_inode` that is to be parsed
- * @pid_num: stores pid number
- * @pfd_ino: stores pidfd inode number
+ * @pidstr:    string in format `pid[:pidfd_inode]` that is to be parsed
+ * @pid_num:   stores pid number
+ * @pfd_ino:   stores pidfd inode number
+ * @flags:     uncommon values that are accepted as PIDs
+ *             (e.g.: zero = UL_PID_ZERO, negative = UL_PID_NEGATIVE)
+ *             the flag values can be ORed
  *
  * If @pfd_ino is not destined to be set, pass it as NULL.
  *
@@ -25,7 +28,7 @@
  *         On failure, a negative errno number is returned
  *         and errno is set to indicate the issue.
  */
-int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino)
+int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino, int flags)
 {
        int rc;
        char *end = NULL;
@@ -38,12 +41,18 @@ int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino)
        if (num == 0 && end == pidstr)
                return -(errno = EINVAL);
 
-       if (errno == ERANGE || (num <= 0 || num > SINT_MAX(pid_t)))
+       if (errno == ERANGE || num < SINT_MIN(pid_t) || num > SINT_MAX(pid_t))
+               return -(errno = ERANGE);
+
+       if (num == 0 && !(flags & UL_PID_ZERO))
+               return -(errno = ERANGE);
+
+       if (num < 0 && !(flags & UL_PID_NEGATIVE))
                return -(errno = ERANGE);
 
        *pid_num = (pid_t) num;
 
-       if (*end == ':' && pfd_ino) {
+       if (*end == ':' && pfd_ino && num > 0) {
                rc = ul_strtou64(++end, pfd_ino, 10);
                if (rc < 0)
                        return rc;
@@ -65,14 +74,17 @@ int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino)
  * @pidstr:  string in format `pid[:pidfd_inode]` that is to be parsed
  * @pid_num: stores pid number
  * @pfd_ino: stores pidfd inode number
+ * @flags:     uncommon values that are accepted as PIDs
+ *             (e.g.: zero = UL_PID_ZERO, negative = UL_PID_NEGATIVE)
+ *             the flag values can be ORed
  *
  * If @pfd_ino is not destined to be set, pass it as NULL.
  *
  * On failure, err() is called with an error message to indicate the issue.
  */
-void ul_parse_pid_str_or_err(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino)
+void ul_parse_pid_str_or_err(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino, int flags)
 {
-       if (ul_parse_pid_str(pidstr, pid_num, pfd_ino) < 0) {
+       if (ul_parse_pid_str(pidstr, pid_num, pfd_ino, flags) < 0) {
                err(EXIT_FAILURE, N_("failed to parse PID argument '%s'"), pidstr);
        }
 }
index 161f2fe2eb4356367ced54f2e21e228c67518706..22328c182953a2b9c1c50121169f1783591ee714 100644 (file)
@@ -238,7 +238,7 @@ int main(int argc, char **argv)
 
        argv += optind - 1;
        while (*++argv) {
-               rc = ul_parse_pid_str(*argv, &ctx.pid, &ctx.pidfd_ino);
+               rc = ul_parse_pid_str(*argv, &ctx.pid, &ctx.pidfd_ino, 0);
                if (rc)
                        err(EXIT_FAILURE, _("invalid PID argument '%s'"), *argv);
                print_inode(&ctx);
index 4fe11d02bdf190e9b21973dbe17fb43301be957b..dd6eab938254f0c8ff71bc9ec5d33a48342fcb03 100644 (file)
@@ -645,7 +645,7 @@ int main(int argc, char **argv)
        for ( ; (ctl.arg = *argv) != NULL; argv++) {
                errno = 0;
 
-               rc = ul_parse_pid_str(ctl.arg, &ctl.pid, &ctl.pidfd_ino);
+               rc = ul_parse_pid_str(ctl.arg, &ctl.pid, &ctl.pidfd_ino, UL_PID_ZERO | UL_PID_NEGATIVE);
                if(errno == 0 && rc == 0) {
                        if (check_signal_handler(&ctl) <= 0)
                                continue;
index d77a41c5ea26841666f1d5c7fd8317215a4cac58..b89c54bc46f4b4fea26d600ad6c6d45f5b6d6d0c 100644 (file)
@@ -63,7 +63,7 @@ static void parse_pids_or_err(struct process_info *pinfos, size_t n_strings, cha
 {
        for (size_t i = 0; i < n_strings; i++) {
                struct process_info *pi = &pinfos[i];
-               ul_parse_pid_str_or_err(strings[i], &pi->pid, &pi->pidfd_ino);
+               ul_parse_pid_str_or_err(strings[i], &pi->pid, &pi->pidfd_ino, 0);
        }
 }
 
index 2bbfe79ced89736574851bf385acff32fe1aa0b9..0ddf8cd9f92c13cdb748e9f1a0fd6a5424e80ae2 100644 (file)
@@ -579,7 +579,7 @@ static int parse_pid_str(char *pidstr, pid_t *ns_target_pid)
        int pfd = -1;
        uint64_t pidfd_ino = 0;
 
-       ul_parse_pid_str_or_err(pidstr, ns_target_pid, &pidfd_ino);
+       ul_parse_pid_str_or_err(pidstr, ns_target_pid, &pidfd_ino, 0);
        if (pidfd_ino)
                pfd = ul_get_valid_pidfd_or_err(*ns_target_pid, pidfd_ino);
        return pfd;
index 8d118a8f5d030d704a370917672bc1dd356f2f87..b92db2c3fb65db4fcae9c54cfb7afb98c8f213ad 100644 (file)
@@ -519,7 +519,7 @@ static int parse_pid_str(char *pidstr, pid_t *pidnum)
        int pfd = -1;
        uint64_t pidfd_ino = 0;
 
-       ul_parse_pid_str_or_err(pidstr, pidnum, &pidfd_ino);
+       ul_parse_pid_str_or_err(pidstr, pidnum, &pidfd_ino, 0);
        if (pidfd_ino)
                pfd = ul_get_valid_pidfd_or_err(*pidnum, pidfd_ino);