summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2024-10-14 12:31:57 +0200
committerLennart Poettering <lennart@poettering.net>2024-10-14 12:44:36 +0200
commitde34ec188c4d4f682a337445aa7753259cd7f821 (patch)
treec9b0b4c8d6716185324158c150f9b49a3233f4fe /src
parentMerge pull request #34716 from dvdhrm/pr/derand (diff)
downloadsystemd-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.h6
-rw-r--r--src/basic/pidref.c4
-rw-r--r--src/basic/pidref.h14
-rw-r--r--src/basic/process-util.h3
-rw-r--r--src/libsystemd/sd-json/json-util.c15
-rw-r--r--src/test/test-pidref.c16
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);