Skip to content

Commit

Permalink
Merge branch 'develop' into pb_doc_stat_syscall
Browse files Browse the repository at this point in the history
  • Loading branch information
pranav-bhatt authored Jul 20, 2024
2 parents d1ef2b0 + fae5344 commit 09d7dc6
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 62 deletions.
58 changes: 52 additions & 6 deletions src/safeposix/syscalls/sys_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,16 +409,50 @@ impl Cage {
0
}

/// ### Description
///
/// The exec system call replaces the current Cage object image with a new
/// Cage object and exec is called immediately after a process(Cage) forks.
/// For our purposes this translates to removing the parent cage object
/// from the cagetable and adding the child object to it. We also close
/// any file descriptors that the parent object holds if the `O_CLOEX`
/// flag has been set on that file descriptor
///
/// ### Arguments
///
/// `child_cageid`: uid of the new child Cage object
///
/// ### Returns
///
/// Returns 0 upon successfully update the current running image
///
/// ### Errors
///
/// This syscall doesn't directly have any cases where it returns an error
///
/// ### Panics
///
/// This function doesn't directly panic - but the unmap memory mappings
/// function panics if it cannot create an shm entry or if the unwrapping
/// on the file descriptor fails due to an invalid fd
///
/// For more information please refer to - [https://man7.org/linux/man-pages/man3/exec.3.html]
pub fn exec_syscall(&self, child_cageid: u64) -> i32 {
// We remove the current running process from the cagetable
interface::cagetable_remove(self.cageid);

// Function call to unmap shared memory mappings of the current process
self.unmap_shm_mappings();

// Initialize an empty vector to hold file descriptors
let mut cloexecvec = vec![];
for fd in 0..MAXFD {
// Get mutex of the file descriptor
let checkedfd = self.get_filedescriptor(fd).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
// The O_CLOEXEC flag determines whether the fd should be closed upon calling
// exec or not
if match filedesc_enum {
File(f) => f.flags & O_CLOEXEC,
Stream(s) => s.flags & O_CLOEXEC,
Expand All @@ -427,21 +461,30 @@ impl Cage {
Epoll(p) => p.flags & O_CLOEXEC,
} != 0
{
// If the flag is set - we add the fd to our vector
cloexecvec.push(fd);
}
}
}

//For each fd in our close vector list
//We call the close_syscall which takes in a file decsriptor
//and closes it
for fdnum in cloexecvec {
self.close_syscall(fdnum);
}

// we grab the parent cages main threads sigset and store it at 0
// this way the child can initialize the sigset properly when it establishes its
// own mainthreadid
// We clone the parent cage's main threads and store them at index 0
// This is done since there isn't a thread established for the child Cage object
// yet - And there is no threadId to store it at.
// The child Cage object can then initialize and store the sigset appropriately
// when it establishes its own main thread id.
// A sigset is a data structure that keeps track of which signals are affected by the process
let newsigset = interface::RustHashMap::new();
if !interface::RUSTPOSIX_TESTSUITE.load(interface::RustAtomicOrdering::Relaxed) {
// we don't add these for the test suite
// When rustposix runs independently (not as Lind paired with NaCL runtime) we
// do not handle signals The test suite runs rustposix independently
// and hence we do not handle signals for the test suite
let mainsigsetatomic = self
.sigset
.get(
Expand All @@ -456,6 +499,9 @@ impl Cage {
newsigset.insert(0, mainsigset);
}

// Initialize a new cage object to replace the current running image
// We set all the ids to -1 to indicate the loading phase
// We clone the fd table with the memories unmapped
let newcage = Cage {
cageid: child_cageid,
cwd: interface::RustLock::new(self.cwd.read().clone()),
Expand All @@ -477,8 +523,8 @@ impl Cage {
main_threadid: interface::RustAtomicU64::new(0),
interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid),
};
//wasteful clone of fdtable, but mutability constraints exist

// Insert new cage with updated fd tables to be inserted in the cagetable
interface::cagetable_insert(child_cageid, newcage);
0
}
Expand Down
1 change: 1 addition & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
mod fs_tests;
mod ipc_tests;
mod networking_tests;
mod sys_tests;
use rand::Rng;
use std::net::{TcpListener, UdpSocket};

Expand Down
146 changes: 90 additions & 56 deletions src/tests/sys_tests.rs
Original file line number Diff line number Diff line change
@@ -1,105 +1,139 @@
#![allow(dead_code)] //suppress warning for these functions not being used in targets other than the tests
#![allow(dead_code)] //suppress warning for these functions not being used in targets other than the
// tests

#[allow(unused_parens)]
#[cfg(test)]
pub mod test_sys {
#[cfg(test)]
pub mod sys_tests {
use super::super::*;
use crate::interface;
use crate::safeposix::syscalls::sys_calls::*;

pub fn test_sys() {
ut_lind_getpid();
ut_lind_getppid();
ut_lind_getegid();
ut_lind_getuid();
ut_lind_geteuid();
ut_lind_getgid();
ut_lind_fork();
}
use crate::safeposix::cage::{FileDescriptor::*, *};
use crate::safeposix::{cage::*, dispatcher::*, filesystem};

#[test]
pub fn ut_lind_getpid() {
lindrustinit(0);
let cage = interface::cagetable_getref(1);
assert_eq!(cage.getpid_syscall(),1);
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
assert_eq!(cage.getpid_syscall(), 1);
lindrustfinalize();
}
}

#[test]
pub fn ut_lind_getppid() {
lindrustinit(0);
let cage = interface::cagetable_getref(1);
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
cage.fork_syscall(2);
let cage2 = interface::cagetable_getref(2);
assert_eq!(cage2.getppid_syscall(),1);
lindrustfinalize();

}
assert_eq!(cage2.getppid_syscall(), 1);
lindrustfinalize();
}

#[test]
pub fn ut_lind_getuid() {
lindrustinit(0);
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
// The first call to geteuid always returns -1
assert_eq!(cage.getuid_syscall(),-1);
assert_eq!(cage.getuid_syscall(), -1);
// Subsequent calls return the default value
assert_eq!(cage.getuid_syscall(),DEFAULT_UID);
assert_eq!(cage.getuid_syscall(), DEFAULT_UID as i32);
lindrustfinalize()
}

#[test]
pub fn ut_lind_geteuid() {
lindrustinit(0);
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
// The first call to geteuid always returns -1
assert_eq!(cage.geteuid_syscall(),-1);
assert_eq!(cage.geteuid_syscall(), -1);
// Subsequent calls return the default value
assert_eq!(cage.geteuid_syscall(),DEFAULT_UID);
assert_eq!(cage.geteuid_syscall(), DEFAULT_UID as i32);
lindrustfinalize()
}

#[test]
pub fn ut_lind_getgid() {
lindrustinit(0);
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
// The first call to geteuid always returns -1
assert_eq!(cage.getgid_syscall(),-1);
assert_eq!(cage.getgid_syscall(), -1);
// Subsequent calls return the default value
assert_eq!(cage.getgid_syscall(),DEFAULT_GID);
assert_eq!(cage.getgid_syscall(), DEFAULT_GID as i32);
lindrustfinalize()
}
}

#[test]
pub fn ut_lind_getegid() {
lindrustinit(0);
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
// The first call to geteuid always returns -1
assert_eq!(cage.getegid_syscall(),-1);
assert_eq!(cage.getegid_syscall(), -1);
// Subsequent calls return the default value
assert_eq!(cage.getegid_syscall(),DEFAULT_GID);
assert_eq!(cage.getegid_syscall(), DEFAULT_GID as i32);
lindrustfinalize()
}
}

#[test]
pub fn ut_lind_fork() {
// Since the fork syscall is heavily tested in relation to other syscalls
// we only perform simple checks for testing the sanity of the fork syscall
lindrustinit(0);
let cage = interface::cagetable_getref(1);
// Spawn a new child object using the fork syscall
cage.fork_syscall(2);
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
// Spawn a new child object using the fork syscall
cage.fork_syscall(2);
// Search for the new cage object with cage_id = 2
let child_cage = interface::cagetable_getref(2);
let child_cage = interface::cagetable_getref(2);
// Assert the parent value is the the id of the first cage object
assert_eq!(child_cage.getpid_syscall(),1);
// Assert that the cage id of the child is the value passed in the original fork syscall
assert_eq!(child_cage.getuid(),2);
// Assert that the cwd is the same as the parent cage object
assert_eq!(child_cage.cwd.read(),cage.cwd.read())
assert_eq!(child_cage.getppid_syscall(), 1);
// Assert that the cage id of the child is the value passed in the original fork
// syscall
assert_eq!(child_cage.getuid_syscall(), -1);
assert_eq!(child_cage.getuid_syscall(), DEFAULT_UID as i32);
lindrustfinalize();
}

#[test]
pub fn ut_lind_exit() {
// Since exit function is heavily used and tested in other syscalls and their tests
// We only perform preliminary checks for checking the sanity of this syscall
// We don't check for cases such as exiting a cage twice - since the exiting process
// is handled by the NaCl runtime - and it ensures that a cage does not exit twice
lindrustinit(0);
// Since exit function is heavily used and tested in other syscalls and their
// tests We only perform preliminary checks for checking the sanity of
// this syscall We don't check for cases such as exiting a cage twice -
// since the exiting process is handled by the NaCl runtime - and it
// ensures that a cage does not exit twice acquiring a lock on TESTMUTEX
// prevents other tests from running concurrently, and also performs
// clean env setup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);
// Call the exit call
assert_eq(cage.exit_syscall(EXIT_SUCCESS),EXIT_SUCCESS);
lindrustfinalize();
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
lindrustfinalize();
}
}

#[test]
pub fn ut_lind_exec() {
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
// and also performs clean env setup
let _thelock = setup::lock_and_init();
let cage1 = interface::cagetable_getref(1);
// Spawn a new child
cage1.fork_syscall(2);
// Assert that the fork was correct
let child_cage = interface::cagetable_getref(2);
assert_eq!(child_cage.getuid_syscall(), -1);
assert_eq!(child_cage.getuid_syscall(), DEFAULT_UID as i32);
// Spawn exec and check if it returns 0
assert_eq!(cage1.exec_syscall(2), 0);
lindrustfinalize();
}
}

0 comments on commit 09d7dc6

Please sign in to comment.