diff --git a/src/safeposix/syscalls/fs_calls.rs b/src/safeposix/syscalls/fs_calls.rs index beb037a2..3587e3a3 100644 --- a/src/safeposix/syscalls/fs_calls.rs +++ b/src/safeposix/syscalls/fs_calls.rs @@ -186,13 +186,13 @@ impl Cage { if path.len() == 0 { return syscall_error(Errno::ENOENT, "open", "given path was null"); } - + // Retrieve the absolute path from the root directory. The absolute path is then // used to validate directory paths while navigating through // subdirectories and creating a new file or open existing file at the given // location. let truepath = normpath(convpath(path), self); - + // Fetch the next file descriptor and its lock write guard to ensure the file // can be associated with the file descriptor let (fd, guardopt) = self.get_next_fd(None); @@ -204,11 +204,12 @@ impl Cage { "no available file descriptor number could be found", ); } - + // When the file descriptor is valid, we proceed with performing the remaining // checks for open_syscall. - let fdoption = &mut *guardopt.unwrap_or_else(|| panic!("File descriptor couldn't be fetched!")); - + let fdoption = + &mut *guardopt.unwrap_or_else(|| panic!("File descriptor couldn't be fetched!")); + // Walk through the absolute path which returns a tuple consisting of inode // number of file (if it exists), and inode number of parent (if it exists) match metawalkandparent(truepath.as_path()) { @@ -223,13 +224,13 @@ impl Cage { "tried to open a file that did not exist, and O_CREAT was not specified", ); } - + // Error is thrown when the input flags contain S_IFCHR flag representing a // special character file. if S_IFCHR == (S_IFCHR & flags) { return syscall_error(Errno::EINVAL, "open", "Invalid value in flags"); } - + // S_FILETYPEFLAGS represents a bitmask that can be used to extract the file // type information from a file's mode. This code is // referenced from Lind-Repy codebase. Here, we are @@ -239,14 +240,14 @@ impl Cage { if mode & (S_IRWXA | S_FILETYPEFLAGS as u32) != mode { return syscall_error(Errno::EPERM, "open", "Mode bits were not sane"); } - + let filename = truepath.file_name().unwrap().to_str().unwrap().to_string(); //for now we assume this is sane, but maybe this should be checked later let time = interface::timestamp(); //We do a real timestamp now - + // S_IFREG is the flag for a regular file, so it's added to the mode to // indicate that the new file being created is a regular file. let effective_mode = S_IFREG as u32 | mode; - + // Create a new inode of type "File" representing a file and set the // required attributes let newinode = Inode::File(GenericInode { @@ -263,12 +264,12 @@ impl Cage { ctime: time, mtime: time, }); - + // Fetch the next available inode number using the FileSystem MetaData table let newinodenum = FS_METADATA .nextinode .fetch_add(1, interface::RustAtomicOrdering::Relaxed); //fetch_add returns the previous value, which is the inode number we want - + // Fetch the inode of the parent directory and only proceed when its type is // directory. if let Inode::Dir(ref mut ind) = @@ -291,7 +292,7 @@ impl Cage { FS_METADATA.inodetable.insert(newinodenum, newinode); log_metadata(&FS_METADATA, pardirinode); log_metadata(&FS_METADATA, newinodenum); - + // FileObjectTable stores the entries of the currently opened files in the // system Since, a new file is being opened here, an // entry corresponding to that newinode is made in the FileObjectTable @@ -303,13 +304,14 @@ impl Cage { vac.insert(interface::openfile(sysfilename, 0).unwrap()); // new file of size 0 } - + // The file object of size 0, associated with the newinode number is // inserted into the FileDescriptorTable associated with the cage using the // guard lock. - let _insertval = fdoption.insert(File(self._file_initializer(newinodenum, flags, 0))); + let _insertval = + fdoption.insert(File(self._file_initializer(newinodenum, flags, 0))); } - + // Case 2: When the file exists (we don't need to look at parent here) (Some(inodenum), ..) => { //If O_CREAT and O_EXCL flags are set in the input parameters, @@ -326,7 +328,7 @@ impl Cage { ); } let size; - + // Fetch the Inode Object associated with the inode number of the existing // file. There are different Inode types supported // by the open_syscall (i.e., File, Directory, Socket, CharDev). @@ -344,38 +346,40 @@ impl Cage { if let interface::RustHashEntry::Occupied(occ) = &entry { occ.get().close().unwrap(); } - + f.size = 0; - + // Update the timestamps as well let latest_time = interface::timestamp(); f.ctime = latest_time; f.mtime = latest_time; - + // Remove the previous file and add a new one of 0 length if let interface::RustHashEntry::Occupied(occ) = entry { occ.remove_entry(); } - + // The current file is removed from the filesystem let sysfilename = format!("{}{}", FILEDATAPREFIX, inodenum); interface::removefile(sysfilename.clone()).unwrap(); } - + // Once the metadata for the file is reset, a new file is inserted // in file system. Also, it is // inserted back to the FileObjectTable and associated with same // inodeNumber representing that the file is currently in open // state. - if let interface::RustHashEntry::Vacant(vac) = FILEOBJECTTABLE.entry(inodenum) { + if let interface::RustHashEntry::Vacant(vac) = + FILEOBJECTTABLE.entry(inodenum) + { let sysfilename = format!("{}{}", FILEDATAPREFIX, inodenum); vac.insert(interface::openfile(sysfilename, f.size).unwrap()); } - + // Update the final size and reference count for the file size = f.size; f.refcount += 1; - + // Current Implementation for File Truncate: The // previous entry of the file is removed from // the FileObjectTable, with a new file of size @@ -384,7 +388,7 @@ impl Cage { // the file size and pointer of the existing // file? } - + // When the existing file type is of Directory or Character Device, only // the file size and the reference count is updated. Inode::Dir(ref mut f) => { @@ -395,20 +399,21 @@ impl Cage { size = f.size; f.refcount += 1; } - + // If the existing file type is a socket, error is thrown as socket type // files are not supported by open_syscall Inode::Socket(_) => { return syscall_error(Errno::ENXIO, "open", "file is a UNIX domain socket"); } } - + // The file object of size 0, associated with the existing inode number is // inserted into the FileDescriptorTable associated with the cage using the // guard lock. - let _insertval = fdoption.insert(File(self._file_initializer(inodenum, flags, size))); + let _insertval = + fdoption.insert(File(self._file_initializer(inodenum, flags, size))); } - + // Case 3: When neither the file directory nor the parent directory exists (None, None) => { // O_CREAT flag is used to create a file if it doesn't exist. @@ -433,7 +438,6 @@ impl Cage { // Return the valid file descriptor fd } - /// ### Description /// @@ -1310,8 +1314,12 @@ impl Cage { pub fn fstat_syscall(&self, fd: i32, statbuf: &mut StatData) -> i32 { // Attempt to get the file descriptor - // BUG: This can panic if there is an invalid file descriptor provided - let checkedfd = self.get_filedescriptor(fd).unwrap(); + + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fstat_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); // Acquire a write lock on the file descriptor to ensure exclusive access. let unlocked_fd = checkedfd.read(); @@ -1466,10 +1474,11 @@ impl Cage { /// refer to the statfs man page [here](https://man7.org/linux/man-pages/man2/statfs.2.html). pub fn fstatfs_syscall(&self, fd: i32, databuf: &mut FSData) -> i32 { - // BUG: If the provided file descriptor is out of bounds, get_filedescriptor - // returns Err(), unwrapping on which produces a 'panic!' - // otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fstatfs_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { @@ -1579,7 +1588,11 @@ impl Cage { /// [read(2)](https://man7.org/linux/man-pages/man2/read.2.html) pub fn read_syscall(&self, fd: i32, buf: *mut u8, count: usize) -> i32 { // Attempt to get the file descriptor - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "read_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); // Acquire a write lock on the file descriptor to ensure exclusive access. let mut unlocked_fd = checkedfd.write(); @@ -1790,7 +1803,11 @@ impl Cage { /// [pread(2)](https://man7.org/linux/man-pages/man2/pread.2.html) pub fn pread_syscall(&self, fd: i32, buf: *mut u8, count: usize, offset: isize) -> i32 { // Attempt to get the file descriptor - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "pread_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); // Acquire a write lock on the file descriptor to ensure exclusive access. let mut unlocked_fd = checkedfd.write(); @@ -2011,7 +2028,11 @@ impl Cage { //If the provided file descriptor is out of bounds, get_filedescriptor returns //Err(), unwrapping on which produces a 'panic!' //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "write_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); // Acquire a write lock on the file descriptor to ensure exclusive access. let mut unlocked_fd = checkedfd.write(); @@ -2242,11 +2263,11 @@ impl Cage { /// For more detailed description of all the commands and return values, see /// [pwrite(2)](https://man7.org/linux/man-pages/man2/pwrite.2.html) pub fn pwrite_syscall(&self, fd: i32, buf: *const u8, count: usize, offset: isize) -> i32 { - //BUG - //If the provided file descriptor is out of bounds, get_filedescriptor returns - //Err(), unwrapping on which produces a 'panic!' - //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "pwrite_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); // Acquire a write lock on the file descriptor to ensure exclusive access. let mut unlocked_fd = checkedfd.write(); @@ -2452,7 +2473,7 @@ impl Cage { /// The function first retrieves the file descriptor object associated with /// the provided file descriptor and then matches the file descriptor /// type and calls the appropriate write function based on the type. - /// #### Sockets: + /// #### Sockets: /// The function writes data to the connected socket, handling /// both TCP and UDP sockets. /// * Checks if the socket is connected (either fully connected or @@ -2460,7 +2481,7 @@ impl Cage { /// * If connected, calls the underlying `writev` function on the raw /// socket. /// * Handles errors returned by the underlying `writev` function. - /// #### Pipes: + /// #### Pipes: /// The function writes data to the pipe, supporting non-blocking /// writes. /// * Checks if the pipe is open for writing. @@ -2469,19 +2490,23 @@ impl Cage { /// /// #### Streams: /// The function supports logging data written to a stream. - /// * Concatenates the multiple buffers (`iovec`) into a single contiguous slice. + /// * Concatenates the multiple buffers (`iovec`) into a single contiguous + /// slice. /// * Calls `log_from_slice` to write the data and logs the result. /// * Returns the number of bytes successfully written. /// /// #### Files: /// The function writes data to regular files using vectored I/O. /// * Checks if the file is open for writing. - /// * Retrieves the associated inode and ensures the write position is valid. - /// * Handles writing past the end of the file by padding with blank bytes if necessary. + /// * Retrieves the associated inode and ensures the write position is + /// valid. + /// * Handles writing past the end of the file by padding with blank bytes + /// if necessary. /// * Updates the file size if the write extends the file. - /// * Writes data using the vectored I/O method and returns the number of bytes written. + /// * Writes data using the vectored I/O method and returns the number of + /// bytes written. /// * Triggers `EISDIR` if an attempt is made to write to a directory. - /// + /// /// ### Function Arguments /// * `fd`: The file descriptor to write to. /// * `iovec`: A pointer to an array of `IovecStruct` objects representing @@ -2503,8 +2528,9 @@ impl Cage { /// socket protocol. /// * `EAGAIN(11)`: There is no data available right now (for pipes). /// * `EPIPE(32)`: The pipe has been closed on the other end (for pipes). - /// * `EISDIR(21)`: The target file descriptor points to a directory (for files). - /// + /// * `EISDIR(21)`: The target file descriptor points to a directory (for + /// files). + /// /// ### Panics /// * If an unknown error code is returned by the underlying socket writev /// * If the inode number does not exist in the file system metadata table. @@ -2516,7 +2542,11 @@ impl Cage { iovec: *const interface::IovecStruct, iovcnt: i32, ) -> i32 { - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "writev_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { // we're only implementing this for INET/tcp sockets right now @@ -2687,11 +2717,12 @@ impl Cage { Inode::File(ref mut normalfile_inode_obj) => { // The inode object retrieved is of type File. We get a mutable // reference to the actual inode data. - let position = normalfile_filedesc_obj.position; + let position = normalfile_filedesc_obj.position; // Get the current write position from the file descriptor object let filesize = normalfile_inode_obj.size; // Get the file size - let blankbytecount = position as isize - filesize as isize; - // Calculate the difference between the required and desired file position + let blankbytecount = position as isize - filesize as isize; + // Calculate the difference between the required and desired file + // position // Retrieve the file object from the file object table let mut fileobject = FILEOBJECTTABLE @@ -2827,11 +2858,11 @@ impl Cage { /// For more detailed description of all the commands and return values, see /// [lseek(2)](https://man7.org/linux/man-pages/man2/lseek.2.html) pub fn lseek_syscall(&self, fd: i32, offset: isize, whence: i32) -> i32 { - //BUG - //If the provided file descriptor is out of bounds, get_filedescriptor returns - //Err(), unwrapping on which produces a 'panic!' - //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "lseek_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); // Acquire a write lock on the file descriptor to ensure exclusive access. let mut unlocked_fd = checkedfd.write(); @@ -3111,11 +3142,11 @@ impl Cage { /// [fchdir(2)](https://linux.die.net/man/2/fchdir) pub fn fchdir_syscall(&self, fd: i32) -> i32 { - //BUG - //if the provided file descriptor is out of bounds, get_filedescriptor returns - //Err(), unwrapping on which produces a 'panic!' - //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fchdir_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); //If a table descriptor entry corresponds to a file, we check if it is //a directory file type. If it is not, we return `A component of path is @@ -3593,11 +3624,11 @@ impl Cage { /// For more detailed description of all the commands and return values, see /// [close(2)](https://man7.org/linux/man-pages/man2/close.2.html) pub fn _close_helper_inner(&self, fd: i32) -> i32 { - //BUG - //if the provided file descriptor is out of bounds, get_filedescriptor returns - // Err(), unwrapping on which produces a 'panic!' - //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "close_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { // We decide, how to proceed depending on the fd type. @@ -3828,11 +3859,12 @@ impl Cage { // Once we know that the closing of the fd was successful, // we remove the file descriptor from the fd table and free the space. // - // Bug: - // if the provided file descriptor is out of bounds, get_filedescriptor returns - // Err(), unwrapping on which produces a 'panic!' - //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "close_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); // This operation effectively removes the file descriptor from the fd table // by removing its reference from the variable and then not using it further, @@ -3878,11 +3910,11 @@ impl Cage { /// [fcntl(2)](https://linux.die.net/man/2/fcntl) pub fn fcntl_syscall(&self, fd: i32, cmd: i32, arg: i32) -> i32 { - //BUG - //if the provided file descriptor is out of bounds, get_filedescriptor returns - // Err(), unwrapping on which produces a 'panic!' - //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fcntl_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { //'flags' consists of bitwise-or'd access mode, file creation, and file status flags @@ -4024,11 +4056,11 @@ impl Cage { /// devices, and possible error values, see [ioctl(2)](https://man.openbsd.org/ioctl) pub fn ioctl_syscall(&self, fd: i32, request: u32, ptrunion: IoctlPtrUnion) -> i32 { - //BUG - //if the provided file descriptor is out of bounds, 'get_filedescriptor' - // returns Err(), unwrapping on which produces a 'panic!' - //otherwise, file descriptor table entry is stored in 'checkedfd' - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "ioctl_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); //if a table descriptor entry is non-empty, a valid request is performed if let Some(filedesc_enum) = &mut *unlocked_fd { @@ -4297,11 +4329,11 @@ impl Cage { /// [fchmod(2)](https://linux.die.net/man/2/fchmod) pub fn fchmod_syscall(&self, fd: i32, mode: u32) -> i32 { - //BUG - //if the provided file descriptor is out of bounds, 'get_filedescriptor' - //returns `Err()`, unwrapping on which produces a `panic!` - //otherwise, file descriptor table entry is stored in `checkedfd` - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fchmod_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); //if a table descriptor entry is non-empty, a valid request is performed if let Some(filedesc_enum) = &*unlocked_fd { @@ -4574,7 +4606,11 @@ impl Cage { //------------------------------------FLOCK SYSCALL------------------------------------ pub fn flock_syscall(&self, fd: i32, operation: i32) -> i32 { - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "flock_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { let lock = match filedesc_enum { @@ -5057,7 +5093,11 @@ impl Cage { //------------------------------------FSYNC SYSCALL------------------------------------ pub fn fsync_syscall(&self, fd: i32) -> i32 { - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fsync_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { @@ -5108,7 +5148,11 @@ impl Cage { //------------------------------------FDATASYNC SYSCALL------------------------------------ pub fn fdatasync_syscall(&self, fd: i32) -> i32 { - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fdatasync_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { @@ -5165,7 +5209,11 @@ impl Cage { nbytes: isize, flags: u32, ) -> i32 { - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "sync_file_range_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { @@ -5221,7 +5269,11 @@ impl Cage { //------------------FTRUNCATE SYSCALL------------------ pub fn ftruncate_syscall(&self, fd: i32, length: isize) -> i32 { - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "ftruncate_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { match filedesc_enum { diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index 90f738d5..7e4a9d83 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -629,7 +629,11 @@ impl Cage { prereserved: bool, ) -> i32 { //checkedfd is an atomic reference count of the number of locks on the fd - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "bind_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); //returns a write lock once no other writers or readers have access to the lock let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { @@ -877,7 +881,11 @@ impl Cage { pub fn connect_syscall(&self, fd: i32, remoteaddr: &interface::GenSockaddr) -> i32 { //If fd is out of range of [0,MAXFD], process will panic //Otherwise, we obtain a write guard to the Option object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "connect_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); //Pattern match such that FileDescriptor object must be the Socket variant //Otherwise, return with an err as the fd refers to something other than a @@ -1356,10 +1364,12 @@ impl Cage { if dest_addr.port() == 0 && dest_addr.addr().is_unspecified() { return self.send_syscall(fd, buf, buflen, flags); } - //BUG: - //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write guard to the Option object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "sendto_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); //Check if the write guard holds a valid FileDescriptor if let Some(filedesc_enum) = &mut *unlocked_fd { @@ -1591,10 +1601,11 @@ impl Cage { /// for more detailed description of all the commands and return values, see /// [send(2)](https://linux.die.net/man/2/send) pub fn send_syscall(&self, fd: i32, buf: *const u8, buflen: usize, flags: i32) -> i32 { - //BUG: - //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write guard to the Option object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "send_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); //Check if the write guard holds a valid FileDescriptor if let Some(filedesc_enum) = &mut *unlocked_fd { @@ -2212,10 +2223,11 @@ impl Cage { flags: i32, addr: &mut Option<&mut interface::GenSockaddr>, ) -> i32 { - //BUG: - //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write guard to the Option object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "recv_common", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); //Check if the write guard holds a valid FileDescriptor, and if so //call recv_common_inner. @@ -2430,10 +2442,11 @@ impl Cage { /// for more detailed description of all the commands and return values, see /// [listen(2)](https://linux.die.net/man/2/listen) pub fn listen_syscall(&self, fd: i32, backlog: i32) -> i32 { - //BUG: - //If fd is out of range of [0,MAXFD], process will panic - //Otherwise, we obtain a write guard to the Option object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "listen_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { match filedesc_enum { @@ -2819,7 +2832,11 @@ impl Cage { // this function is an inner function of shutdown and checks for fd pub fn _cleanup_socket(&self, fd: i32, how: i32) -> i32 { // get the file descriptor object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "netshutdown_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(ref mut filedesc_enum) = &mut *unlocked_fd { let inner_result = self._cleanup_socket_inner(filedesc_enum, how, true); @@ -2915,7 +2932,11 @@ impl Cage { pub fn accept_syscall(&self, fd: i32, addr: &mut interface::GenSockaddr) -> i32 { //If fd is out of range of [0,MAXFD], process will panic //Otherwise, we obtain a write guard to the Option object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "accept_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { //Find the next available file descriptor and grab a mutable reference @@ -3412,7 +3433,11 @@ impl Cage { if !exceptfds_ref.is_set(fd) { continue; } - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "select_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if unlocked_fd.is_none() { return syscall_error(Errno::EBADF, "select", "invalid file descriptor"); @@ -3469,7 +3494,11 @@ impl Cage { // try to get the FileDescriptor Object from fd number // if the fd exists, do further processing based on the file descriptor type // otherwise, raise an error - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "select_readfds", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { match filedesc_enum { @@ -3628,7 +3657,11 @@ impl Cage { // try to get the FileDescriptor Object from fd number // if the fd exists, do further processing based on the file descriptor type // otherwise, raise an error - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "select_writefds", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { match filedesc_enum { @@ -3795,7 +3828,11 @@ impl Cage { } // try to get the file descriptor object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "getsockopt_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { if let Socket(ref mut sockfdobj) = filedesc_enum { @@ -4011,7 +4048,11 @@ impl Cage { } // get the file descriptor object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "setsockopt_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let mut unlocked_fd = checkedfd.write(); if let Some(filedesc_enum) = &mut *unlocked_fd { if let Socket(ref mut sockfdobj) = filedesc_enum { @@ -4245,7 +4286,11 @@ impl Cage { } // get the file descriptor object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "getpeername_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { if let Socket(sockfdobj) = filedesc_enum { @@ -4316,7 +4361,11 @@ impl Cage { } // get the file descriptor object - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "getsockname_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { if let Socket(sockfdobj) = filedesc_enum { @@ -4751,7 +4800,11 @@ impl Cage { } // check if the other fd is an epoll or not... - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "epoll_ctl_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { match filedesc_enum { diff --git a/src/safeposix/syscalls/sys_calls.rs b/src/safeposix/syscalls/sys_calls.rs index 10be5122..4794fc38 100644 --- a/src/safeposix/syscalls/sys_calls.rs +++ b/src/safeposix/syscalls/sys_calls.rs @@ -204,7 +204,11 @@ impl Cage { let newfdtable = init_fdtable(); //Loop from 0 to maximum value of file descriptor index for fd in 0..MAXFD { - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "fork_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); //Get the lock for the file descriptor let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { @@ -447,7 +451,11 @@ impl Cage { let mut cloexecvec = vec![]; for fd in 0..MAXFD { // Get mutex of the file descriptor - let checkedfd = self.get_filedescriptor(fd).unwrap(); + let fdres = self.get_filedescriptor(fd); + if fdres.is_err() { + return syscall_error(Errno::EBADF, "exec_syscall", "invalid file descriptor"); + } + let checkedfd = fdres.unwrap(); let unlocked_fd = checkedfd.read(); if let Some(filedesc_enum) = &*unlocked_fd { // For each valid file descriptor we chech if the O_CLOEXEC flag is set or not