fix: refuse stdin to a privileged command while a sudo password is set
CI / test (3.10) (push) Successful in 1m2s
CI / test (3.11) (push) Successful in 47s
CI / test (3.12) (push) Successful in 42s
CI / test (3.10) (pull_request) Successful in 43s
CI / test (3.11) (pull_request) Successful in 46s
CI / test (3.12) (pull_request) Successful in 51s

run_command(privileged=True, stdin=data) sent `sudo -S` with stdin =
<sudo password>\n + data. A sudo that does not prompt (NOPASSWD, a cached
timestamp) leaves the password line on stdin, and the command reads it as
the first line of the data - `cat > file` wrote it into the file
(NetOrk/netork#1029).

run_command now raises ValueError for that combination before opening a
channel. Stdin still reaches the command under `sudo -n` (no password set),
for a root login, and for unprivileged commands. Callers stage the data
without privilege and have root install the file. open_stream documents the
same caveat.
This commit is contained in:
Christian Manivong committed 2026-10-12 20:41:06 +02:00
1 parent 7bd005eb29
commit 647e058b8a
3 files changed
+72 -7

No files matched your search

+25 -3
View File
@@ -132,6 +132,16 @@ _YUM_SECURITY_COMMAND = "LC_ALL=C yum updateinfo list security -q 2>/dev/null"
#: cannot take the restart with it.
_REBOOT_DETACHED = "sh -c '(trap \"\" HUP; sleep 2; /sbin/reboot) </dev/null >/dev/null 2>&1 &'"
#: Why ``run_command`` refuses stdin to a privileged command while a sudo
#: password is set (NetOrk/netork#1029).
_PRIVILEGED_STDIN = (
"run_command(privileged=True) takes no stdin while a sudo password is set: "
"sudo -S reads the password from stdin, and a sudo that does not prompt "
"(NOPASSWD, a cached timestamp) leaves it for the command, which would read it "
"as the first line of the data. Stage the data without privilege (umask 077, "
"mktemp, cat) and have root install that file."
)
#: What to do when sudo wants a password netOrk does not have.
_SUDO_PASSWORD_HINT = (
"sudo requires a password on this device but none is configured in netOrk. "
@@ -428,13 +438,25 @@ class LinuxDriver(
timeout: float = 60,
stdin: bytes | None = None,
) -> CommandResult:
"""Run *command* on an exec channel: no PTY, stderr apart, a real exit code."""
"""Run *command* on an exec channel: no PTY, stderr apart, a real exit code.
:raises ValueError: for *stdin* to a privileged command while a sudo
password is set (see ``_PRIVILEGED_STDIN``).
"""
line, prefix = self._privileged(command, privileged)
data = (prefix or b"") + (stdin or b"") if (prefix or stdin) else None
if prefix and stdin is not None:
raise ValueError(_PRIVILEGED_STDIN)
data = prefix or stdin or None
return run_on_transport(self._transport(), line, stdin=data, timeout=timeout)
def open_stream(self, command: str, *, privileged: bool = False) -> ByteStream:
"""Start *command* on an exec channel and return a stream to it."""
"""Start *command* on an exec channel and return a stream to it.
A privileged stream with a sudo password starts with that password, for
``sudo -S``; a sudo that does not prompt leaves it for *command*. Write
nothing to such a stream that must not follow the password, as
``_PRIVILEGED_STDIN`` says for ``run_command``.
"""
line, prefix = self._privileged(command, privileged)
return open_stream_on_transport(self._transport(), line, stdin_prefix=prefix)