From bb9bb5521102d8846c14054ec502f64ee95a0688 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 26 Mar 2024 16:28:33 +0100 Subject: [PATCH] vsh: Fix 'stdin' closing in 'cmdComplete' While the 'complete' command is meant to be hidden and used only for the completion script, there's nothing preventing it being used in all virsh modes. This poses a problem as the command tries to close 'stdin' to avoid the possibility that an auth callback would want to read the password. In interactive mode this immediately terminates virsh and in non-interactive mode it attempts to close it multiple times if you use virsh in batch mode. Fix the issues by using virOnce() to close it exactly once and do so only in non-interactive mode. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- tools/vsh.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tools/vsh.c b/tools/vsh.c index 3fd567c1bf..1e8be2393e 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -3405,11 +3405,25 @@ const vshCmdInfo info_complete = { #ifdef WITH_READLINE + +static virOnceControl vshCmdCompleteCloseStdinOnce = VIR_ONCE_CONTROL_INITIALIZER; + +static void +vshCmdCompleteCloseStdin(void) +{ + /* In non-interactive mode which is how the 'complete' command is intended + * to be used we need to ensure that any authentication callback will not + * attempt to read any input which would break the completion */ + int stdin_fileno = STDIN_FILENO; + + VIR_FORCE_CLOSE(stdin_fileno); +} + + bool cmdComplete(vshControl *ctl, const vshCmd *cmd) { const vshClientHooks *hooks = ctl->hooks; - int stdin_fileno = STDIN_FILENO; const char *arg = ""; const vshCmdOpt *opt = NULL; g_auto(GStrv) matches = NULL; @@ -3422,7 +3436,10 @@ cmdComplete(vshControl *ctl, const vshCmd *cmd) /* This command is flagged VSH_CMD_FLAG_NOCONNECT because we * need to prevent auth hooks reading any input. Therefore, we * have to close stdin and then connect ourselves. */ - VIR_FORCE_CLOSE(stdin_fileno); + if (!ctl->imode) { + if (virOnce(&vshCmdCompleteCloseStdinOnce, vshCmdCompleteCloseStdin) < 0) + return false; + } if (!(hooks && hooks->connHandler && hooks->connHandler(ctl))) return false;