From: Luca Boccassi Date: Thu, 11 Jun 2026 15:13:11 +0000 (+0100) Subject: ask-password: do not reuse flags across Varlink calls X-Git-Tag: v261-rc4~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=92e4afc4d3045148e9749b30e890d3f09d8c7eda;p=thirdparty%2Fsystemd.git ask-password: do not reuse flags across Varlink calls The flags parameter is parsed into a global variable, which means when there are multiple consecutive calls it is reused. Switch to a local copy. Follow-up for 066f6bfb6278962e288cce2ba522a2e400980e7c Assisted-by: kres (claude-opus-4-7) Co-developed-by: Claude Opus 4.8 --- diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index 6a1abf5f999..17d839e98dd 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -250,6 +250,8 @@ static int vl_method_ask(sd_varlink *link, sd_json_variant *parameters, sd_varli .push_cache = -1, .echo_mode = _ECHO_MODE_INVALID, }; + /* Local copy so that parameters passed are per-invocation */ + AskPasswordFlags ask_flags = arg_flags; int r; assert(link); @@ -285,21 +287,21 @@ static int vl_method_ask(sd_varlink *link, sd_json_variant *parameters, sd_varli req.until = MIN(usec_add(now(CLOCK_MONOTONIC), p.timeout_usec), p.until_usec); /* If the timeout is set to zero, don't ask agents, just stick to cache */ - SET_FLAG(arg_flags, ASK_PASSWORD_NO_AGENT, req.until == 0); + SET_FLAG(ask_flags, ASK_PASSWORD_NO_AGENT, req.until == 0); if (p.accept_cached >= 0) - SET_FLAG(arg_flags, ASK_PASSWORD_ACCEPT_CACHED, p.accept_cached); + SET_FLAG(ask_flags, ASK_PASSWORD_ACCEPT_CACHED, p.accept_cached); if (p.push_cache >= 0) - SET_FLAG(arg_flags, ASK_PASSWORD_PUSH_CACHE, p.push_cache); + SET_FLAG(ask_flags, ASK_PASSWORD_PUSH_CACHE, p.push_cache); if (p.echo_mode >= 0) { - SET_FLAG(arg_flags, ASK_PASSWORD_ECHO, p.echo_mode == ECHO_ON); - SET_FLAG(arg_flags, ASK_PASSWORD_SILENT, p.echo_mode == ECHO_OFF); + SET_FLAG(ask_flags, ASK_PASSWORD_ECHO, p.echo_mode == ECHO_ON); + SET_FLAG(ask_flags, ASK_PASSWORD_SILENT, p.echo_mode == ECHO_OFF); } _cleanup_strv_free_erase_ char **l = NULL; - r = ask_password_auto(&req, arg_flags, &l); + r = ask_password_auto(&req, ask_flags, &l); if (r == -EUNATCH) return sd_varlink_error(link, "io.systemd.AskPassword.NoPasswordAvailable", NULL); if (r == -ETIME) diff --git a/test/units/TEST-74-AUX-UTILS.ask-password.sh b/test/units/TEST-74-AUX-UTILS.ask-password.sh index 421ebb74b78..ef0c1aa9e7d 100755 --- a/test/units/TEST-74-AUX-UTILS.ask-password.sh +++ b/test/units/TEST-74-AUX-UTILS.ask-password.sh @@ -6,9 +6,15 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh +KEY="" +SOCKET_DIR="" + at_exit() { set +e systemctl stop waldo-ask-pw-agent.service + systemctl stop test-askpw.service + [[ -n "$KEY" ]] && keyctl unlink "$KEY" @u + rm -rf "$SOCKET_DIR" } trap at_exit EXIT @@ -22,3 +28,23 @@ varlinkctl introspect /run/systemd/io.systemd.AskPassword systemd-run -u waldo-ask-pw-agent.service -p Environment=SYSTEMD_ASK_PASSWORD_AGENT_PASSWORD=waldo -p Type=notify systemd-tty-ask-password-agent --watch --console=/dev/console assert_eq "$(systemd-ask-password --no-tty)" "waldo" assert_eq "$(varlinkctl call /usr/bin/systemd-ask-password io.systemd.AskPassword.Ask '{"message":"foobar"}' | jq '.passwords[0]')" "\"waldo\"" + +# Per-request Varlink Ask flags must not leak across calls sharing one connection +SOCKET_DIR="$(mktemp -d)" +sock="$SOCKET_DIR/ask.sock" +KEY="$(keyctl add user test-askpw hunter2 @u)" + +systemd-run --unit=test-askpw.service -p Type=notify -p KeyringMode=shared \ + systemd-socket-activate --accept --fdname=varlink -l "$sock" -- \ + systemd-ask-password + +# timeoutUSec:0 disables the agent, so the keyring cache is the only source. +req_cached='{"method":"io.systemd.AskPassword.Ask","parameters":{"keyname":"test-askpw","timeoutUSec":0,"acceptCached":true}}' +req_plain='{"method":"io.systemd.AskPassword.Ask","parameters":{"keyname":"test-askpw","timeoutUSec":0}}' +printf '%s\0%s\0' "$req_cached" "$req_plain" | socat -t20 - "UNIX-CONNECT:$sock" >"$SOCKET_DIR/replies" +mapfile -d '' -t replies <"$SOCKET_DIR/replies" + +assert_eq "${#replies[@]}" "2" +assert_in "hunter2" "${replies[0]}" +assert_not_in "hunter2" "${replies[1]}" +assert_in "NoPasswordAvailable" "${replies[1]}"