Skip to content

exec_pty: keep user tty output flags in sync with the command - #570

Open
ElenaFri wants to merge 1 commit into
sudo-project:mainfrom
ElenaFri:fix-349-stderr-pipe-oflag
Open

ElenaFri wants to merge 1 commit into
sudo-project:mainfrom
ElenaFri:fix-349-stderr-pipe-oflag

Conversation

@ElenaFri

Copy link
Copy Markdown
Contributor

Preserve the user terminal's output flags (OPOST/ONLCR) when stderr
is redirected to a pipe, socket or FIFO, and keep them in sync with the
command's pty while it runs (sync_user_oflag()). When the command's
pty performs output post-processing, the user terminal keeps it too;
when the command switches its pty to raw mode (e.g. a full-screen
program), the user terminal follows and goes raw as well.

Normal sessions are unaffected: the sync only arms when stderr is
redirected away from the terminal, and it reuses the existing
sudo_term_raw() interface, so there is no library ABI change.

Testing

With the fix installed:

sudo strace -f /bin/sh -c 'for i in 1 2 3 4; do echo ligne $i; done' \
    2> >(tee /tmp/err.log)

now renders with every line aligned to the left margin instead of
staircased. make check passes for lib/util and src.

Known limitation

While a command holds its own pty in raw mode (full-screen/ncurses
programs such as vim or top), stderr echoed back to the now-raw terminal
by an external reader can still staircase: a single line discipline
cannot serve both sudo's relayed cooked output and an uncontrolled raw
third-party stream. This is no worse than the current behaviour. For
that case strace -o file, sudo I/O logging, or Defaults>root !use_pty remain the appropriate workarounds.

Fixes GitHub issue #349

When use_pty is enabled (the default) and the command's stderr is
redirected to a pipe, socket or FIFO while its stdout is still the
user's terminal, a third party reading that stderr (e.g. the tee in
"sudo strace cmd 2> >(tee log)") writes back to the terminal itself.
Since the terminal was in raw mode, the newline-only output was
rendered staircased.

Statically preserving the terminal's output flags, as is done for a
piped stdout (commit 78b7121), would fix this but regress full-screen
commands, which run their pty raw and emit bare newlines that ONLCR
would mangle.  Instead, track the command's OPOST state via its pty
and toggle the user terminal's output flags to match as output is
relayed: ONLCR while the command is cooked, raw while it is not.  This
is gated on stderr being a pipe/socket/FIFO, reuses sudo_term_raw()
(no ABI change) and caches the applied state.

While a full-screen command holds its pty raw, stderr echoed to the
terminal by an external reader is still staircased; a single line
discipline cannot serve both sudo's relayed output and a raw stream
sudo does not control.  This is no worse than before.

Fixes GitHub issue sudo-project#349
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant