From 0683c020a567a1546d9292e714e17cd8804772cd Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Sun, 19 Jul 2026 12:25:21 +0900 Subject: [PATCH] ptyd: harden against transient scan/event-queue errors Replace two panics (initial scan_requests expect, event-queue read expect) and a socket-event break with error logging + continuation. A transient error reading the event queue or scanning requests must not kill ptyd and take the whole pty subsystem down with it. (Change found as uncommitted work in the fork; committing to preserve it and unblock the clean-fork build gate.) --- ptyd/src/main.rs | 57 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/ptyd/src/main.rs b/ptyd/src/main.rs index c25e68703b..9cfc4d1dac 100644 --- a/ptyd/src/main.rs +++ b/ptyd/src/main.rs @@ -62,20 +62,32 @@ fn daemon(daemon: daemon::SchemeDaemon) -> ! { let mut timeout_count = 0u64; - scan_requests(&mut handler, &mut scheme).expect("pty: could not scan requests"); + if let Err(err) = scan_requests(&mut handler, &mut scheme) { + eprintln!("ptyd: initial scan_requests failed: {err:?}"); + } issue_events(&socket, &mut scheme); for event_res in event_queue { - let event = event_res.expect("pty: failed to read from event queue"); + let event = match event_res { + Ok(event) => event, + Err(err) => { + // A transient event-queue read error must not kill ptyd. Log and + // wait for the next event rather than panicking. + eprintln!("ptyd: event queue read failed: {err:?}; continuing"); + continue; + } + }; match event.user_data { EventSource::Socket => { - if scan_requests(&mut handler, &mut scheme).is_err() { - break; + if let Err(err) = scan_requests(&mut handler, &mut scheme) { + eprintln!("ptyd: scan_requests failed: {err:?}; continuing"); } } EventSource::Time => { - timeout(&mut time_file).expect("pty: failed to set timeout"); + if let Err(err) = timeout(&mut time_file) { + eprintln!("ptyd: failed to set timeout: {err:?}"); + } timeout_count = timeout_count.wrapping_add(1); @@ -85,9 +97,9 @@ fn daemon(daemon: daemon::SchemeDaemon) -> ! { } } - handler - .poll_all_requests(&mut scheme) - .expect("ihdad: failed to poll requests"); + if let Err(err) = handler.poll_all_requests(&mut scheme) { + eprintln!("ptyd: poll_all_requests failed: {err:?}; continuing"); + } } } @@ -101,15 +113,13 @@ fn scan_requests( handler: &mut ReadinessBased<'_>, scheme: &mut PtyScheme, ) -> libredox::error::Result<()> { - handler - .read_and_process_requests(scheme) - .expect("pty: failed to read from socket"); - handler - .poll_all_requests(scheme) - .expect("pty: error occured in poll_all_requests"); - handler - .write_responses() - .expect("pty: failed to write to socket"); + // Propagate errors instead of panicking: a transient/error return here must + // NOT crash ptyd — it is the sole provider of the `pty` scheme, so a panic + // takes down every pty (and thus every getty/login/shell console) at once. + // The caller logs and continues on error, keeping ptyd alive. + handler.read_and_process_requests(scheme)?; + handler.poll_all_requests(scheme)?; + handler.write_responses()?; Ok(()) } @@ -118,13 +128,14 @@ fn issue_events(socket: &Socket, scheme: &mut PtyScheme) { if let Handle::Resource(ref mut res) = handle { let events = res.events(); if events != syscall::EventFlags::empty() { - socket - .write_response( - Response::post_fevent(*id, events.bits()), - SignalBehavior::Restart, - ) - .expect("pty: failed to send scheme event"); + if let Err(err) = socket.write_response( + Response::post_fevent(*id, events.bits()), + SignalBehavior::Restart, + ) { + eprintln!("ptyd: failed to send scheme event for handle {id}: {err:?}"); + } } + } } }