diff --git a/internal/shim-sev/src/payload.rs b/internal/shim-sev/src/payload.rs index 12d2f1ff..ce990832 100644 --- a/internal/shim-sev/src/payload.rs +++ b/internal/shim-sev/src/payload.rs @@ -9,6 +9,7 @@ use crate::shim_stack::init_stack_with_guard; use crate::usermode::usermode; use crate::{BOOT_INFO, PAYLOAD_READY}; +use crate::spin::RWLocked; use core::ops::DerefMut; use core::sync::atomic::Ordering; use crt0stack::{self, Builder, Entry}; @@ -63,6 +64,22 @@ pub static NEXT_MMAP_RWLOCK: Lazy> = Lazy::new(|| { RwLock::::const_new(spinning::RawRwLock::const_new(), mmap_start) }); +/// The process context +pub struct ProcessContext { + /// used file handles, one bit per fd, up to 65536 + pub files: [u8; 8192], +} + +/// The process context global variable +pub static PROCESS_CONTEXT: Lazy> = Lazy::new(|| { + let mut ctx = ProcessContext { files: [0u8; 8192] }; + + // FIXME: might want to remove in the future + ctx.files[0] = 7; // validate fd 0, 1, 2 + + RWLocked::new(ctx) +}); + /// load the elf binary fn map_elf(app_virt_start: VirtAddr) -> &'static Header { let (code_start, code_end) = { diff --git a/internal/shim-sev/src/syscall.rs b/internal/shim-sev/src/syscall.rs index 5efa026c..d120b03a 100644 --- a/internal/shim-sev/src/syscall.rs +++ b/internal/shim-sev/src/syscall.rs @@ -9,14 +9,14 @@ use crate::attestation::SEV_SECRET; use crate::eprintln; use crate::hostcall::{HostCall, HOST_CALL_ALLOC}; use crate::paging::SHIM_PAGETABLE; -use crate::payload::{NEXT_BRK_RWLOCK, NEXT_MMAP_RWLOCK}; +use crate::payload::{NEXT_BRK_RWLOCK, NEXT_MMAP_RWLOCK, PROCESS_CONTEXT}; use core::convert::TryFrom; use core::mem::size_of; use core::ops::{Deref, DerefMut}; use primordial::{Address, Register}; use sallyport::{Cursor, Request}; use syscall::{ - BaseSyscallHandler, EnarxSyscallHandler, FileSyscallHandler, MemorySyscallHandler, + BaseSyscallHandler, EnarxSyscallHandler, FdHandler, FileSyscallHandler, MemorySyscallHandler, NetworkSyscallHandler, ProcessSyscallHandler, SyscallHandler, SystemSyscallHandler, ARCH_GET_FS, ARCH_GET_GS, ARCH_SET_FS, ARCH_SET_GS, SEV_TECH, }; @@ -171,6 +171,55 @@ impl SystemSyscallHandler for Handler {} impl NetworkSyscallHandler for Handler {} impl FileSyscallHandler for Handler {} +impl FdHandler for Handler { + fn fd_register(&mut self, fd: i32) { + let i: usize = (fd / 8) as _; + let b: u8 = 1u8 << (fd % 8); + + let mut context = PROCESS_CONTEXT.write(); + + if context.files[i] & b != 0 { + panic!("Register already registered fd") + } + + context.files[i] = context.files[i] | b; + } + + fn fd_unregister(&mut self, fd: i32) { + let i: usize = (fd / 8) as _; + let b: u8 = 1u8 << (fd % 8); + + let mut context = PROCESS_CONTEXT.write(); + + if context.files[i] & b == 0 { + panic!("Unregister not registered fd") + } + + context.files[i] = context.files[i] & (!b); + } + + fn fd_is_valid(&mut self, fd: i32) -> sallyport::Result { + let i: usize = (fd / 8) as _; + let b: u8 = 1u8 << (fd % 8); + + let context = PROCESS_CONTEXT.read(); + + if context.files[i] & b == 0 { + return Err(libc::EBADFD); + } + + Ok(Default::default()) + } + + fn fd_epoll_ctl(&mut self, epfd: i32, op: i32, fd: i32, event: libc::epoll_event) { + unimplemented!() + } + + fn fd_get_epoll_event_data(&mut self, epfd: i32, fd: i32) -> u64 { + unimplemented!() + } +} + impl BaseSyscallHandler for Handler { fn unknown_syscall( &mut self, diff --git a/internal/shim-sgx/Cargo.lock b/internal/shim-sgx/Cargo.lock index af0c987a..6d919366 100644 --- a/internal/shim-sgx/Cargo.lock +++ b/internal/shim-sgx/Cargo.lock @@ -60,6 +60,15 @@ version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + [[package]] name = "lset" version = "0.1.0" @@ -118,6 +127,12 @@ dependencies = [ "primordial", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "scroll" version = "0.10.2" @@ -161,11 +176,21 @@ dependencies = [ "sallyport", "sgx", "sgx-heap", + "spinning", "syscall", "untrusted", "xsave", ] +[[package]] +name = "spinning" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" +dependencies = [ + "lock_api", +] + [[package]] name = "syn" version = "1.0.58" diff --git a/internal/shim-sgx/Cargo.toml b/internal/shim-sgx/Cargo.toml index 5a51dbb9..61faaa42 100644 --- a/internal/shim-sgx/Cargo.toml +++ b/internal/shim-sgx/Cargo.toml @@ -25,6 +25,7 @@ nbytes = "0.1" lset = "0.1" xsave = "0.1.1" const-default = { version = "0.1" } +spinning = { version = "0.1", default-features = false } [profile.dev.package.rcrt1] opt-level = 3 diff --git a/internal/shim-sgx/src/handler.rs b/internal/shim-sgx/src/handler.rs index 614da1ab..d8f09b55 100644 --- a/internal/shim-sgx/src/handler.rs +++ b/internal/shim-sgx/src/handler.rs @@ -17,8 +17,9 @@ use sgx::{ }, }; use sgx_heap::Heap; +use spinning::Lazy; use syscall::{ - BaseSyscallHandler, EnarxSyscallHandler, FileSyscallHandler, MemorySyscallHandler, + BaseSyscallHandler, EnarxSyscallHandler, FdHandler, FileSyscallHandler, MemorySyscallHandler, NetworkSyscallHandler, ProcessSyscallHandler, SyscallHandler, SystemSyscallHandler, ARCH_GET_FS, ARCH_GET_GS, ARCH_SET_FS, ARCH_SET_GS, SGX_DUMMY_QUOTE, SGX_DUMMY_TI, SGX_QUOTE_SIZE, SGX_TECH, SYS_ENARX_CPUID, SYS_ENARX_GETATT, @@ -27,6 +28,7 @@ use untrusted::{AddressValidator, UntrustedRef, UntrustedRefMut, ValidateSlice}; pub const TRACE: bool = false; use crate::enclave::{syscall, Context}; +use crate::spin::RWLocked; pub struct Handler<'a> { pub aex: &'a mut StateSaveArea, @@ -126,6 +128,71 @@ impl<'a> SyscallHandler for Handler<'a> {} impl<'a> SystemSyscallHandler for Handler<'a> {} impl<'a> NetworkSyscallHandler for Handler<'a> {} +/// The process context +pub struct ProcessContext { + /// used file handles, one bit per fd, up to 65536 + pub files: [u8; 8192], +} + +/// The process context global variable +pub static PROCESS_CONTEXT: Lazy> = Lazy::new(|| { + let mut ctx = ProcessContext { files: [0u8; 8192] }; + + // FIXME: might want to remove in the future + ctx.files[0] = 7; // validate fd 0, 1, 2 + + RWLocked::new(ctx) +}); + +impl<'a> FdHandler for Handler<'a> { + fn fd_register(&mut self, fd: i32) { + let i: usize = (fd / 8) as _; + let b: u8 = 1u8 << (fd % 8); + + let mut context = PROCESS_CONTEXT.write(); + + if context.files[i] & b != 0 { + panic!("Register already registered fd") + } + + context.files[i] = context.files[i] | b; + } + + fn fd_unregister(&mut self, fd: i32) { + let i: usize = (fd / 8) as _; + let b: u8 = 1u8 << (fd % 8); + + let mut context = PROCESS_CONTEXT.write(); + + if context.files[i] & b == 0 { + panic!("Unregister not registered fd") + } + + context.files[i] = context.files[i] & (!b); + } + + fn fd_is_valid(&mut self, fd: i32) -> sallyport::Result { + let i: usize = (fd / 8) as _; + let b: u8 = 1u8 << (fd % 8); + + let context = PROCESS_CONTEXT.read(); + + if context.files[i] & b == 0 { + return Err(libc::EBADFD); + } + + Ok(Default::default()) + } + + fn fd_epoll_ctl(&mut self, epfd: i32, op: i32, fd: i32, event: libc::epoll_event) { + unimplemented!() + } + + fn fd_get_epoll_event_data(&mut self, epfd: i32, fd: i32) -> u64 { + unimplemented!() + } +} + impl<'a> BaseSyscallHandler for Handler<'a> { fn translate_shim_to_host_addr(buf: *const T) -> usize { buf as _ diff --git a/internal/shim-sgx/src/main.rs b/internal/shim-sgx/src/main.rs index a10a6bbd..f9f0bae5 100644 --- a/internal/shim-sgx/src/main.rs +++ b/internal/shim-sgx/src/main.rs @@ -71,5 +71,6 @@ mod entry; mod event; mod handler; mod hostlib; +mod spin; use hostlib::Layout; diff --git a/internal/shim-sgx/src/spin.rs b/internal/shim-sgx/src/spin.rs new file mode 100644 index 00000000..5d9b43c4 --- /dev/null +++ b/internal/shim-sgx/src/spin.rs @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! wrapper around spinning types to permit trait implementations. + +#![allow(dead_code)] + +use spinning::{Mutex, MutexGuard, RawMutex, RawRwLock, RwLock, RwLockReadGuard, RwLockWriteGuard}; + +/// A wrapper around spinning::Mutex to permit trait implementations. +pub struct Locked { + inner: Mutex, +} + +impl Locked { + /// Constructor + #[inline] + pub const fn new(inner: A) -> Self { + Self { + inner: Mutex::const_new(RawMutex::const_new(), inner), + } + } + + /// get a [`MutexGuard`](spinning::MutexGuard) + #[inline] + pub fn lock(&self) -> MutexGuard { + self.inner.lock() + } +} + +/// A wrapper around spinning::RwLock to permit trait implementations. +pub struct RWLocked { + inner: RwLock, +} + +impl RWLocked { + /// Constructor + #[inline] + pub const fn new(inner: A) -> Self { + Self { + inner: RwLock::const_new(RawRwLock::const_new(), inner), + } + } + + /// get a [`RwLockReadGuard`](spinning::RwLockReadGuard) + #[inline] + pub fn read(&self) -> RwLockReadGuard { + self.inner.read() + } + + /// get a [`RwLockWriteGuard`](spinning::RwLockWriteGuard) + #[inline] + pub fn write(&self) -> RwLockWriteGuard { + self.inner.write() + } +} diff --git a/internal/syscall/src/fdhandle.rs b/internal/syscall/src/fdhandle.rs new file mode 100644 index 00000000..413f817b --- /dev/null +++ b/internal/syscall/src/fdhandle.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! internal fd book keeping + +use sallyport::Result; + +/// internal fd book keeping +pub trait FdHandler { + /// register a valid fd + fn fd_register(&mut self, fd: libc::c_int); + + /// unregister a valid fd + fn fd_unregister(&mut self, fd: libc::c_int); + + /// check, if an fd is valid + /// + /// returns `Err(libc::EBADFD)` if not + fn fd_is_valid(&mut self, fd: libc::c_int) -> Result; + + /// shadow epoll_ctl + fn fd_epoll_ctl( + &mut self, + epfd: libc::c_int, + op: libc::c_int, + fd: libc::c_int, + event: libc::epoll_event, + ); + + /// get the event data for an fd + fn fd_get_epoll_event_data(&mut self, epfd: libc::c_int, fd: libc::c_int) -> u64; +} diff --git a/internal/syscall/src/file.rs b/internal/syscall/src/file.rs index fc3cf22d..1634c91e 100644 --- a/internal/syscall/src/file.rs +++ b/internal/syscall/src/file.rs @@ -2,17 +2,25 @@ //! file syscalls -use crate::BaseSyscallHandler; +use crate::{BaseSyscallHandler, FdHandler}; use core::mem::MaybeUninit; use sallyport::{request, Block, Result}; use untrusted::{AddressValidator, UntrustedRef, UntrustedRefMut, Validate, ValidateSlice}; /// file syscalls -pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { +pub trait FileSyscallHandler: BaseSyscallHandler + FdHandler + AddressValidator + Sized { /// syscall fn close(&mut self, fd: libc::c_int) -> Result { self.trace("close", 1); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + let ret = unsafe { self.proxy(request!(libc::SYS_close => fd))? }; + + // internal book keeping + self.fd_unregister(fd); + Ok(ret) } @@ -20,6 +28,9 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { fn read(&mut self, fd: libc::c_int, buf: UntrustedRefMut, count: libc::size_t) -> Result { self.trace("read", 4); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + let buf = buf.validate_slice(count, self).ok_or(libc::EFAULT)?; let c = self.new_cursor(); @@ -56,6 +67,10 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { iovcnt: libc::c_int, ) -> Result { self.trace("readv", 3); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + // FIXME: this is not an ideal implementation of readv, but for the sake // of simplicity this readv implementation behaves very much like how the // Linux kernel would for a module that does not support readv, but does @@ -76,6 +91,9 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { self.trace("write", 3); } + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + // Limit the write to `Block::buf_capacity()` let count = usize::min(count, Block::buf_capacity()); @@ -105,6 +123,10 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { iovcnt: libc::c_int, ) -> Result { self.trace("writev", 3); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + let iovec = iovec.validate_slice(iovcnt, self).ok_or(libc::EFAULT)?; let mut size = 0usize; @@ -131,6 +153,10 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { /// syscall fn ioctl(&mut self, fd: libc::c_int, request: libc::c_ulong, arg: usize) -> Result { self.trace("ioctl", 3); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + match (fd as _, request as _) { (libc::STDIN_FILENO, libc::TIOCGWINSZ) | (libc::STDOUT_FILENO, libc::TIOCGWINSZ) @@ -168,6 +194,7 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { bufsize: libc::size_t, ) -> Result { self.trace("readlink", 3); + // Fake readlink("/proc/self/exe") const PROC_SELF_EXE: &str = "/proc/self/exe"; @@ -203,6 +230,10 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { /// syscall fn fstat(&mut self, fd: libc::c_int, statbuf: UntrustedRefMut) -> Result { self.trace("fstat", 2); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + // Fake fstat(0|1|2, ...) done by glibc or rust match fd { libc::STDIN_FILENO | libc::STDOUT_FILENO | libc::STDERR_FILENO => { @@ -260,6 +291,10 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { /// syscall fn fcntl(&mut self, fd: libc::c_int, cmd: libc::c_int, arg: libc::c_int) -> Result { self.trace("fcntl", 3); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + match (fd, cmd) { (libc::STDIN_FILENO, libc::F_GETFL) => { //eprintln!("SC> fcntl({}, F_GETFL) = 0x402 (flags O_RDWR|O_APPEND)", fd); @@ -307,6 +342,11 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { let fds = fds.validate_slice(nfds, self).ok_or(libc::EFAULT)?; + // check if operation is allowed on these fds + for pollfd in fds.iter() { + let _ = self.fd_is_valid(pollfd.fd)?; + } + let c = self.new_cursor(); let (_, buf) = c.copy_from_slice(fds).or(Err(libc::EMSGSIZE))?; @@ -328,6 +368,7 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { /// syscall fn pipe(&mut self, pipefd: UntrustedRefMut) -> Result { self.trace("pipe", 1); + let pipefd = pipefd.validate_slice(2, self).ok_or(libc::EFAULT)?; let c = self.new_cursor(); @@ -343,13 +384,23 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { .or(Err(libc::EFAULT))?; } + for fd in pipefd { + // register valid fd + self.fd_register(*fd); + } + Ok(ret) } /// syscall fn epoll_create1(&mut self, flags: libc::c_int) -> Result { self.trace("epoll_create1", 1); + let ret = unsafe { self.proxy(request!(libc::SYS_epoll_create1 => flags))? }; + + // register valid fd + self.fd_register(usize::from(ret[0]) as _); + Ok(ret) } @@ -363,6 +414,12 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { ) -> Result { self.trace("epoll_ctl", 4); + // check if operation is allowed on this epfd + let _ = self.fd_is_valid(epfd)?; + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + let event = event.validate(self).ok_or(libc::EFAULT)?; let c = self.new_cursor(); @@ -387,6 +444,9 @@ pub trait FileSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { ) -> Result { self.trace("epoll_wait", 4); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(epfd)?; + let maxevents: usize = maxevents as _; let event = event.validate_slice(maxevents, self).ok_or(libc::EFAULT)?; diff --git a/internal/syscall/src/lib.rs b/internal/syscall/src/lib.rs index 22d9e640..6924a4ac 100644 --- a/internal/syscall/src/lib.rs +++ b/internal/syscall/src/lib.rs @@ -8,6 +8,7 @@ mod base; mod enarx; +mod fdhandle; mod file; mod memory; mod network; @@ -21,6 +22,7 @@ use untrusted::AddressValidator; pub use crate::base::BaseSyscallHandler; pub use crate::enarx::EnarxSyscallHandler; +pub use crate::fdhandle::FdHandler; pub use crate::file::FileSyscallHandler; pub use crate::memory::MemorySyscallHandler; pub use crate::network::NetworkSyscallHandler; diff --git a/internal/syscall/src/network.rs b/internal/syscall/src/network.rs index 56cd70cc..464c089b 100644 --- a/internal/syscall/src/network.rs +++ b/internal/syscall/src/network.rs @@ -2,21 +2,30 @@ //! network syscalls -use crate::BaseSyscallHandler; +use crate::{BaseSyscallHandler, FdHandler}; use sallyport::{request, Block, Result}; use untrusted::{AddressValidator, UntrustedRef, UntrustedRefMut, Validate, ValidateSlice}; /// network syscalls -pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { +pub trait NetworkSyscallHandler: BaseSyscallHandler + FdHandler + AddressValidator + Sized { /// syscall fn socket(&mut self, domain: libc::c_int, type_: libc::c_int, protocol: libc::c_int) -> Result { self.trace("socket", 3); - unsafe { self.proxy(request!(libc::SYS_socket => domain, type_, protocol)) } + let ret = unsafe { self.proxy(request!(libc::SYS_socket => domain, type_, protocol))? }; + + // register valid fd + self.fd_register(usize::from(ret[0]) as _); + + Ok(ret) } /// syscall fn bind(&mut self, fd: libc::c_int, addr: UntrustedRef, addrlen: libc::size_t) -> Result { self.trace("bind", 3); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + if addrlen > Block::buf_capacity() { return Err(libc::EINVAL); } @@ -34,6 +43,9 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { /// syscall fn listen(&mut self, sockfd: libc::c_int, backlog: libc::c_int) -> Result { self.trace("listen", 2); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(sockfd)?; + unsafe { self.proxy(request!(libc::SYS_listen => sockfd, backlog)) } } @@ -46,6 +58,9 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { ) -> Result { self.trace("getsockname", 3); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + let addrlen = addrlen.validate(self).ok_or(libc::EFAULT)?; let c = self.new_cursor(); @@ -100,6 +115,9 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { ) -> Result { self.trace("accept4", 4); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + if addr.as_ptr().is_null() { return unsafe { self.proxy( @@ -139,6 +157,9 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { *addrlen = block_addrlen; } + // register valid fd + self.fd_register(usize::from(ret[0]) as _); + Ok(ret) } @@ -150,6 +171,10 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { addrlen: libc::size_t, ) -> Result { self.trace("connect", 3); + + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + if addrlen > Block::buf_capacity() { return Err(libc::EINVAL); } @@ -176,6 +201,9 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { ) -> Result { self.trace("recvfrom", 6); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(fd)?; + // Limit the read to `Block::buf_capacity()` let count = usize::min(count, Block::buf_capacity()); @@ -266,6 +294,9 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { ) -> Result { self.trace("sendto", 6); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(sockfd)?; + // Limit the write to `Block::buf_capacity()` let count = usize::min(count, Block::buf_capacity()); @@ -320,6 +351,9 @@ pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized { ) -> Result { self.trace("setsockopt", 5); + // check if operation is allowed on this fd + let _ = self.fd_is_valid(sockfd)?; + let optval = optval.validate_slice(optlen, self).ok_or(libc::EFAULT)?; let c = self.new_cursor(); let (_, buf) = c.copy_from_slice(optval).or(Err(libc::EMSGSIZE))?;