sd-varlink: Return empty object for missing params

Previously, sd-varlink was inconsistent about what it did with
empty/missing/null parameters in a Varlink call or reply: when
dispatching to a callback, it would always construct an empty object and
hand over the empty object to the handler (good!). But when returning
the value directly (i.e. with sd_varlink_call), it would return NULL
when parameters were omitted and a JSON null when the paramerters were
null.

This inconsistency is a violation of UAPI.20, which states that
receivers of Varlink messages MUST treat omitted/null/empty parameters
on Varlink calls and replies equivalently, where senders only SHOULD
prefer to omit the parameters.

This commit makes sd-varlink normalize the parameters to an empty object
whenever it is null or omitted, which brings sd-varlink into compliance
with this rule in UAPI.20

(cherry picked from commit 34db99971e728e2c4f155c01d43d24f3fe313bef)
This commit is contained in:
Adrian Vovk
2026-10-16 17:24:52 +01:00
committed by Luca Boccassi
parent adc93a4ad5
commit ffcf226c7f
2 changed files with 38 additions and 20 deletions
@@ -380,5 +380,24 @@ echo "$result" | grep "untrusted data decompressed safely" >/dev/null
kill "$SERVE_PID" 2>/dev/null || true
wait "$SERVE_PID" 2>/dev/null || true
# Verify consistent handling of omitted/null/empty parameters
check_output_is_empty_object() {
REPLY="$1"
# This is a "Varlink server" that reads the incoming call, discards it, and
# directly sends the contents of $REPLY as the reply. This lets us exercise
# sd-varlink's client-side parsing of the Varlink call/reply framing
# shellcheck disable=SC2016
SERVE_PID=$(systemd-notify --fork -- \
systemd-socket-activate -l "$SERVE_SOCKET" --inetd -a -- \
bash -c 'read -r -d "" _; printf "%s\0" "$0"' "$REPLY")
varlinkctl call "unix:$SERVE_SOCKET" com.example.Test '{}' | grep "^{}$"
varlinkctl --exec call "unix:$SERVE_SOCKET" com.example.Test '{}' -- grep "^{}$"
kill "$SERVE_PID" 2>/dev/null || true
wait "$SERVE_PID" 2>/dev/null || true
}
check_output_is_empty_object '{}'
check_output_is_empty_object '{"parameters": null}'
check_output_is_empty_object '{"parameters": {}}'
rm -f "$SERVE_SOCKET"
rm -rf "$(dirname "$SERVE_SOCKET")" "$SERVE_TMPDIR"