Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/RawPOSIX/src/interface/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ pub fn round_up_page(length: u64) -> u64 {
/// * `parent_vmmap` - vmmap struct of parent
/// * `child_vmmap` - vmmap struct of child
pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) {
let parent_base = parent_vmmap.base_address.unwrap();
let child_base = child_vmmap.base_address.unwrap();

// iterate through each vmmap entry
for (_interval, entry) in parent_vmmap.entries.iter() {
// translate page number to user address
Expand Down Expand Up @@ -633,6 +630,7 @@ pub fn brk_handler(cageid: u64, brk: u32) -> i32 {
}

// update vmmap entry
vmmap.remove_entry(0, old_brk_page);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we have to call remove here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I still remember correctly, add_entry_with_overwrite from vmmap does not automatically remove the old entries when the inserted new entries is overlapping with it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd comment that here then. Also worth checking that the comment for the function is clear about that wherever add_entry_with_overwrite lives

let _ = vmmap.add_entry_with_overwrite(
0,
brk_page,
Expand Down
28 changes: 17 additions & 11 deletions src/RawPOSIX/src/interface/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,25 @@ pub fn signal_get_handler(cageid: u64, signo: i32) -> u32 {

// send specified signal to the cage, return value indicates whether the cage exists
// thread safety: this function could possibly be invoked by multiple threads of the same cage
// NOTE: signo should be checked to make sure it's valid before passing to this function
pub fn lind_send_signal(cageid: u64, signo: i32) -> bool {
if let Some(cage) = cagetable_getref_opt(cageid) {
let mut pending_signals = cage.pending_signals.write();
// TODO: currently we are queuing the same signals instead of merging the same signal
// this is different from linux which always merge the same signal if they havn't been handled yet
// we queue the signals for now because our epoch based signal implementation could have much longer
// gap for signal checkings than linux. We need to finally decide whether do the queuing or merging
// in the future, probably based on some experimental data
pending_signals.push(signo);

// we only trigger epoch if the signal is not blocked
if !signal_check_block(cageid, signo) {
signal_epoch_trigger(cageid);
// From https://man7.org/linux/man-pages/man2/kill.2.html
// If sig is 0, then no signal is sent, but existence and permission
// checks are still performed
if signo > 0 {
let mut pending_signals = cage.pending_signals.write();
// TODO: currently we are queuing the same signals instead of merging the same signal
// this is different from linux which always merge the same signal if they havn't been handled yet
// we queue the signals for now because our epoch based signal implementation could have much longer
// gap for signal checkings than linux. We need to finally decide whether do the queuing or merging
// in the future, probably based on some experimental data
pending_signals.push(signo);

// we only trigger epoch if the signal is not blocked
if !signal_check_block(cageid, signo) {
signal_epoch_trigger(cageid);
}
}

true
Expand Down
27 changes: 20 additions & 7 deletions src/RawPOSIX/src/safeposix/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,8 @@ pub fn lind_syscall_api(
// Convert user space buffer address to physical address
let optval_ptr = translate_vmmap_addr(&cage, arg4).unwrap() as *mut i32;
let optval = unsafe { &mut *optval_ptr };
cage.getsockopt_syscall(virtual_fd, level, optname, optval)
let optlen = arg5 as u32;
cage.getsockopt_syscall(virtual_fd, level, optname, optval, optlen)
}

SOCKETPAIR_SYSCALL => {
Expand Down Expand Up @@ -1089,18 +1090,30 @@ pub fn lind_syscall_api(

WAIT_SYSCALL => {
let cage = interface::cagetable_getref(cageid);
// Convert user space buffer address to physical address
let status_addr = translate_vmmap_addr(&cage, arg1).unwrap() as u64;
let status = interface::get_i32_ref(status_addr).unwrap();
// status could possibly be NULL
let status = {
if arg1 == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does dennis's pr affect this?

None
} else {
let status_addr = translate_vmmap_addr(&cage, arg1).unwrap() as u64;
Some(interface::get_i32_ref(status_addr).unwrap())
}
};
cage.wait_syscall(status)
}

WAITPID_SYSCALL => {
let pid = arg1 as i32;
let cage = interface::cagetable_getref(cageid);
// Convert user space buffer address to physical address
let status_addr = translate_vmmap_addr(&cage, arg2).unwrap();
let status = interface::get_i32_ref(status_addr).unwrap();
// status could possibly be NULL
let status = {
if arg2 == 0 {
None
} else {
let status_addr = translate_vmmap_addr(&cage, arg2).unwrap() as u64;
Some(interface::get_i32_ref(status_addr).unwrap())
}
};
let options = arg3 as i32;

cage.waitpid_syscall(pid, status, options)
Expand Down
3 changes: 2 additions & 1 deletion src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1435,9 +1435,10 @@ impl Cage {
return syscall_error(Errno::EBADF, "getdents", "Bad File Descriptor");
}
let vfd = wrappedvfd.unwrap();
// calling getdents64 instead of getdents since glibc expects result from getdents64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this?

let ret = unsafe {
libc::syscall(
libc::SYS_getdents as c_long,
libc::SYS_getdents64 as c_long,
vfd.underfd as i32,
buf as *mut c_void,
nbytes,
Expand Down
1 change: 1 addition & 0 deletions src/RawPOSIX/src/safeposix/syscalls/net_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ impl Cage {
level: i32,
optname: i32,
optval: &mut i32,
optlen: u32,
) -> i32 {
let wrappedvfd = fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64);
if wrappedvfd.is_err() {
Expand Down
23 changes: 16 additions & 7 deletions src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl Cage {
* into the end of its parent's zombie list. Then when parent wants to wait for any of child, it could just check its
* zombie list and retrieve the first entry from it (first in, first out).
*/
pub fn waitpid_syscall(&self, cageid: i32, status: &mut i32, options: i32) -> i32 {
pub fn waitpid_syscall(&self, cageid: i32, status: Option<&mut i32>, options: i32) -> i32 {
let mut zombies = self.zombies.write();
let child_num = self.child_num.load(interface::RustAtomicOrdering::Relaxed);

Expand Down Expand Up @@ -311,13 +311,13 @@ impl Cage {
// reach here means we already found the desired exited child
let zombie = zombie_opt.unwrap();
// update the status
*status = zombie.exit_code;
let _ = status.map(|st| *st = zombie.exit_code);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im probably just too much of a newbie at rust, but why do we use map here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is equivalent to

if let Some(value) = status.as_mut() {
    *value = zombie.exit_code;
}

It has no meaningful difference in terms of performance. Though this approach (map method) is indeed more difficult for new people to understand. Do we have a perference to write rust code with simple form for new people to understand?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a rule of thumb writing code that's simpler to follow is the best option, though adding a comment here also achieves the same results. I just wasn't sure if using map like this would be clear to anyone with basic understanding of rust. I'd either change it or add a comment.


// return child's cageid
zombie.cageid as i32
}

pub fn wait_syscall(&self, status: &mut i32) -> i32 {
pub fn wait_syscall(&self, status: Option<&mut i32>) -> i32 {
self.waitpid_syscall(0, status, 0)
}

Expand All @@ -336,15 +336,15 @@ impl Cage {
if self.getgid.load(interface::RustAtomicOrdering::Relaxed) == -1 {
self.getgid
.store(DEFAULT_GID as i32, interface::RustAtomicOrdering::Relaxed);
return -1;
return DEFAULT_GID as i32;
}
DEFAULT_GID as i32 //Lind is only run in one group so a default value is returned
}
pub fn getegid_syscall(&self) -> i32 {
if self.getegid.load(interface::RustAtomicOrdering::Relaxed) == -1 {
self.getegid
.store(DEFAULT_GID as i32, interface::RustAtomicOrdering::Relaxed);
return -1;
return DEFAULT_GID as i32;
}
DEFAULT_GID as i32 //Lind is only run in one group so a default value is returned
}
Expand All @@ -353,15 +353,15 @@ impl Cage {
if self.getuid.load(interface::RustAtomicOrdering::Relaxed) == -1 {
self.getuid
.store(DEFAULT_UID as i32, interface::RustAtomicOrdering::Relaxed);
return -1;
return DEFAULT_UID as i32;
}
DEFAULT_UID as i32 //Lind is only run as one user so a default value is returned
}
pub fn geteuid_syscall(&self) -> i32 {
if self.geteuid.load(interface::RustAtomicOrdering::Relaxed) == -1 {
self.geteuid
.store(DEFAULT_UID as i32, interface::RustAtomicOrdering::Relaxed);
return -1;
return DEFAULT_UID as i32;
}
DEFAULT_UID as i32 //Lind is only run as one user so a default value is returned
}
Expand Down Expand Up @@ -407,6 +407,15 @@ impl Cage {
return syscall_error(Errno::EINVAL, "sigkill", "Invalid signal number");
}

// if cage id is 0, send signal to itself
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we expand this comment a bit?

I think from the manpage: If pid equals 0, then sig is sent to every process in the process
group of the calling process.

we should just explain that we dont have process groups so it just sends to itself if thats correct?

let cage_id = {
if cage_id == 0 {
self.cageid
} else {
cage_id as u64
}
};

if !lind_send_signal(cage_id as u64, sig) {
return syscall_error(Errno::ESRCH, "kill", "Target cage does not exist");
}
Expand Down