From: Lennart Poettering Date: Mon, 14 Oct 2024 10:31:57 +0000 (+0200) Subject: pidref: hookup PID_AUTOMATIC special pid_t value with PidRef X-Git-Tag: v257-rc1~221^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=de34ec188c4d4f682a337445aa7753259cd7f821;p=thirdparty%2Fsystemd.git pidref: hookup PID_AUTOMATIC special pid_t value with PidRef The PID_AUTOMATIC value is now properly recognized by the PidRef logic too. This needed some massaging of header includes, to ensure pidref.h can access process-util.h's definitions and vice versa. --- diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h index 0a7616443db..c9e1da39ab4 100644 --- a/src/basic/namespace-util.h +++ b/src/basic/namespace-util.h @@ -3,9 +3,11 @@ #include +typedef enum NamespaceType NamespaceType; + #include "pidref.h" -typedef enum NamespaceType { +enum NamespaceType { NAMESPACE_CGROUP, NAMESPACE_IPC, NAMESPACE_NET, @@ -16,7 +18,7 @@ typedef enum NamespaceType { NAMESPACE_TIME, _NAMESPACE_TYPE_MAX, _NAMESPACE_TYPE_INVALID = -EINVAL, -} NamespaceType; +}; extern const struct namespace_info { const char *proc_name; diff --git a/src/basic/pidref.c b/src/basic/pidref.c index 8529236c5ec..1defe863e2b 100644 --- a/src/basic/pidref.c +++ b/src/basic/pidref.c @@ -428,6 +428,10 @@ int pidref_wait_for_terminate(const PidRef *pidref, siginfo_t *ret) { } } +bool pidref_is_automatic(const PidRef *pidref) { + return pidref && pid_is_automatic(pidref->pid); +} + static void pidref_hash_func(const PidRef *pidref, struct siphash *state) { siphash24_compress_typesafe(pidref->pid, state); } diff --git a/src/basic/pidref.h b/src/basic/pidref.h index 4738c6eb5d5..8647f4bd23b 100644 --- a/src/basic/pidref.h +++ b/src/basic/pidref.h @@ -1,18 +1,26 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +typedef struct PidRef PidRef; + #include "macro.h" +#include "process-util.h" /* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes continuously. */ -typedef struct PidRef { +struct PidRef { pid_t pid; /* always valid */ int fd; /* only valid if pidfd are available in the kernel, and we manage to get an fd */ uint64_t fd_id; /* the inode number of pidfd. only useful in kernel 6.9+ where pidfds live in their own pidfs and each process comes with a unique inode number */ -} PidRef; +}; #define PIDREF_NULL (const PidRef) { .fd = -EBADF } +/* A special pidref value that we are using when a PID shall be automatically acquired from some surrounding + * context, for example connection peer. Much like PIDREF_NULL it will be considerd unset by + * pidref_is_set().*/ +#define PIDREF_AUTOMATIC (const PidRef) { .pid = PID_AUTOMATIC, .fd = -EBADF } + /* Turns a pid_t into a PidRef structure on-the-fly *without* acquiring a pidfd for it. (As opposed to * pidref_set_pid() which does so *with* acquiring one, see below) */ #define PIDREF_MAKE_FROM_PID(x) (PidRef) { .pid = (x), .fd = -EBADF } @@ -21,6 +29,8 @@ static inline bool pidref_is_set(const PidRef *pidref) { return pidref && pidref->pid > 0; } +bool pidref_is_automatic(const PidRef *pidref); + int pidref_acquire_pidfd_id(PidRef *pidref); bool pidref_equal(PidRef *a, PidRef *b); diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 2efe89e1359..c282df7701e 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -15,6 +15,7 @@ #include "format-util.h" #include "macro.h" #include "namespace-util.h" +#include "pidref.h" #include "time-util.h" #define procfs_file_alloca(pid, field) \ @@ -148,7 +149,7 @@ static inline bool sched_priority_is_valid(int i) { return i >= 0 && i <= sched_get_priority_max(SCHED_RR); } -#define PID_AUTOMATIC ((pid_t) INT_MIN) /* special value indicating "acquire pid from connection peer */ +#define PID_AUTOMATIC ((pid_t) INT_MIN) /* special value indicating "acquire pid from connection peer" */ #define PID_INVALID ((pid_t) 0) /* default value for "invalid pid" */ static inline bool pid_is_valid(pid_t p) { diff --git a/src/libsystemd/sd-json/json-util.c b/src/libsystemd/sd-json/json-util.c index 2ff45875654..0c1dea566af 100644 --- a/src/libsystemd/sd-json/json-util.c +++ b/src/libsystemd/sd-json/json-util.c @@ -185,7 +185,13 @@ int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dis * above. If SD_JSON_STRICT is set this will acquire a pidfd for the process, and validate that the * auxiliary fields match it. Otherwise, this will just store the pid and the pidfd inode number (the * latter not if the provided boot id differs from the local one), and not attempt to get a pidfd for - * it, or authenticate it. */ + * it, or authenticate it. + * + * If SD_JSON_RELAX is specified, a specified but zero/empty PID will be mapped to PIDREF_AUTOMATIC, + * which is supposed to indicate that the PID shall be automatically derived, typically from the + * connection peer. + * + * Note that SD_JSON_RELAX and SD_JSON_STRICT can be combined. */ if (sd_json_variant_is_null(variant)) { pidref_done(p); @@ -220,6 +226,13 @@ int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dis } else return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is neither a numeric PID nor a PID object.", strna(name)); + /* If SD_JSON_RELAX is set then we'll take a specified but zero field as request for "automic" PID derivation */ + if ((flags & SD_JSON_RELAX) && data.pid == 0 && data.fd_id == 0 && sd_id128_is_null(data.boot_id)) { + pidref_done(p); + *p = PIDREF_AUTOMATIC; + return 0; + } + /* Before casting the 64bit data.pid field to pid_t, let's ensure it fits the pid_t range. */ if (data.pid > PID_T_MAX || !pid_is_valid(data.pid)) return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' does not contain a valid PID.", strna(name)); diff --git a/src/test/test-pidref.c b/src/test/test-pidref.c index 53ed10d1537..7298b365968 100644 --- a/src/test/test-pidref.c +++ b/src/test/test-pidref.c @@ -224,4 +224,20 @@ TEST(pidref_verify) { assert_se(pidref_verify(&pidref) == (pidref.fd >= 0)); } +TEST(pidref_is_automatic) { + assert_se(!pidref_is_automatic(NULL)); + assert_se(!pidref_is_automatic(&PIDREF_NULL)); + assert_se(!pidref_is_automatic(&PIDREF_MAKE_FROM_PID(1))); + assert_se(!pidref_is_automatic(&PIDREF_MAKE_FROM_PID(getpid_cached()))); + assert_se(pidref_is_automatic(&PIDREF_AUTOMATIC)); + + assert_se(!pid_is_automatic(0)); + assert_se(!pid_is_automatic(1)); + assert_se(!pid_is_automatic(getpid_cached())); + assert_se(pid_is_automatic(PID_AUTOMATIC)); + + assert_se(!pidref_is_set(&PIDREF_AUTOMATIC)); + assert_se(!pid_is_valid(PID_AUTOMATIC)); +} + DEFINE_TEST_MAIN(LOG_DEBUG);