From db371eeafb826880156c15e8017f7f6bec3151e6 Mon Sep 17 00:00:00 2001 From: "Alice W." Date: Mon, 4 Nov 2024 13:06:53 -0500 Subject: [PATCH 1/7] kernel close --- src/safeposix/syscalls/fs_calls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/safeposix/syscalls/fs_calls.rs b/src/safeposix/syscalls/fs_calls.rs index 541ec76..caf50c4 100644 --- a/src/safeposix/syscalls/fs_calls.rs +++ b/src/safeposix/syscalls/fs_calls.rs @@ -1881,8 +1881,8 @@ impl Cage { } } -pub fn kernel_close(_fdentry: fdtables::FDTableEntry, kernelfd: u64) { +pub fn kernel_close(fdentry: fdtables::FDTableEntry) { let _ret = unsafe { - libc::close(kernelfd as i32) + libc::close(fdentry.underfd as i32) }; } From cd097bca26d377607282352bb38039b8244aeb44 Mon Sep 17 00:00:00 2001 From: "Alice W." Date: Mon, 4 Nov 2024 13:14:04 -0500 Subject: [PATCH 2/7] patch --- src/safeposix/syscalls/fs_calls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/safeposix/syscalls/fs_calls.rs b/src/safeposix/syscalls/fs_calls.rs index caf50c4..0072b1b 100644 --- a/src/safeposix/syscalls/fs_calls.rs +++ b/src/safeposix/syscalls/fs_calls.rs @@ -1881,7 +1881,7 @@ impl Cage { } } -pub fn kernel_close(fdentry: fdtables::FDTableEntry) { +pub fn kernel_close(fdentry: fdtables::FDTableEntry, _count: u64) { let _ret = unsafe { libc::close(fdentry.underfd as i32) }; From 862e5a69520e878d2b180beefb43ee99a08f8bba Mon Sep 17 00:00:00 2001 From: "Alice W." Date: Tue, 5 Nov 2024 12:14:56 -0500 Subject: [PATCH 3/7] fix select -- handling None value --- src/safeposix/syscalls/net_calls.rs | 54 ++++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index e2270ac..d183c94 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -490,12 +490,6 @@ impl Cage { * bitmask by ourself. We use Vec to express the fd_set of the virtual file descriptor * in Lind, and expand the conversion function between lind fd_set and kernel fd_set. * - * We chose to use bit-set to implement our own fd_set data structure because bit-set - * provides efficient set operations, allowing us to effectively represent and manipulate - * file descriptor sets. These operations can maximize the fidelity to the POSIX fd_set - * characteristics. - * Reference: https://docs.rs/bit-set/latest/bit_set/struct.BitSet.html - * * select() will return: * - the total number of bits that are set in readfds, writefds, errorfds * - 0, if the timeout expired before any file descriptors became ready @@ -532,25 +526,35 @@ impl Cage { fdkindset.insert(FDKIND_KERNEL); let (selectbittables, unparsedtables, mappingtable) = fdtables::prepare_bitmasks_for_select(self.cageid, nfds as u64, orfds.copied(), owfds.copied(), oefds.copied(), &fdkindset).unwrap(); + // libc select() - let (readnfd, mut real_readfds) = selectbittables[0].get(&FDKIND_KERNEL).unwrap(); - let (writenfd, mut real_writefds) = selectbittables[1].get(&FDKIND_KERNEL).unwrap(); - let (errornfd, mut real_errorfds) = selectbittables[2].get(&FDKIND_KERNEL).unwrap(); + // Check: + // 1. If there exists virtual fd_set values + // 2. If there exists kernel fd_set + // If yes -- Convert into kernel fd_set structure + // If no -- Set it to null + let (readnfd, mut real_readfds) = selectbittables + .get(0) + .and_then(|table| table.get(&FDKIND_KERNEL).cloned()) + .unwrap_or((0, fdtables::_init_fd_set())); + let (writenfd, mut real_writefds) = selectbittables + .get(1) + .and_then(|table| table.get(&FDKIND_KERNEL).cloned()) + .unwrap_or((0, fdtables::_init_fd_set())); + let (errornfd, mut real_errorfds) = selectbittables + .get(2) + .and_then(|table| table.get(&FDKIND_KERNEL).cloned()) + .unwrap_or((0, fdtables::_init_fd_set())); - let mut realnewnfds = readnfd; - if realnewnfds < writenfd { - realnewnfds = writenfd; - } else if realnewnfds < errornfd { - realnewnfds = errornfd; - } + let mut realnewnfds = readnfd.max(writenfd).max(errornfd); // Ensured that null_mut is used if the Option is None for fd_set parameters. let ret = unsafe { libc::select( - *realnewnfds as i32, - &mut real_readfds as *mut fd_set, - &mut real_writefds as *mut fd_set, - &mut real_errorfds as *mut fd_set, + realnewnfds as i32, + &mut real_readfds as *mut _, + &mut real_writefds as *mut _, + &mut real_errorfds as *mut _, &mut timeout as *mut timeval) }; @@ -560,14 +564,14 @@ impl Cage { } // impipe/imsock select() - let start_time = starttimer(); + // let start_time = starttimer(); - let end_time = match rposix_timeout { - Some(time) => time, - None => RustDuration::MAX, - }; + // let end_time = match rposix_timeout { + // Some(time) => time, + // None => RustDuration::MAX, + // }; - let mut return_code = 0; + // let mut return_code = 0; let mut unreal_read = HashSet::new(); let mut unreal_write = HashSet::new(); From 630503a4c0866b9d52506d3fe8b693ca64a2687c Mon Sep 17 00:00:00 2001 From: "Alice W." Date: Tue, 5 Nov 2024 12:44:40 -0500 Subject: [PATCH 4/7] debug select -- nfds usage --- src/safeposix/syscalls/net_calls.rs | 39 ++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index d183c94..a8e1b58 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -504,6 +504,13 @@ impl Cage { rposix_timeout: Option, ) -> i32 { + println!("[Select] nfds: {:?}", nfds); + println!("[Select] readfds: {:?}", readfds); + println!("[Select] writefds: {:?}", writefds); + println!("[Select] errorfds: {:?}", errorfds); + println!("[Select] timeout: {:?}", rposix_timeout); + io::stdout().flush().unwrap(); + let mut timeout; if rposix_timeout.is_none() { timeout = libc::timeval { @@ -548,6 +555,10 @@ impl Cage { let mut realnewnfds = readnfd.max(writenfd).max(errornfd); + println!("[Select] - Before kernel select \n[Select] real_readfds: {:?}", real_readfds); + println!("[Select] timeout: {:?}\n[Select] rposix_timeout: {:?}\n[Select] realnewnfds: {:?}", timeout, rposix_timeout, realnewnfds); + io::stdout().flush().unwrap(); + // Ensured that null_mut is used if the Option is None for fd_set parameters. let ret = unsafe { libc::select( @@ -558,7 +569,23 @@ impl Cage { &mut timeout as *mut timeval) }; + println!("[Select] - After kernel select - real_readfds: {:?}", real_readfds); + println!("[Select] - After kernel select - realnewnfds: {:?}", realnewnfds); + println!("[Select] - After kernel select - Return value: {:?}", ret); + io::stdout().flush().unwrap(); + if ret < 0 { + let err = unsafe { + libc::__errno_location() + }; + let err_str = unsafe { + libc::strerror(*err) + }; + let err_msg = unsafe { + CStr::from_ptr(err_str).to_string_lossy().into_owned() + }; + println!("[Select] Error message: {:?}", err_msg); + io::stdout().flush().unwrap(); let errno = get_errno(); return handle_errno(errno, "select"); } @@ -626,7 +653,7 @@ impl Cage { // Revert result let (read_flags, read_result) = fdtables::get_one_virtual_bitmask_from_select_result( FDKIND_KERNEL, - nfds as u64, + realnewnfds as u64, Some(real_readfds), unreal_read, None, @@ -639,7 +666,7 @@ impl Cage { let (write_flags, write_result) = fdtables::get_one_virtual_bitmask_from_select_result( FDKIND_KERNEL, - nfds as u64, + realnewnfds as u64, Some(real_writefds), unreal_write, None, @@ -652,7 +679,7 @@ impl Cage { let (error_flags, error_result) = fdtables::get_one_virtual_bitmask_from_select_result( FDKIND_KERNEL, - nfds as u64, + realnewnfds as u64, Some(real_errorfds), HashSet::new(), // Assuming there are no unreal errorsets None, @@ -663,6 +690,12 @@ impl Cage { **errorfds = error_result.unwrap(); } + let final_ret = read_flags + write_flags + error_flags; + println!("[Select] read_flags: {:?}", read_flags); + println!("[Select] write_flags: {:?}", write_flags); + println!("[Select] error_flags: {:?}", error_flags); + println!("[Select] final return: {:?}", final_ret); + io::stdout().flush().unwrap(); // The total number of descriptors ready (read_flags + write_flags + error_flags) as i32 } From f2d0b76c18550b7b2e40607549e78576db999a74 Mon Sep 17 00:00:00 2001 From: "Alice W." Date: Tue, 5 Nov 2024 13:24:25 -0500 Subject: [PATCH 5/7] fixed select --- src/safeposix/syscalls/net_calls.rs | 48 +++++------------------------ 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index a8e1b58..499cf40 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -482,13 +482,12 @@ impl Cage { } /* - * fd_set is used in the Linux select system call to specify the file descriptor - * to be monitored. fd_set is actually a bit array, each bit of which represents - * a file descriptor. fd_set is a specific data type used by the kernel, so we need - * to make sure the final variable we pass to the kernel is in the format that the - * kernel expects. That's why we choose to use FD_SET function instead of doing - * bitmask by ourself. We use Vec to express the fd_set of the virtual file descriptor - * in Lind, and expand the conversion function between lind fd_set and kernel fd_set. + * The design logic for select is first to categorize the file descriptors (fds) received from the user based on FDKIND. + * Specifically, kernel fds are passed to the underlying libc select, while impipe and imsock fds would be processed by the + * in-memory system. Afterward, the results are combined and consolidated accordingly. + * + * (Note: Currently, only kernel fds are supported. The implementation for in-memory pipes is commented out and will require + * further integration and testing once in-memory pipe support is added.) * * select() will return: * - the total number of bits that are set in readfds, writefds, errorfds @@ -503,14 +502,6 @@ impl Cage { mut errorfds: Option<&mut fd_set>, rposix_timeout: Option, ) -> i32 { - - println!("[Select] nfds: {:?}", nfds); - println!("[Select] readfds: {:?}", readfds); - println!("[Select] writefds: {:?}", writefds); - println!("[Select] errorfds: {:?}", errorfds); - println!("[Select] timeout: {:?}", rposix_timeout); - io::stdout().flush().unwrap(); - let mut timeout; if rposix_timeout.is_none() { timeout = libc::timeval { @@ -555,9 +546,6 @@ impl Cage { let mut realnewnfds = readnfd.max(writenfd).max(errornfd); - println!("[Select] - Before kernel select \n[Select] real_readfds: {:?}", real_readfds); - println!("[Select] timeout: {:?}\n[Select] rposix_timeout: {:?}\n[Select] realnewnfds: {:?}", timeout, rposix_timeout, realnewnfds); - io::stdout().flush().unwrap(); // Ensured that null_mut is used if the Option is None for fd_set parameters. let ret = unsafe { @@ -569,23 +557,7 @@ impl Cage { &mut timeout as *mut timeval) }; - println!("[Select] - After kernel select - real_readfds: {:?}", real_readfds); - println!("[Select] - After kernel select - realnewnfds: {:?}", realnewnfds); - println!("[Select] - After kernel select - Return value: {:?}", ret); - io::stdout().flush().unwrap(); - if ret < 0 { - let err = unsafe { - libc::__errno_location() - }; - let err_str = unsafe { - libc::strerror(*err) - }; - let err_msg = unsafe { - CStr::from_ptr(err_str).to_string_lossy().into_owned() - }; - println!("[Select] Error message: {:?}", err_msg); - io::stdout().flush().unwrap(); let errno = get_errno(); return handle_errno(errno, "select"); } @@ -689,13 +661,7 @@ impl Cage { if let Some(errorfds) = errorfds.as_mut() { **errorfds = error_result.unwrap(); } - - let final_ret = read_flags + write_flags + error_flags; - println!("[Select] read_flags: {:?}", read_flags); - println!("[Select] write_flags: {:?}", write_flags); - println!("[Select] error_flags: {:?}", error_flags); - println!("[Select] final return: {:?}", final_ret); - io::stdout().flush().unwrap(); + // The total number of descriptors ready (read_flags + write_flags + error_flags) as i32 } From 0755d67d655785002354e2c4071d94b4d0687948 Mon Sep 17 00:00:00 2001 From: "Alice W." Date: Thu, 7 Nov 2024 09:53:47 -0500 Subject: [PATCH 6/7] Refine comments and format changing --- src/safeposix/syscalls/net_calls.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index 499cf40..422b1a6 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -523,14 +523,22 @@ impl Cage { // fdkindset.insert(FDKIND_IMPIPE); fdkindset.insert(FDKIND_KERNEL); - let (selectbittables, unparsedtables, mappingtable) = fdtables::prepare_bitmasks_for_select(self.cageid, nfds as u64, orfds.copied(), owfds.copied(), oefds.copied(), &fdkindset).unwrap(); + let (selectbittables, unparsedtables, mappingtable) + = fdtables::prepare_bitmasks_for_select( + self.cageid, + nfds as u64, + orfds.copied(), + owfds.copied(), + oefds.copied(), + &fdkindset) + .unwrap(); - // libc select() - // Check: - // 1. If there exists virtual fd_set values - // 2. If there exists kernel fd_set - // If yes -- Convert into kernel fd_set structure - // If no -- Set it to null + // ------ libc select() ------ + // In select, each fd_set is allowed to contain empty values, as it’s possible for the user to input a mixture of pure + // virtual_fds and those with underlying real file descriptors. This means we need to check each fd_set separately to + // handle both types of descriptors properly. The goal here is to ensure that each fd_set (read, write, error) is correctly + // initialized. To handle cases where selectbittables does not contain an entry at the expected index or where it doesn’t + // include a FDKIND_KERNEL entry, the code assigns a default value with an initialized fd_set and an nfd of 0. let (readnfd, mut real_readfds) = selectbittables .get(0) .and_then(|table| table.get(&FDKIND_KERNEL).cloned()) From b3280f6f67936ff56c2454a4716508128febc2e9 Mon Sep 17 00:00:00 2001 From: "Alice W." Date: Fri, 8 Nov 2024 11:59:12 -0500 Subject: [PATCH 7/7] Remove impipe related code in select() --- src/safeposix/syscalls/net_calls.rs | 171 ---------------------------- 1 file changed, 171 deletions(-) diff --git a/src/safeposix/syscalls/net_calls.rs b/src/safeposix/syscalls/net_calls.rs index 422b1a6..655320f 100644 --- a/src/safeposix/syscalls/net_calls.rs +++ b/src/safeposix/syscalls/net_calls.rs @@ -520,7 +520,6 @@ impl Cage { let oefds = errorfds.as_mut().map(|fds| &mut **fds); let mut fdkindset = HashSet::new(); - // fdkindset.insert(FDKIND_IMPIPE); fdkindset.insert(FDKIND_KERNEL); let (selectbittables, unparsedtables, mappingtable) @@ -570,66 +569,9 @@ impl Cage { return handle_errno(errno, "select"); } - // impipe/imsock select() - // let start_time = starttimer(); - - // let end_time = match rposix_timeout { - // Some(time) => time, - // None => RustDuration::MAX, - // }; - - // let mut return_code = 0; let mut unreal_read = HashSet::new(); let mut unreal_write = HashSet::new(); - /* TODO - 1. Do we need to handle errfds? - 2. Err returns? - */ - // loop { - // for (fdkind_flag, entry) in unparsedtables[0].iter() { - // if *fdkind_flag == FDKIND_IMPIPE { - // let res = self.select_impipe_read(fdkind_flag, entry, &mut unreal_read, &mut return_code, mappingtable.clone()); - // if res != 0 { - // return syscall_error(Errno::EINVAL, "select", ""); - // } - // } else if *fdkind_flag == FDKIND_IMSOCK { - // let res = self.select_imsock_read(fdkind_flag, entry, &mut unreal_read, &mut return_code, mappingtable.clone()); - // if res != 0 { - // return syscall_error(Errno::EINVAL, "select", ""); - // } - // } - // } - - // for (fdkind_flag, entry) in unparsedtables[1].iter() { - // if *fdkind_flag == FDKIND_IMPIPE { - // let res = self.select_impipe_write(fdkind_flag, entry, &mut unreal_write, &mut return_code, mappingtable.clone()); - // if res != 0 { - // return syscall_error(Errno::EINVAL, "select", ""); - // } - // } else if *fdkind_flag == FDKIND_IMSOCK { - // let res = self.select_imsock_write(entry); - // if res != 0 { - // return syscall_error(Errno::EINVAL, "select", ""); - // } - // } - // } - - // // We haven't handle errfds - - // // we break if there is any file descriptor ready - // // or timeout is reached - // if return_code != 0 || readtimer(start_time) > end_time { - // break; - // } else { - // // otherwise, check for signal and loop again - // if sigcheck() { - // return syscall_error(Errno::EINTR, "select", "interrupted function call"); - // } - // // We yield to let other threads continue if we've found no ready descriptors - // lind_yield(); - // } - // } // Revert result let (read_flags, read_result) = fdtables::get_one_virtual_bitmask_from_select_result( FDKIND_KERNEL, @@ -674,119 +616,6 @@ impl Cage { (read_flags + write_flags + error_flags) as i32 } - // pub fn select_impipe_read( - // &self, - // fdkind: &u32, - // entry: &HashSet, - // unreal_read: &mut HashSet, - // return_code: &mut i32, - // mappingtable: HashMap<(u32, u64), u64>, - // ) -> i32 { - // for impipe_entry in entry { - // if let IPCTableEntry::Pipe(ref pipe_entry) = *IPC_TABLE.get(&impipe_entry.underfd).unwrap() { - // if impipe_entry.perfdinfo as i32 & O_RDONLY != 0 { - // if pipe_entry.pipe.check_select_read() { - // *return_code += 1; - // match mappingtable.get(&(*fdkind, impipe_entry.underfd)) { - // Some(&virfd) => unreal_read.insert(virfd), - // None => return syscall_error(Errno::EBADFD, "select", "impipe") - // }; - // } - // } - // } - // } - // return 0; - // } - - // pub fn select_imsock_read( - // &self, - // fdkind: &u32, - // entry: &HashSet, - // unreal_read: &mut HashSet, - // return_code: &mut i32, - // mappingtable: HashMap<(u32, u64), u64>, - // ) -> i32 { - // for imsock_entry in entry { - // if let IPCTableEntry::DomainSocket(ref mut sock_entry) = *IPC_TABLE.get_mut(&imsock_entry.underfd).unwrap() { - // match sock_entry.state { - // ConnState::INPROGRESS => { - // let remotepathstring = CString::new(sock_entry.remoteaddr.unwrap().path()).unwrap(); - // let dsconnobj = DS_CONNECTION_TABLE.get(&remotepathstring); - // if dsconnobj.is_none() { - // sock_entry.state = ConnState::CONNECTED; - // } - // }, - // ConnState::LISTEN => { - // let localpathstring = CString::new(sock_entry.localaddr.unwrap().path()).unwrap(); - // let dsconnobj = DS_CONNECTION_TABLE.get(&localpathstring); - // if dsconnobj.is_some() { - // match mappingtable.get(&(*fdkind, imsock_entry.underfd)) { - // Some(&virfd) => unreal_read.insert(virfd), - // None => return syscall_error(Errno::EINVAL, "select", "invalid operation") - // }; - // *return_code += 1; - // } - // }, - // ConnState::CONNECTED | ConnState::CONNRDONLY => { - // let receivepipe = sock_entry.receivepipe.as_ref().unwrap(); - // if receivepipe.check_select_read() { - // match mappingtable.get(&(*fdkind, imsock_entry.underfd)) { - // Some(&virfd) => unreal_read.insert(virfd), - // None => return syscall_error(Errno::EINVAL, "select", "invalid operation") - // }; - // *return_code += 1; - // } - // }, - // _ => {} - // } - // } - // } - // 0 - // } - - // pub fn select_impipe_write( - // &self, - // fdkind: &u32, - // entry: &HashSet, - // unreal_write: &mut HashSet, - // return_code: &mut i32, - // mappingtable: HashMap<(u32, u64), u64>, - // ) -> i32 { - // for impipe_entry in entry { - // if let IPCTableEntry::Pipe(ref pipe_entry) = *IPC_TABLE.get(&impipe_entry.underfd).unwrap() { - // if impipe_entry.perfdinfo as i32 & O_WRONLY != 0 { - // if pipe_entry.pipe.check_select_write() { - // *return_code += 1; - // match mappingtable.get(&(*fdkind, impipe_entry.underfd)) { - // Some(&virfd) => unreal_write.insert(virfd), - // None => return syscall_error(Errno::EBADFD, "select", "impipe") - // }; - // } - // } - - // } - // } - // return 0; - // } - - // pub fn select_imsock_write( - // &self, - // entry: &HashSet, - // ) -> i32 { - // for imsock_entry in entry { - // if let IPCTableEntry::DomainSocket(ref mut sock_entry) = *IPC_TABLE.get_mut(&imsock_entry.underfd).unwrap() { - // if sock_entry.state == ConnState::INPROGRESS || sock_entry.state == ConnState::CONNWRONLY { // and writeonly - // let remotepathstring = CString::new(sock_entry.remoteaddr.unwrap().path()).unwrap(); - // let dsconnobj = DS_CONNECTION_TABLE.get(&remotepathstring); - // if dsconnobj.is_none() { - // sock_entry.state = ConnState::CONNECTED; - // } - // } - // } - // } - // return 0; - // } - /* * Get the kernel fd with provided virtual fd first * getsockopt() will return 0 when success and -1 when fail