Skip to content

Commit 1e8b055

Browse files
committed
"Fix" the ignored sigtstp test
1 parent f5a4d16 commit 1e8b055

File tree

3 files changed

+36
-32
lines changed

3 files changed

+36
-32
lines changed

sudo/lib/exec/backchannel.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ use std::{
44
mem::size_of,
55
os::{
66
fd::{AsRawFd, RawFd},
7-
unix::{net::UnixStream, process::ExitStatusExt},
7+
unix::net::UnixStream,
88
},
9-
process::ExitStatus,
109
};
1110

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

14-
use super::signal_fmt;
13+
use super::{signal_fmt, ExitReason};
1514

1615
type Prefix = u8;
1716
type ParentData = c_int;
@@ -89,14 +88,11 @@ impl From<io::Error> for ParentMessage {
8988
}
9089
}
9190

92-
impl From<ExitStatus> for ParentMessage {
93-
fn from(status: ExitStatus) -> Self {
94-
if let Some(code) = status.code() {
95-
Self::CommandExit(code)
96-
} else {
97-
// `ExitStatus::code` docs state that it only returns `None` if the process was
98-
// terminated by a signal so this should always succeed.
99-
Self::CommandSignal(status.signal().unwrap())
91+
impl From<ExitReason> for ParentMessage {
92+
fn from(reason: ExitReason) -> Self {
93+
match reason {
94+
ExitReason::Code(code) => Self::CommandExit(code),
95+
ExitReason::Signal(signal) => Self::CommandSignal(signal),
10096
}
10197
}
10298
}

sudo/lib/exec/monitor.rs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use std::{
99
time::Duration,
1010
};
1111

12-
use crate::log::{dev_info, dev_warn};
1312
use crate::system::{
1413
fork, getpgid,
1514
interface::ProcessId,
@@ -18,13 +17,18 @@ use crate::system::{
1817
term::{set_controlling_terminal, tcgetpgrp, tcsetpgrp},
1918
wait::{waitpid, WaitError, WaitOptions},
2019
};
20+
use crate::{
21+
exec::event::StopReason,
22+
log::{dev_info, dev_warn},
23+
};
2124

2225
use signal_hook::consts::*;
2326

2427
use super::{
2528
backchannel::{MonitorBackchannel, MonitorMessage, ParentMessage},
2629
event::{EventClosure, EventDispatcher},
2730
io_util::{retry_while_interrupted, was_interrupted},
31+
ExitReason,
2832
};
2933
use super::{cond_fmt, signal_fmt};
3034

@@ -103,10 +107,17 @@ pub(super) fn exec_monitor(
103107
// FIXME (ogsudo): Set the command as the foreground process for the follower.
104108

105109
// Start the event loop.
106-
dispatcher.event_loop(&mut closure);
110+
let reason = dispatcher.event_loop(&mut closure);
107111
// FIXME (ogsudo): Terminate the command using `killpg` if it's not terminated.
108112
// FIXME (ogsudo): Take the controlling tty so the command's children don't receive SIGHUP when we exit.
109-
// FIXME (ogsudo): Send the command status back to the parent.
113+
114+
match reason {
115+
StopReason::Break(()) => {}
116+
StopReason::Exit(exit_reason) => {
117+
closure.backchannel.send(&exit_reason.into()).ok();
118+
}
119+
}
120+
110121
// FIXME (ogsudo): The tty is restored here if selinux is available.
111122

112123
drop(closure);
@@ -180,6 +191,7 @@ impl<'a> MonitorClosure<'a> {
180191
// There's something wrong with the backchannel, break the event loop
181192
Err(err) => {
182193
dev_warn!("monitor could not read from backchannel: {}", err);
194+
// FIXME: maybe the break reason should be `io::Error` instead.
183195
dispatcher.set_break(());
184196
self.backchannel.send(&err.into()).unwrap();
185197
}
@@ -198,7 +210,7 @@ impl<'a> MonitorClosure<'a> {
198210
}
199211
}
200212

201-
fn handle_sigchld(&mut self, command_pid: ProcessId) {
213+
fn handle_sigchld(&mut self, command_pid: ProcessId, dispatcher: &mut EventDispatcher<Self>) {
202214
let status = loop {
203215
match waitpid(command_pid, WaitOptions::new().untraced().no_hang()) {
204216
Ok((_pid, status)) => break status,
@@ -211,25 +223,24 @@ impl<'a> MonitorClosure<'a> {
211223
dev_info!("command ({command_pid}) exited with status code {exit_code}");
212224
// The command did exit, set it's PID to `None`.
213225
self.command_pid = None;
214-
self.backchannel
215-
.send(&ParentMessage::CommandExit(exit_code))
216-
.ok();
226+
dispatcher.set_exit(ExitReason::Code(exit_code))
217227
} else if let Some(signal) = status.term_signal() {
218228
dev_info!(
219229
"command ({command_pid}) was terminated by {}",
220230
signal_fmt(signal),
221231
);
222232
// The command was terminated, set it's PID to `None`.
223233
self.command_pid = None;
224-
self.backchannel
225-
.send(&ParentMessage::CommandSignal(signal))
226-
.ok();
227-
} else if let Some(_signal) = status.stop_signal() {
228-
// FIXME: we should save the foreground process group ID so we can restore it later.
234+
dispatcher.set_exit(ExitReason::Signal(signal))
235+
} else if let Some(signal) = status.stop_signal() {
229236
dev_info!(
230237
"command ({command_pid}) was stopped by {}",
231-
signal_fmt(_signal),
238+
signal_fmt(signal),
232239
);
240+
// FIXME: we should save the foreground process group ID so we can restore it later.
241+
self.backchannel
242+
.send(&ParentMessage::CommandSignal(signal))
243+
.ok();
233244
} else if status.did_continue() {
234245
dev_info!("command ({command_pid}) continued execution");
235246
} else {
@@ -308,7 +319,7 @@ fn is_self_terminating(
308319

309320
impl<'a> EventClosure for MonitorClosure<'a> {
310321
type Break = ();
311-
type Exit = ();
322+
type Exit = ExitReason;
312323

313324
fn on_signal(&mut self, info: SignalInfo, dispatcher: &mut EventDispatcher<Self>) {
314325
dev_info!(
@@ -325,12 +336,7 @@ impl<'a> EventClosure for MonitorClosure<'a> {
325336
};
326337

327338
match info.signal() {
328-
SIGCHLD => {
329-
self.handle_sigchld(command_pid);
330-
if self.command_pid.is_none() {
331-
dispatcher.set_exit(());
332-
}
333-
}
339+
SIGCHLD => self.handle_sigchld(command_pid, dispatcher),
334340
// Skip the signal if it was sent by the user and it is self-terminating.
335341
_ if info.is_user_signaled()
336342
&& is_self_terminating(info.pid(), command_pid, self.command_pgrp) => {}

sudo/lib/exec/parent.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,10 @@ impl ParentClosure {
199199
dev_info!("command exited with status code {code}");
200200
dispatcher.set_exit(ExitReason::Code(code).into());
201201
}
202-
203202
ParentMessage::CommandSignal(signal) => {
203+
// FIXME: this isn't right as the command has not exited if the signal is
204+
// not a termination one. However, doing this makes us fail an ignored
205+
// compliance test instead of hanging forever.
204206
dev_info!("command was terminated by {}", signal_fmt(signal));
205207
dispatcher.set_exit(ExitReason::Signal(signal).into());
206208
}

0 commit comments

Comments
 (0)