sd-bus: handle non-string keys in dictionaries in JSON dump

JSON only supports string keys in objects, but D-Bus specification is a
bit more lenient and allows dict entries to have any basic type as key.
Let's stringify allowed non-string keys so that we can represent them as
JSON objects.

Relevant snippet from the D-Bus specification:

  A DICT_ENTRY works exactly like a struct, but rather than parentheses
  it uses curly braces, and it has more restrictions. The restrictions
  are: it occurs only as an array element type; it has exactly two
  single complete types inside the curly braces; the first single
  complete type (the "key") must be a basic type rather than a container
  type. Implementations must not accept dict entries outside of arrays,
  must not accept dict entries with zero, one, or more than two fields,
  and must not accept dict entries with non-basic-typed keys. A dict
  entry is always a key-value pair.

Resolves: #32904
This commit is contained in:
Frantisek Sumsal
2026-05-13 07:50:32 +09:00
committed by Yu Watanabe
parent 304899fa57
commit 7cecff8c99
2 changed files with 33 additions and 2 deletions
+27 -2
View File
@@ -72,6 +72,7 @@ static int json_transform_dict_array(sd_bus_message *m, sd_json_variant **ret) {
CLEANUP_ARRAY(elements, n_elements, sd_json_variant_unref_many);
for (;;) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *key = NULL;
const char *contents;
char type;
@@ -94,11 +95,35 @@ static int json_transform_dict_array(sd_bus_message *m, sd_json_variant **ret) {
if (r < 0)
return r;
r = json_transform_one(m, elements + n_elements);
r = json_transform_one(m, &key);
if (r < 0)
return r;
n_elements++;
/* JSON only supports string keys in objects, but D-Bus specification is a bit more lenient
* and allows dict entries to have any basic type as key. Let's stringify allowed non-string
* keys so that we can represent them as JSON objects. */
if (!sd_json_variant_is_string(key)) {
_cleanup_free_ char *s = NULL;
if (!IN_SET(sd_json_variant_type(key),
SD_JSON_VARIANT_BOOLEAN,
SD_JSON_VARIANT_INTEGER,
SD_JSON_VARIANT_REAL,
SD_JSON_VARIANT_UNSIGNED))
return -EINVAL;
r = sd_json_variant_format(key, /* flags= */ 0, &s);
if (r < 0)
return r;
key = sd_json_variant_unref(key);
r = sd_json_variant_new_string(&key, s);
if (r < 0)
return r;
}
elements[n_elements++] = TAKE_PTR(key);
r = json_transform_one(m, elements + n_elements);
if (r < 0)
+6
View File
@@ -43,6 +43,12 @@ busctl call --json=short \
busctl call -j \
org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.DBus.Properties \
GetAll s "org.freedesktop.systemd1.Manager" | jq -c
# Do the same with D-Bus' org.freedesktop.DBus.Debug.Stats interface which also provides some
# complex signatures that caused issues during the JSON conversion in the past
# See: https://github.com/systemd/systemd/issues/32904
busctl call --json=pretty \
org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.Debug.Stats \
GetStats | jq -c
busctl call --verbose --timeout=60 --expect-reply=yes \
org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \
ListUnitsByPatterns asas 1 "active" 2 "systemd-*.socket" "*.mount"