]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
json-util: initialize "remote" flag for PidRef when parsing JSON pidref serializations 34719/head
authorLennart Poettering <lennart@poettering.net>
Fri, 11 Oct 2024 15:14:26 +0000 (17:14 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 15 Oct 2024 16:26:05 +0000 (18:26 +0200)
Now that we have a way to recognize "remoteness" of a PidRef, let's make
sure when we decode a JSON pidref we initialize things that way.

src/libsystemd/sd-json/json-util.c
src/test/test-json.c

index 4c978850c4ad0e06d3bcd8508da913cde5023a6b..d42c61a69c7c1a00965544201d0f6e8beb22c6fe 100644 (file)
@@ -151,7 +151,7 @@ int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispa
 }
 
 int json_variant_new_pidref(sd_json_variant **ret, PidRef *pidref) {
-        sd_id128_t boot_id;
+        sd_id128_t boot_id = SD_ID128_NULL;
         int r;
 
         /* Turns a PidRef into a triplet of PID, pidfd inode nr, and the boot ID. The triplet should uniquely
@@ -160,22 +160,24 @@ int json_variant_new_pidref(sd_json_variant **ret, PidRef *pidref) {
         if (!pidref_is_set(pidref))
                 return sd_json_variant_new_null(ret);
 
-        r = pidref_acquire_pidfd_id(pidref);
-        if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r) && r != -ENOMEDIUM)
-                return r;
+        if (!pidref_is_remote(pidref)) {
+                r = pidref_acquire_pidfd_id(pidref);
+                if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r) && r != -ENOMEDIUM)
+                        return r;
 
-        if (pidref->fd_id > 0) {
                 /* If we have the pidfd inode number, also acquire the boot ID, to make things universally unique */
-                r = sd_id128_get_boot(&boot_id);
-                if (r < 0)
-                        return r;
+                if (pidref->fd_id > 0) {
+                        r = sd_id128_get_boot(&boot_id);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         return sd_json_buildo(
                         ret,
                         SD_JSON_BUILD_PAIR_INTEGER("pid", pidref->pid),
                         SD_JSON_BUILD_PAIR_CONDITION(pidref->fd_id > 0, "pidfdId", SD_JSON_BUILD_INTEGER(pidref->fd_id)),
-                        SD_JSON_BUILD_PAIR_CONDITION(pidref->fd_id > 0, "bootId", SD_JSON_BUILD_ID128(boot_id)));
+                        SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(boot_id), "bootId", SD_JSON_BUILD_ID128(boot_id)));
 }
 
 int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
@@ -252,7 +254,7 @@ int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dis
                 } else {
                         local_boot_id = sd_id128_equal(data.boot_id, my_boot_id);
                         if (!local_boot_id) {
-                                json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), 0, "JSON field '%s' refers to non-local PID.", strna(name));
+                                json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), 0, "JSON field '%s' refers to non-local PID%s.", strna(name), FLAGS_SET(flags, SD_JSON_STRICT) ? "" : ", proceeding");
                                 if (FLAGS_SET(flags, SD_JSON_STRICT))
                                         return -ESRCH;
                         }
@@ -260,35 +262,41 @@ int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dis
         }
 
         _cleanup_(pidref_done) PidRef np = PIDREF_NULL;
-        if (local_boot_id != 0) {
-                /* Try to acquire a pidfd – unless this is definitely not a local PID */
+        if (local_boot_id == 0)
+                /* If this is definitely not the local boot ID, then mark the PidRef as remote in the sense of pidref_is_remote() */
+                np = (PidRef) {
+                        .pid = data.pid,
+                        .fd = -EREMOTE,
+                        .fd_id = data.fd_id,
+                };
+        else {
+                /* Try to acquire a pidfd if this is or might be a local PID */
                 r = pidref_set_pid(&np, data.pid);
                 if (r < 0) {
                         json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), r, "Unable to get fd for PID in JSON field '%s': %m", strna(name));
                         if (FLAGS_SET(flags, SD_JSON_STRICT))
                                 return r;
-                }
-        }
-
-        /* If the the PID is dead or we otherwise can't get a pidfd of it, then store at least the PID number */
-        if (!pidref_is_set(&np))
-                np = PIDREF_MAKE_FROM_PID(data.pid);
 
-        /* If the pidfd inode nr is specified, validate it or at least state */
-        if (data.fd_id > 0) {
-                if (np.fd >= 0) {
-                        r = pidref_acquire_pidfd_id(&np);
-                        if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r))
-                                return json_log(variant, flags, r, "Unable to get pidfd ID to validate JSON field '%s': %m", strna(name));
+                        /* If the PID is dead or we otherwise can't get a pidfd of it, then store at least the PID number */
+                        np = PIDREF_MAKE_FROM_PID(data.pid);
+                }
 
-                        if (data.fd_id != np.fd_id) {
-                                json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), 0, "JSON field '%s' references PID with non-matching inode number.", strna(name));
-                                if (FLAGS_SET(flags, SD_JSON_STRICT))
-                                        return -ESRCH;
+                /* If the pidfd inode nr is specified, validate it or at least state */
+                if (data.fd_id > 0) {
+                        if (np.fd >= 0) {
+                                r = pidref_acquire_pidfd_id(&np);
+                                if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r))
+                                        return json_log(variant, flags, r, "Unable to get pidfd ID to validate JSON field '%s': %m", strna(name));
+
+                                if (data.fd_id != np.fd_id) {
+                                        json_log(variant, flags | (FLAGS_SET(flags, SD_JSON_STRICT) ? 0 : SD_JSON_DEBUG), 0, "JSON field '%s' references PID with non-matching inode number.", strna(name));
+                                        if (FLAGS_SET(flags, SD_JSON_STRICT))
+                                                return -ESRCH;
+                                }
+                        } else {
+                                json_log(variant, flags|SD_JSON_DEBUG, 0, "Not validating PID inode number on JSON field '%s', because operating without pidfd.", strna(name));
+                                np.fd_id = data.fd_id;
                         }
-                } else if (local_boot_id != 0) {
-                        json_log(variant, flags|SD_JSON_DEBUG, 0, "Not validating PID inode number on JSON field '%s', because operating without pidfd.", strna(name));
-                        np.fd_id = data.fd_id;
                 }
         }
 
index 75dff429d51334570b76c3d80debcc28fdd96758..c4df19e08dcd7aba7fd4ce409d2db4ee012a9c58 100644 (file)
@@ -1272,24 +1272,34 @@ TEST(pidref) {
         assert_se(pidref_set_pid(&pid1, 1) >= 0);
 
         _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+        sd_id128_t randomized_boot_id;
+        assert_se(sd_id128_randomize(&randomized_boot_id) >= 0);
         assert_se(sd_json_buildo(&v,
                                  JSON_BUILD_PAIR_PIDREF("myself", &myself),
-                                 JSON_BUILD_PAIR_PIDREF("pid1", &pid1)) >= 0);
+                                 JSON_BUILD_PAIR_PIDREF("pid1", &pid1),
+                                 SD_JSON_BUILD_PAIR("remote", SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR_UNSIGNED("pid", 1),
+                                                                                   SD_JSON_BUILD_PAIR_UNSIGNED("pidfdId", 4711),
+                                                                                   SD_JSON_BUILD_PAIR_ID128("bootId", randomized_boot_id))),
+                                 SD_JSON_BUILD_PAIR("automatic", SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR_UNSIGNED("pid", 0)))) >= 0);
 
         sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
 
         struct {
-                PidRef myself, pid1;
+                PidRef myself, pid1, remote, automatic;
         } data = {
                 .myself = PIDREF_NULL,
                 .pid1 = PIDREF_NULL,
+                .remote = PIDREF_NULL,
+                .automatic = PIDREF_NULL,
         };
 
         assert_se(sd_json_dispatch(
                                   v,
                                   (const sd_json_dispatch_field[]) {
-                                          { "myself", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, myself), 0 },
-                                          { "pid1", _SD_JSON_VARIANT_TYPE_INVALID,   json_dispatch_pidref, voffsetof(data, pid1),   0 },
+                                          { "myself",    _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, myself),    SD_JSON_STRICT },
+                                          { "pid1",      _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, pid1),      SD_JSON_STRICT },
+                                          { "remote",    _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, remote),    0              },
+                                          { "automatic", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, automatic), SD_JSON_RELAX  },
                                           {},
                                   },
                                   /* flags= */ 0,
@@ -1300,12 +1310,20 @@ TEST(pidref) {
 
         assert_se(!pidref_equal(&myself, &data.pid1));
         assert_se(!pidref_equal(&pid1, &data.myself));
+        assert_se(!pidref_equal(&myself, &data.remote));
+        assert_se(!pidref_equal(&pid1, &data.remote));
 
         assert_se((myself.fd_id > 0) == (data.myself.fd_id > 0));
         assert_se((pid1.fd_id > 0) == (data.pid1.fd_id > 0));
 
+        assert_se(!pidref_is_set(&data.automatic));
+        assert_se(pidref_is_automatic(&data.automatic));
+        assert_se(pidref_is_set(&data.remote));
+        assert_se(pidref_is_remote(&data.remote));
+
         pidref_done(&data.myself);
         pidref_done(&data.pid1);
+        pidref_done(&data.remote);
 }
 
 TEST(devnum) {