When a command is run via "sudo -b" it has no access to terminal
input. In non-pty mode, the command runs in an orphaned process
group and reads from the controlling terminal fail with EIO. We
cannot do the same while running in a pty but if we set stdin to a
half-closed pipe, reads from it will get EOF. That is close enough.
Changes made to the terminal settings while the command is suspended
are now reflected in the pty when the command is resumed. This is
more consistent with the non-pty behavior and allows for the removal
of the "tty_initialized" global. One downside to this change is
that if a terminal-based program using the pty is stopped with
SIGSTOP it may have the wrong terminal settings on resume.
However, this is no different from the non-pty case.
Previously, we only did this when running in the foreground but
this can cause problems when running a program that reads the
terminal settings or window size in the background. If sudo is
running in the background, the terminal settings will be updated
if it transitions to the foreground process.
Based on a suggestion from From Duncan Overbruck.
While we cannot catch SIGSTOP, we _can_ catch SIGCONT and set
/dev/tty to raw mode when running in the foreground. Ignore SIGCONT
in suspend_sudo_pty() so we don't call resume_terminal() twice.
This fixes a hang when there is /dev/tty data in a buffer to be
flushed by the final call to del_io_events(). We do not want to
re-enable the reader when flushing the buffers as part of pty_finish().
See PR #247 for analysis of the problem and how to reproduce it.
If sudo is not the process group leader and stdin is not a tty, we
may be running as a background job via a shell script. Start the
command in the background to avoid changing the terminal mode from
a background process. GitHub issue #237
When sudo is not the process group leader, we still need to stop
sudo's process group and not just the sudo process itself. If we
only send the signal to sudo itself, the shell will not notice if
it is not in monitor mode. This can happen when sudo is run from
a shell script, for example. In this case we need to signal the
shell itself. If the process group leader is no longer present,
we must kill the command since there will be no one to resume us.
If sudo is not the process group leader we must only send the suspend
signal to sudo itself. When sudo is run via a shell script, it
usually has the same process group as the shell script interpreter.
We do not want to suspend the script itself when the command run
by sudo is suspended.
If we are logging I/O but not terminal input/output (either because
no terminal is present or because that is what the plugin requested),
the non-pty exec path is now taken.
This will be shared with exec_nopty.c in the future to log
stdin/stdout/stderr without running the command in a pty.
Both exec_pty.c and exec_nopty.c now use the same closure.
When ptracing a process, we receive the signal-delivery-stop signal
before the group-stop signal. If sudo is running the command in
the same terminal, we need to wait until the stop signal is actually
delivered to the command before we can suspend sudo itself. If we
suspend sudo before receiving the group-stop, the command will be
restarted with PTRACE_LISTEN too late and will miss the SIGCONT
from sudo.
This allows intercept mode to work with shells that close all open
fds upon startup. The ctor in sudo_intercept.so requests the port
number and secret over the socket inherited from the parent then
closes it. For each policy request, a TCP connection is made to
the sudo parent process to perform the policy check. Child processes
re-use the TCP socket to request the port number and secret just like
the initial process started by sudo does.
The goal is to make it harder for someone to have a fake policy checker.
This will not stop a determined adversary since the secret is present
in the address space of the running process.