Skip to content

Commit

Permalink
"Fix" the ignored sigtstp test
Browse files Browse the repository at this point in the history
  • Loading branch information
pvdrz committed Jun 16, 2023
1 parent ec80bc4 commit 21c7d8b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 32 deletions.
18 changes: 7 additions & 11 deletions sudo/lib/exec/backchannel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ use std::{
mem::size_of,
os::{
fd::{AsRawFd, RawFd},
unix::{net::UnixStream, process::ExitStatusExt},
unix::net::UnixStream,
},
process::ExitStatus,
};

use crate::system::{interface::ProcessId, signal::SignalNumber};

use super::signal_fmt;
use super::{signal_fmt, ExitReason};

type Prefix = u8;
type ParentData = c_int;
Expand Down Expand Up @@ -89,14 +88,11 @@ impl From<io::Error> for ParentMessage {
}
}

impl From<ExitStatus> for ParentMessage {
fn from(status: ExitStatus) -> Self {
if let Some(code) = status.code() {
Self::CommandExit(code)
} else {
// `ExitStatus::code` docs state that it only returns `None` if the process was
// terminated by a signal so this should always succeed.
Self::CommandSignal(status.signal().unwrap())
impl From<ExitReason> for ParentMessage {
fn from(reason: ExitReason) -> Self {
match reason {
ExitReason::Code(code) => Self::CommandExit(code),
ExitReason::Signal(signal) => Self::CommandSignal(signal),
}
}
}
Expand Down
46 changes: 26 additions & 20 deletions sudo/lib/exec/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::{
time::Duration,
};

use crate::log::{dev_info, dev_warn};
use crate::system::{
fork, getpgid,
interface::ProcessId,
Expand All @@ -18,13 +17,18 @@ use crate::system::{
term::{set_controlling_terminal, tcgetpgrp, tcsetpgrp},
wait::{waitpid, WaitError, WaitOptions},
};
use crate::{
exec::event::StopReason,
log::{dev_info, dev_warn},
};

use signal_hook::consts::*;

use super::{
backchannel::{MonitorBackchannel, MonitorMessage, ParentMessage},
event::{EventClosure, EventDispatcher},
io_util::{retry_while_interrupted, was_interrupted},
ExitReason,
};
#[cfg(feature = "dev")]
use super::{cond_fmt, signal_fmt};
Expand Down Expand Up @@ -104,10 +108,17 @@ pub(super) fn exec_monitor(
// FIXME (ogsudo): Set the command as the foreground process for the follower.

// Start the event loop.
dispatcher.event_loop(&mut closure);
let reason = dispatcher.event_loop(&mut closure);
// FIXME (ogsudo): Terminate the command using `killpg` if it's not terminated.
// FIXME (ogsudo): Take the controlling tty so the command's children don't receive SIGHUP when we exit.
// FIXME (ogsudo): Send the command status back to the parent.

match reason {
StopReason::Break(()) => {}
StopReason::Exit(exit_reason) => {
closure.backchannel.send(&exit_reason.into()).ok();
}
}

// FIXME (ogsudo): The tty is restored here if selinux is available.

drop(closure);
Expand Down Expand Up @@ -181,6 +192,7 @@ impl<'a> MonitorClosure<'a> {
// There's something wrong with the backchannel, break the event loop
Err(err) => {
dev_warn!("monitor could not read from backchannel: {}", err);
// FIXME: maybe the break reason should be `io::Error` instead.
dispatcher.set_break(());
self.backchannel.send(&err.into()).unwrap();
}
Expand All @@ -199,7 +211,7 @@ impl<'a> MonitorClosure<'a> {
}
}

fn handle_sigchld(&mut self, command_pid: ProcessId) {
fn handle_sigchld(&mut self, command_pid: ProcessId, dispatcher: &mut EventDispatcher<Self>) {
let status = loop {
match waitpid(command_pid, WaitOptions::new().untraced().no_hang()) {
Ok((_pid, status)) => break status,
Expand All @@ -212,25 +224,24 @@ impl<'a> MonitorClosure<'a> {
dev_info!("command ({command_pid}) exited with status code {exit_code}");
// The command did exit, set it's PID to `None`.
self.command_pid = None;
self.backchannel
.send(&ParentMessage::CommandExit(exit_code))
.ok();
dispatcher.set_exit(ExitReason::Code(exit_code))
} else if let Some(signal) = status.term_signal() {
dev_info!(
"command ({command_pid}) was terminated by {}",
signal_fmt(signal),
);
// The command was terminated, set it's PID to `None`.
self.command_pid = None;
self.backchannel
.send(&ParentMessage::CommandSignal(signal))
.ok();
} else if let Some(_signal) = status.stop_signal() {
// FIXME: we should save the foreground process group ID so we can restore it later.
dispatcher.set_exit(ExitReason::Signal(signal))
} else if let Some(signal) = status.stop_signal() {
dev_info!(
"command ({command_pid}) was stopped by {}",
signal_fmt(_signal),
signal_fmt(signal),
);
// FIXME: we should save the foreground process group ID so we can restore it later.
self.backchannel
.send(&ParentMessage::CommandSignal(signal))
.ok();
} else if status.did_continue() {
dev_info!("command ({command_pid}) continued execution");
} else {
Expand Down Expand Up @@ -309,7 +320,7 @@ fn is_self_terminating(

impl<'a> EventClosure for MonitorClosure<'a> {
type Break = ();
type Exit = ();
type Exit = ExitReason;

fn on_signal(&mut self, info: SignalInfo, dispatcher: &mut EventDispatcher<Self>) {
dev_info!(
Expand All @@ -326,12 +337,7 @@ impl<'a> EventClosure for MonitorClosure<'a> {
};

match info.signal() {
SIGCHLD => {
self.handle_sigchld(command_pid);
if self.command_pid.is_none() {
dispatcher.set_exit(());
}
}
SIGCHLD => self.handle_sigchld(command_pid, dispatcher),
// Skip the signal if it was sent by the user and it is self-terminating.
_ if info.is_user_signaled()
&& is_self_terminating(info.pid(), command_pid, self.command_pgrp) => {}
Expand Down
4 changes: 3 additions & 1 deletion sudo/lib/exec/parent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,10 @@ impl ParentClosure {
dev_info!("command exited with status code {code}");
dispatcher.set_exit(ExitReason::Code(code).into());
}

ParentMessage::CommandSignal(signal) => {
// FIXME: this isn't right as the command has not exited if the signal is
// not a termination one. However, doing this makes us fail an ignored
// compliance test instead of hanging forever.
dev_info!("command was terminated by {}", signal_fmt(signal));
dispatcher.set_exit(ExitReason::Signal(signal).into());
}
Expand Down

0 comments on commit 21c7d8b

Please sign in to comment.