diff options
author | Lennart Poettering <lennart@poettering.net> | 2024-10-14 12:31:57 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2024-10-14 12:44:36 +0200 |
commit | de34ec188c4d4f682a337445aa7753259cd7f821 (patch) | |
tree | c9b0b4c8d6716185324158c150f9b49a3233f4fe /src | |
parent | Merge pull request #34716 from dvdhrm/pr/derand (diff) | |
download | systemd-de34ec188c4d4f682a337445aa7753259cd7f821.tar.xz systemd-de34ec188c4d4f682a337445aa7753259cd7f821.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/namespace-util.h | 6 | ||||
-rw-r--r-- | src/basic/pidref.c | 4 | ||||
-rw-r--r-- | src/basic/pidref.h | 14 | ||||
-rw-r--r-- | src/basic/process-util.h | 3 | ||||
-rw-r--r-- | src/libsystemd/sd-json/json-util.c | 15 | ||||
-rw-r--r-- | src/test/test-pidref.c | 16 |
6 files changed, 52 insertions, 6 deletions
diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h index 0a7616443d..c9e1da39ab 100644 --- a/src/basic/namespace-util.h +++ b/src/basic/namespace-util.h @@ -3,9 +3,11 @@ #include <sys/types.h> +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 8529236c5e..1defe863e2 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 4738c6eb5d..8647f4bd23 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 2efe89e135..c282df7701 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 2ff4587565..0c1dea566a 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 53ed10d153..7298b36596 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); |