Skip to content

Commit 49feaa0

Browse files
VirtAddr::read_mut: return ReadErr instead of None
This makes error handling in the syscalls much cleaner. Another thing that we could do is specifically have a `UserVirtAddr` structure, which on reads validates that the memory that we are reading is valid for memory R/W (depending of mutablity) in the read_{mut} function and the address is a valid userland address (under arch::userland_max_address()). Signed-off-by: Andy-Python-Programmer <[email protected]>
1 parent 3f2fb2c commit 49feaa0

File tree

13 files changed

+95
-102
lines changed

13 files changed

+95
-102
lines changed

src/aero_kernel/src/drivers/e1000.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ enum Error {
4141
UnknownBar,
4242
NoEeprom,
4343
OutOfMemory,
44-
NotSupported,
44+
ReadErr(ReadErr),
45+
}
46+
47+
impl From<ReadErr> for Error {
48+
fn from(value: ReadErr) -> Self {
49+
Self::ReadErr(value)
50+
}
4551
}
4652

4753
#[derive(Copy, Clone)]
@@ -446,9 +452,7 @@ impl E1000 {
446452
let phys = frame.start_address();
447453
let addr = phys.as_hhdm_virt();
448454

449-
let descriptors = addr
450-
.read_mut::<[TxDescriptor; TX_DESC_NUM as usize]>()
451-
.ok_or(Error::NotSupported)?;
455+
let descriptors = addr.read_mut::<[TxDescriptor; TX_DESC_NUM as usize]>()?;
452456

453457
for desc in descriptors {
454458
*desc = TxDescriptor::default();
@@ -485,9 +489,7 @@ impl E1000 {
485489
let phys = frame.start_address();
486490
let addr = phys.as_hhdm_virt();
487491

488-
let descriptors = addr
489-
.read_mut::<[RxDescriptor; RX_DESC_NUM as usize]>()
490-
.ok_or(Error::NotSupported)?;
492+
let descriptors = addr.read_mut::<[RxDescriptor; RX_DESC_NUM as usize]>()?;
491493

492494
for desc in descriptors {
493495
let frame: PhysFrame<Size4KiB> =

src/aero_kernel/src/drivers/pty.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,12 @@ impl INodeInterface for Master {
108108
fn ioctl(&self, command: usize, arg: usize) -> fs::Result<usize> {
109109
match command {
110110
TIOCGPTN => {
111-
let id = VirtAddr::new(arg as u64)
112-
.read_mut::<u32>()
113-
.ok_or(FileSystemError::NotSupported)?;
114-
111+
let id = VirtAddr::new(arg as u64).read_mut::<u32>()?;
115112
*id = self.id;
116113
}
117114

118115
aero_syscall::TIOCSWINSZ => {
119-
let winsize = VirtAddr::new(arg as u64)
120-
.read_mut::<WinSize>()
121-
.ok_or(FileSystemError::NotSupported)?;
122-
116+
let winsize = VirtAddr::new(arg as u64).read_mut::<WinSize>()?;
123117
*self.window_size.lock_irq() = *winsize;
124118
}
125119

@@ -180,29 +174,23 @@ impl INodeInterface for Slave {
180174

181175
match command {
182176
aero_syscall::TIOCGWINSZ => {
183-
let winsize = VirtAddr::new(arg as u64)
184-
.read_mut::<WinSize>()
185-
.ok_or(FileSystemError::NotSupported)?;
186-
177+
let winsize = VirtAddr::new(arg as u64).read_mut::<WinSize>()?;
187178
*winsize = *self.master.window_size.lock_irq();
179+
188180
Ok(0)
189181
}
190182

191183
aero_syscall::TCGETS => {
192-
let termios = VirtAddr::new(arg as u64)
193-
.read_mut::<Termios>()
194-
.ok_or(FileSystemError::NotSupported)?;
195-
184+
let termios = VirtAddr::new(arg as u64).read_mut::<Termios>()?;
196185
*termios = inner.termios;
186+
197187
Ok(0)
198188
}
199189

200190
aero_syscall::TCSETSF => {
201-
let termios = VirtAddr::new(arg as u64)
202-
.read_mut::<Termios>()
203-
.ok_or(FileSystemError::NotSupported)?;
204-
191+
let termios = VirtAddr::new(arg as u64).read_mut::<Termios>()?;
205192
inner.termios = *termios;
193+
206194
Ok(0)
207195
}
208196

src/aero_kernel/src/fs/devfs.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,7 @@ impl INodeInterface for DevFb {
390390
// Device independent colormap information can be get and set using
391391
// the `FBIOGETCMAP` and `FBIOPUTCMAP` ioctls.
392392
FBIOPUTCMAP => {
393-
let struc = VirtAddr::new(arg as _)
394-
.read_mut::<FramebufferCmap>()
395-
.ok_or(FileSystemError::NotSupported);
396-
393+
let struc = VirtAddr::new(arg as _).read_mut::<FramebufferCmap>()?;
397394
log::debug!("fbdev: `FBIOPUTCMAP` is a stub! {struc:?}");
398395
Ok(0)
399396
}

src/aero_kernel/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
nonnull_slice_from_raw_parts,
4545
maybe_uninit_write_slice,
4646
slice_ptr_get,
47-
maybe_uninit_as_bytes
47+
maybe_uninit_as_bytes,
48+
pointer_is_aligned
4849
)]
4950
#![deny(trivial_numeric_casts, unused_allocation)]
5051
#![test_runner(crate::tests::test_runner)]

src/aero_kernel/src/mem/paging/addr.rs

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ use core::fmt;
2323
use core::iter::Step;
2424
use core::ops::{Add, AddAssign, Sub, SubAssign};
2525

26+
use crate::fs::FileSystemError;
27+
2628
use super::page_table::{PageOffset, PageTableIndex};
2729
use super::{PageSize, Size4KiB, VmFrame};
2830

@@ -52,14 +54,28 @@ pub struct VirtAddr(u64);
5254
#[repr(transparent)]
5355
pub struct PhysAddr(u64);
5456

55-
/// A passed `u64` was not a valid virtual address.
56-
///
57-
/// This means that bits 48 to 64 are not
58-
/// a valid sign extension and are not null either. So automatic sign extension would have
59-
/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid
60-
/// address calculation.
61-
#[derive(Debug)]
62-
pub struct VirtAddrNotValid(u64);
57+
#[derive(Copy, Clone, Debug)]
58+
pub enum ReadErr {
59+
Null,
60+
NotAligned,
61+
}
62+
63+
impl From<ReadErr> for FileSystemError {
64+
fn from(_: ReadErr) -> Self {
65+
// `FileSystemError::NotSupported` will be converted to `EINVAL` on
66+
// syscall error conversion.
67+
FileSystemError::NotSupported
68+
}
69+
}
70+
71+
impl From<ReadErr> for aero_syscall::SyscallError {
72+
fn from(value: ReadErr) -> Self {
73+
match value {
74+
ReadErr::Null => Self::EINVAL,
75+
ReadErr::NotAligned => Self::EACCES,
76+
}
77+
}
78+
}
6379

6480
impl VirtAddr {
6581
/// Creates a new canonical virtual address.
@@ -99,20 +115,15 @@ impl VirtAddr {
99115
///
100116
/// ## Example
101117
/// ```no_run
102-
/// let address: &mut SomeStruct = VirtAddr::new(0xcafebabe)
103-
/// .read_mut::<SomeStruct>();
104-
/// .ok_or(AeroSyscallError::EFAULT)?;
118+
/// let address: &mut SomeStruct = VirtAddr::new(0xcafebabe).read_mut::<SomeStruct>()?;
105119
/// ```
106-
pub fn read_mut<'struc, T: Sized>(&self) -> Option<&'struc mut T> {
107-
if self.validate_read::<T>() {
108-
Some(unsafe { &mut *(self.as_mut_ptr() as *mut T) })
109-
} else {
110-
None
111-
}
120+
pub fn read_mut<'a, T: Sized>(&self) -> Result<&'a mut T, ReadErr> {
121+
self.validate_read::<T>()?;
122+
Ok(unsafe { &mut *(self.as_mut_ptr() as *mut T) })
112123
}
113124

114125
pub fn as_bytes_mut(&self, size_bytes: usize) -> &mut [u8] {
115-
assert!(self.validate_read::<&[u8]>());
126+
self.validate_read::<&[u8]>().unwrap();
116127
unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), size_bytes) }
117128
}
118129

@@ -122,10 +133,17 @@ impl VirtAddr {
122133
}
123134

124135
/// Returns if the address is valid to read `sizeof(T)` bytes at the address.
125-
fn validate_read<T: Sized>(&self) -> bool {
136+
fn validate_read<T: Sized>(&self) -> Result<(), ReadErr> {
126137
// FIXME: (*self + core::mem::size_of::<T>()) <= crate::arch::task::userland_last_address()
127-
// // in-range
128-
self.0 != 0 // non-null
138+
let raw = self.as_ptr::<T>();
139+
140+
if raw.is_null() {
141+
return Err(ReadErr::Null);
142+
} else if !raw.is_aligned() {
143+
return Err(ReadErr::NotAligned);
144+
}
145+
146+
Ok(())
129147
}
130148

131149
/// Aligns the virtual address downwards to the given alignment.

src/aero_kernel/src/socket/inet.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,7 @@ impl INodeInterface for InetSocket {
231231
fn ioctl(&self, command: usize, arg: usize) -> fs::Result<usize> {
232232
match command {
233233
SIOCGIFINDEX => {
234-
let ifreq = VirtAddr::new(arg as _)
235-
.read_mut::<IfReq>()
236-
.ok_or(FileSystemError::NotSupported)?;
234+
let ifreq = VirtAddr::new(arg as _).read_mut::<IfReq>()?;
237235

238236
let name = ifreq.name().unwrap();
239237
assert!(name == "eth0");
@@ -243,9 +241,7 @@ impl INodeInterface for InetSocket {
243241
}
244242

245243
SIOCGIFHWADDR => {
246-
let ifreq = VirtAddr::new(arg as _)
247-
.read_mut::<IfReq>()
248-
.ok_or(FileSystemError::NotSupported)?;
244+
let ifreq = VirtAddr::new(arg as _).read_mut::<IfReq>()?;
249245

250246
let name = ifreq.name().ok_or(FileSystemError::InvalidPath)?;
251247
assert!(name == "eth0");
@@ -263,9 +259,7 @@ impl INodeInterface for InetSocket {
263259
}
264260

265261
SIOCSIFADDR => {
266-
let ifreq = VirtAddr::new(arg as _)
267-
.read_mut::<IfReq>()
268-
.ok_or(FileSystemError::NotSupported)?;
262+
let ifreq = VirtAddr::new(arg as _).read_mut::<IfReq>()?;
269263

270264
let family = unsafe { ifreq.data.addr.sa_family };
271265

@@ -274,7 +268,7 @@ impl INodeInterface for InetSocket {
274268
VirtAddr::new(&unsafe { ifreq.data.addr } as *const _ as _),
275269
family,
276270
)
277-
.ok_or(FileSystemError::NotSupported)?
271+
.map_err(|_| FileSystemError::NotSupported)?
278272
.as_inet()
279273
.ok_or(FileSystemError::NotSupported)?;
280274

src/aero_kernel/src/socket/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ pub enum SocketAddr<'a> {
3131
}
3232

3333
impl<'a> SocketAddr<'a> {
34-
pub fn from_family(address: VirtAddr, family: u32) -> Option<Self> {
34+
pub fn from_family(address: VirtAddr, family: u32) -> Result<Self, SyscallError> {
3535
match family {
36-
AF_UNIX => Some(SocketAddr::Unix(address.read_mut::<SocketAddrUnix>()?)),
37-
AF_INET => Some(SocketAddr::INet(address.read_mut::<SocketAddrInet>()?)),
36+
AF_UNIX => Ok(SocketAddr::Unix(address.read_mut::<SocketAddrUnix>()?)),
37+
AF_INET => Ok(SocketAddr::INet(address.read_mut::<SocketAddrInet>()?)),
3838

39-
_ => None,
39+
_ => Err(SyscallError::EINVAL),
4040
}
4141
}
4242

src/aero_kernel/src/socket/unix.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ pub struct AcceptQueue {
111111

112112
impl AcceptQueue {
113113
/// # Parameters
114-
/// * `backlog`: The maximum number of pending connections that the
115-
/// queue can hold.
114+
/// * `backlog`: The maximum number of pending connections that the queue can hold.
116115
pub fn new(backlog: usize) -> Self {
117116
Self {
118117
sockets: VecDeque::with_capacity(backlog),
@@ -370,9 +369,7 @@ impl INodeInterface for UnixSocket {
370369
}
371370

372371
if let Some((address, length)) = address {
373-
let address = address
374-
.read_mut::<SocketAddrUnix>()
375-
.ok_or(FileSystemError::NotSupported)?;
372+
let address = address.read_mut::<SocketAddrUnix>()?;
376373

377374
if let Some(paddr) = peer.inner.lock_irq().address.as_ref() {
378375
*address = paddr.clone();

src/aero_kernel/src/syscall/fs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ pub fn poll(fds: &mut [PollFd], timeout: usize, sigmask: usize) -> Result<usize,
654654

655655
// The timeout can be NULL.
656656
let timeout = if timeout != 0x00 {
657-
Some(crate::utils::validate_ptr(timeout as *const TimeSpec).ok_or(SyscallError::EINVAL)?)
657+
Some(crate::utils::validate_ptr(timeout as *const TimeSpec)?)
658658
} else {
659659
None
660660
};

src/aero_kernel/src/syscall/futex.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ impl FutexContainer {
8989
Self::validate_futex_ptr(uaddr)?;
9090

9191
let key = Self::addr_as_futex_key(uaddr).ok_or(SyscallError::EINVAL)?;
92-
let value = uaddr.read_mut::<AtomicU32>().ok_or(SyscallError::EINVAL)?;
92+
let value = uaddr.read_mut::<AtomicU32>()?;
9393

9494
if value.load(Ordering::SeqCst) == expected {
9595
let futex = self.get_alloc(key);

0 commit comments

Comments
 (0)