diff --git a/src/platform/redox/epoll.rs b/src/platform/redox/epoll.rs index fdbb8680b0..7d238fc5ee 100644 --- a/src/platform/redox/epoll.rs +++ b/src/platform/redox/epoll.rs @@ -123,17 +123,11 @@ impl PalEpoll for Sys { let mut count = 0; for i in 0..read { unsafe { - let event_ptr = events.add(i); + let event_ptr = (events.cast::()).add(i); let target_ptr = events.add(count); - let event = *event_ptr.cast::(); - *target_ptr = epoll_event { - events: event_flags_to_epoll(event.flags), - data: epoll_data { - u64: event.data as u64, - }, - ..Default::default() - }; - count += 1; + if convert_event(event_ptr, target_ptr) { + count += 1; + } } } @@ -141,6 +135,21 @@ impl PalEpoll for Sys { } } +unsafe fn convert_event(event_ptr: *const Event, target_ptr: *mut epoll_event) -> bool { + let event = *event_ptr; + if event.id == syscall::EVENT_TIMEOUT_ID { + return false; + } + *target_ptr = epoll_event { + events: event_flags_to_epoll(event.flags), + data: epoll_data { + u64: event.data as u64, + }, + ..Default::default() + }; + true +} + fn register_timeout(epfd: i32, timeout: i32) -> Result { if timeout < 0 { return Err(Errno(EINVAL)); @@ -154,3 +163,76 @@ fn register_timeout(epfd: i32, timeout: i32) -> Result { }, ) } + +#[cfg(test)] +mod tests { + use super::convert_event; + use crate::header::sys_epoll::{EPOLLIN, epoll_event}; + use core::mem; + use syscall::{data::Event, flag::EVENT_READ}; + + #[test] + fn timeout_event_is_filtered_out() { + assert_eq!(mem::size_of::(), mem::size_of::()); + + let timeout = Event { + id: syscall::EVENT_TIMEOUT_ID, + flags: EVENT_READ, + data: 0xCAFE, + }; + let legitimate = Event { + id: 7, + flags: EVENT_READ, + data: 0xBEEF, + }; + + let mut target: epoll_event = unsafe { mem::zeroed() }; + let accepted = unsafe { convert_event(&timeout, &mut target as *mut _) }; + assert!(!accepted, "kernel-injected EVENT_TIMEOUT_ID must be skipped"); + assert_eq!(target.data.u64, 0, "timeout event must not write the target slot"); + + let accepted = unsafe { convert_event(&legitimate, &mut target as *mut _) }; + assert!(accepted); + unsafe { + assert_eq!((target.events as u32) & EPOLLIN, EPOLLIN); + } + assert_eq!(target.data.u64, 0xBEEF); + } + + #[test] + fn pointer_arithmetic_uses_event_strides() { + let events = [ + Event { + id: 1, + flags: EVENT_READ, + data: 0xA1, + }, + Event { + id: syscall::EVENT_TIMEOUT_ID, + flags: EVENT_READ, + data: 0xA2, + }, + Event { + id: 3, + flags: EVENT_READ, + data: 0xA3, + }, + ]; + let mut targets: [epoll_event; 3] = unsafe { mem::zeroed() }; + + let mut out = 0; + for i in 0..events.len() { + unsafe { + let src = (&events as *const Event).add(i); + let dst = (&mut targets as *mut epoll_event).add(out); + if convert_event(src, dst) { + out += 1; + } + } + } + + assert_eq!(out, 2, "exactly one EVENT_TIMEOUT_ID entry is dropped"); + assert_eq!(targets[0].data.u64, 0xA1); + assert_eq!(targets[1].data.u64, 0xA3); + } +}