Skip to content

Commit

Permalink
Implement clone3
Browse files Browse the repository at this point in the history
Currently uses `clone` internally.

Progress on shadow#1987
  • Loading branch information
sporksmith committed May 11, 2023
1 parent c8c9268 commit 0dad119
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ See [supported platforms](supported_platforms.md).
* Fixed a bug causing `host_options` to undo any changes made to
`host_option_defaults`.

* Implemented the `clone3` syscall. Thread libraries we're aware of that use
`clone3` were gracefully falling back to `clone`, but eventually they may not do so.
This also reduces noise in shadow's log about an unimplemented syscall being attempted.

MAJOR changes (breaking):

* Removed deprecated python scripts that only worked on Shadow 1.x config files
Expand Down
87 changes: 76 additions & 11 deletions src/main/host/syscall/handler/clone.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use log::warn;
use log::{debug, trace, warn};
use nix::errno::Errno;
use shadow_shim_helper_rs::syscall_types::ForeignPtr;
use syscall_logger::log_syscall;
Expand Down Expand Up @@ -48,16 +48,7 @@ bitflags::bitflags! {
}

impl SyscallHandler {
// Note that the syscall args are different than the libc wrapper.
// See "C library/kernel differences" in clone(2).
#[log_syscall(
/* rv */libc::pid_t,
/* flags */i32,
/* child_stack */*const libc::c_void,
/* ptid */*const libc::pid_t,
/* ctid */*const libc::pid_t,
/* newtls */*const libc::c_void)]
pub fn clone(
fn clone_internal(
ctx: &mut SyscallContext,
flags_and_exit_signal: i32,
child_stack: ForeignPtr<()>,
Expand Down Expand Up @@ -129,6 +120,80 @@ impl SyscallHandler {

Ok(libc::pid_t::from(child_tid))
}
// Note that the syscall args are different than the libc wrapper.
// See "C library/kernel differences" in clone(2).
#[log_syscall(
/* rv */libc::pid_t,
/* flags */i32,
/* child_stack */*const libc::c_void,
/* ptid */*const libc::pid_t,
/* ctid */*const libc::pid_t,
/* newtls */*const libc::c_void)]
pub fn clone(
ctx: &mut SyscallContext,
flags_and_exit_signal: i32,
child_stack: ForeignPtr<()>,
ptid: ForeignPtr<libc::pid_t>,
ctid: ForeignPtr<libc::pid_t>,
newtls: u64,
) -> Result<libc::pid_t, SyscallError> {
Self::clone_internal(ctx, flags_and_exit_signal, child_stack, ptid, ctid, newtls)
}

#[log_syscall(
/* rv */libc::pid_t,
/* args*/*const libc::c_void,
/* args_size*/usize)]
pub fn clone3(
ctx: &mut SyscallContext,
args: ForeignPtr<libc::clone_args>,
args_size: usize,
) -> Result<libc::pid_t, SyscallError> {
if args_size != std::mem::size_of::<libc::clone_args>() {
// TODO: allow smaller size, and be careful to only read
// as much as the caller specified, and zero-fill the rest.
return Err(Errno::EINVAL.into());
}
let args = ctx.objs.process.memory_borrow().read(args)?;
trace!("clone3 args: {args:?}");
let Ok(flags) = i32::try_from(args.flags) else {
debug!("Couldn't safely truncate flags to 32 bits: {} ({:?})", args.flags,
CloneFlags::from_bits(args.flags));
return Err(Errno::EINVAL.into());
};
if flags & 0xff != 0 {
// We can't multiplex through `clone` in this case, since these bits
// conflict with the exit signal. Currently this won't happen in practice
// because there are no legal flags that use these bits. It's possible
// that clone3-flags could be added here, but more likely they'll use
// the higher bits first. (clone3 uses 64 bits vs clone's 32).
debug!(
"clone3 got a flag it can't pass through to clone: {} ({:?})",
flags & 0xff,
CloneFlags::from_bits(args.flags & 0xff)
);
return Err(Errno::EINVAL.into());
}
let Ok(exit_signal) = i32::try_from(args.exit_signal) else {
// Couldn't truncate to the 32 bits allowed by `clone`, but
// there also aren't any valid signal numbers that need that many bits.
debug!("Bad signal number: {}", args.exit_signal);
return Err(Errno::EINVAL.into());
};
if exit_signal & !0xff != 0 {
// Couldn't fit into the 8 bits allowed for the signal number by `clone`,
// but there also aren't any valid signal numbers that need that many bits.
return Err(Errno::EINVAL.into());
}
Self::clone_internal(
ctx,
flags | exit_signal,
ForeignPtr::<()>::from(args.stack + args.stack_size),
ForeignPtr::<libc::pid_t>::from_raw_ptr(args.parent_tid as *mut libc::pid_t),
ForeignPtr::<libc::pid_t>::from_raw_ptr(args.child_tid as *mut libc::pid_t),
args.tls,
)
}

#[log_syscall(/* rv */libc::pid_t)]
pub fn gettid(ctx: &mut SyscallContext) -> Result<libc::pid_t, SyscallError> {
Expand Down
1 change: 1 addition & 0 deletions src/main/host/syscall/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl SyscallHandler {
libc::SYS_bind => SyscallHandlerFn::call(Self::bind, &mut ctx),
libc::SYS_brk => SyscallHandlerFn::call(Self::brk, &mut ctx),
libc::SYS_clone => SyscallHandlerFn::call(Self::clone, &mut ctx),
libc::SYS_clone3 => SyscallHandlerFn::call(Self::clone3, &mut ctx),
libc::SYS_close => SyscallHandlerFn::call(Self::close, &mut ctx),
libc::SYS_connect => SyscallHandlerFn::call(Self::connect, &mut ctx),
libc::SYS_dup => SyscallHandlerFn::call(Self::dup, &mut ctx),
Expand Down
1 change: 1 addition & 0 deletions src/main/host/syscall_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ SyscallReturn syscallhandler_make_syscall(SysCallHandler* sys, const SysCallArgs
SHIM_ONLY(clock_gettime);
HANDLE_C(clock_nanosleep);
HANDLE_RUST(clone);
HANDLE_RUST(clone3);
HANDLE_RUST(close);
HANDLE_RUST(connect);
HANDLE_C(creat);
Expand Down
1 change: 1 addition & 0 deletions src/main/utility/pod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ unsafe impl Pod for libc::utimbuf {}
unsafe impl Pod for libc::utmpx {}
unsafe impl Pod for libc::utsname {}
unsafe impl Pod for libc::winsize {}
unsafe impl Pod for libc::clone_args {}

// shadow re-exports this definition from /usr/include/linux/tcp.h
unsafe impl Pod for crate::cshadow::tcp_info {}

0 comments on commit 0dad119

Please sign in to comment.