Support modifying processes' sigactions.
This is, other than vfork, the last piece of functionality that the previous clone() offered (CLONE_SIGHAND) which previously was not implemented.
This commit is contained in:
@@ -368,14 +368,7 @@ impl Context {
|
||||
name: Arc::new(RwLock::new(String::new().into_boxed_str())),
|
||||
cwd: Arc::new(RwLock::new(String::new())),
|
||||
files: Arc::new(RwLock::new(Vec::new())),
|
||||
actions: Arc::new(RwLock::new(vec![(
|
||||
SigAction {
|
||||
sa_handler: unsafe { mem::transmute(SIG_DFL) },
|
||||
sa_mask: [0; 2],
|
||||
sa_flags: SigActionFlags::empty(),
|
||||
},
|
||||
0
|
||||
); 128])),
|
||||
actions: Self::empty_actions(),
|
||||
regs: None,
|
||||
ptrace_stop: false,
|
||||
sigstack: None,
|
||||
@@ -562,4 +555,14 @@ impl Context {
|
||||
|
||||
self.addr_space.replace(addr_space)
|
||||
}
|
||||
pub fn empty_actions() -> Arc<RwLock<Vec<(SigAction, usize)>>> {
|
||||
Arc::new(RwLock::new(vec![(
|
||||
SigAction {
|
||||
sa_handler: unsafe { mem::transmute(SIG_DFL) },
|
||||
sa_mask: [0; 2],
|
||||
sa_flags: SigActionFlags::empty(),
|
||||
},
|
||||
0
|
||||
); 128]))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,4 +303,7 @@ pub trait KernelScheme: Scheme + Send + Sync + 'static {
|
||||
fn as_addrspace(&self, number: usize) -> Result<Arc<RwLock<AddrSpace>>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn as_sigactions(&self, number: usize) -> Result<Arc<RwLock<Vec<(crate::syscall::data::SigAction, usize)>>>> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{
|
||||
FloatRegisters,
|
||||
IntRegisters,
|
||||
EnvRegisters,
|
||||
data::{Map, PtraceEvent, Stat},
|
||||
data::{Map, PtraceEvent, SigAction, Stat},
|
||||
error::*,
|
||||
flag::*,
|
||||
scheme::{calc_seek_offset_usize, Scheme},
|
||||
@@ -141,6 +141,10 @@ enum Operation {
|
||||
// TODO: Remove this once cross-scheme links are merged. That would allow acquiring a new
|
||||
// FD to access the file descriptor behind grants.
|
||||
GrantHandle { description: Arc<RwLock<FileDescription>> },
|
||||
|
||||
Sigactions(Arc<RwLock<Vec<(SigAction, usize)>>>),
|
||||
CurrentSigactions,
|
||||
AwaitingSigactionsChange(Arc<RwLock<Vec<(SigAction, usize)>>>),
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Attr {
|
||||
@@ -150,7 +154,7 @@ enum Attr {
|
||||
}
|
||||
impl Operation {
|
||||
fn needs_child_process(&self) -> bool {
|
||||
matches!(self, Self::Memory { .. } | Self::Regs(_) | Self::Trace | Self::Filetable { .. } | Self::AddrSpace { .. } | Self::CurrentAddrSpace | Self::CurrentFiletable)
|
||||
matches!(self, Self::Memory { .. } | Self::Regs(_) | Self::Trace | Self::Filetable { .. } | Self::AddrSpace { .. } | Self::CurrentAddrSpace | Self::CurrentFiletable | Self::Sigactions(_) | Self::CurrentSigactions | Self::AwaitingSigactionsChange(_))
|
||||
}
|
||||
fn needs_root(&self) -> bool {
|
||||
matches!(self, Self::Attr(_))
|
||||
@@ -286,7 +290,7 @@ impl ProcScheme {
|
||||
let operation = match operation_str {
|
||||
Some("mem") => Operation::Memory { addrspace: current_addrspace()? },
|
||||
Some("addrspace") => Operation::AddrSpace { addrspace: current_addrspace()? },
|
||||
Some("filetable") => Operation::Filetable { filetable: Arc::clone(&context::contexts().current().ok_or(Error::new(ESRCH))?.read().files) },
|
||||
Some("filetable") => Operation::Filetable { filetable: Arc::clone(&context::current()?.read().files) },
|
||||
Some("current-addrspace") => Operation::CurrentAddrSpace,
|
||||
Some("current-filetable") => Operation::CurrentFiletable,
|
||||
Some("regs/float") => Operation::Regs(RegsKind::Float),
|
||||
@@ -300,6 +304,8 @@ impl ProcScheme {
|
||||
Some("uid") => Operation::Attr(Attr::Uid),
|
||||
Some("gid") => Operation::Attr(Attr::Gid),
|
||||
Some("open_via_dup") => Operation::OpenViaDup,
|
||||
Some("sigactions") => Operation::Sigactions(Arc::clone(&context::current()?.read().actions)),
|
||||
Some("current-sigactions") => Operation::CurrentSigactions,
|
||||
_ => return Err(Error::new(EINVAL))
|
||||
};
|
||||
|
||||
@@ -420,6 +426,15 @@ impl Scheme for ProcScheme {
|
||||
handle.info.clone()
|
||||
};
|
||||
|
||||
let handle = |operation, data| Handle {
|
||||
info: Info {
|
||||
flags: 0,
|
||||
pid: info.pid,
|
||||
operation,
|
||||
},
|
||||
data,
|
||||
};
|
||||
|
||||
self.new_handle(match info.operation {
|
||||
Operation::OpenViaDup => {
|
||||
let (uid, gid) = match &*context::contexts().current().ok_or(Error::new(ESRCH))?.read() {
|
||||
@@ -428,7 +443,7 @@ impl Scheme for ProcScheme {
|
||||
return self.open_inner(info.pid, Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?).filter(|s| !s.is_empty()), O_RDWR | O_CLOEXEC, uid, gid);
|
||||
},
|
||||
|
||||
Operation::Filetable { filetable } => {
|
||||
Operation::Filetable { ref filetable } => {
|
||||
// TODO: Maybe allow userspace to either copy or transfer recently dupped file
|
||||
// descriptors between file tables.
|
||||
if buf != b"copy" {
|
||||
@@ -436,16 +451,9 @@ impl Scheme for ProcScheme {
|
||||
}
|
||||
let new_filetable = Arc::try_new(RwLock::new(filetable.read().clone())).map_err(|_| Error::new(ENOMEM))?;
|
||||
|
||||
Handle {
|
||||
info: Info {
|
||||
flags: 0,
|
||||
pid: info.pid,
|
||||
operation: Operation::Filetable { filetable: new_filetable },
|
||||
},
|
||||
data: OperationData::Other,
|
||||
}
|
||||
handle(Operation::Filetable { filetable: new_filetable }, OperationData::Other)
|
||||
}
|
||||
Operation::AddrSpace { addrspace } => {
|
||||
Operation::AddrSpace { ref addrspace } => {
|
||||
let (operation, is_mem) = match buf {
|
||||
// TODO: Better way to obtain new empty address spaces, perhaps using SYS_OPEN. But
|
||||
// in that case, what scheme?
|
||||
@@ -462,14 +470,16 @@ impl Scheme for ProcScheme {
|
||||
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
Handle {
|
||||
info: Info {
|
||||
flags: 0,
|
||||
pid: info.pid,
|
||||
operation,
|
||||
},
|
||||
data: if is_mem { OperationData::Memory(MemData { offset: VirtualAddress::new(0) }) } else { OperationData::Offset(0) },
|
||||
}
|
||||
|
||||
handle(operation, if is_mem { OperationData::Memory(MemData { offset: VirtualAddress::new(0) }) } else { OperationData::Offset(0) })
|
||||
}
|
||||
Operation::Sigactions(ref sigactions) => {
|
||||
let new = match buf {
|
||||
b"empty" => Context::empty_actions(),
|
||||
b"copy" => Arc::new(RwLock::new(sigactions.read().clone())),
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
handle(Operation::Sigactions(new), OperationData::Other)
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
})
|
||||
@@ -991,6 +1001,7 @@ impl Scheme for ProcScheme {
|
||||
Ok(buf.len())
|
||||
}
|
||||
Operation::Filetable { .. } => return Err(Error::new(EBADF)),
|
||||
|
||||
Operation::CurrentFiletable => {
|
||||
let filetable_fd = usize::from_ne_bytes(<[u8; mem::size_of::<usize>()]>::try_from(buf).map_err(|_| Error::new(EINVAL))?);
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(filetable_fd)?;
|
||||
@@ -1014,6 +1025,13 @@ impl Scheme for ProcScheme {
|
||||
|
||||
Ok(3 * mem::size_of::<usize>())
|
||||
}
|
||||
Operation::CurrentSigactions => {
|
||||
let sigactions_fd = usize::from_ne_bytes(<[u8; mem::size_of::<usize>()]>::try_from(buf).map_err(|_| Error::new(EINVAL))?);
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(sigactions_fd)?;
|
||||
let sigactions = hopefully_this_scheme.as_sigactions(number)?;
|
||||
self.handles.write().get_mut(&id).ok_or(Error::new(EBADF))?.info.operation = Operation::AwaitingSigactionsChange(sigactions);
|
||||
Ok(mem::size_of::<usize>())
|
||||
}
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
@@ -1059,8 +1077,10 @@ impl Scheme for ProcScheme {
|
||||
Operation::Attr(Attr::Gid) => "gid",
|
||||
Operation::Filetable { .. } => "filetable",
|
||||
Operation::AddrSpace { .. } => "addrspace",
|
||||
Operation::Sigactions(_) => "sigactions",
|
||||
Operation::CurrentAddrSpace => "current-addrspace",
|
||||
Operation::CurrentFiletable => "current-filetable",
|
||||
Operation::CurrentSigactions => "current-sigactions",
|
||||
Operation::OpenViaDup => "open-via-dup",
|
||||
|
||||
_ => return Err(Error::new(EOPNOTSUPP)),
|
||||
@@ -1124,6 +1144,10 @@ impl Scheme for ProcScheme {
|
||||
context.files = new;
|
||||
Ok(())
|
||||
})?,
|
||||
Operation::AwaitingSigactionsChange(new) => with_context_mut(handle.info.pid, |context: &mut Context| {
|
||||
context.actions = new;
|
||||
Ok(())
|
||||
})?,
|
||||
Operation::Trace => {
|
||||
ptrace::close_session(handle.info.pid);
|
||||
|
||||
@@ -1171,6 +1195,13 @@ impl KernelScheme for ProcScheme {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
fn as_sigactions(&self, number: usize) -> Result<Arc<RwLock<Vec<(crate::syscall::data::SigAction, usize)>>>> {
|
||||
if let Operation::Sigactions(ref sigactions) = self.handles.read().get(&number).ok_or(Error::new(EBADF))?.info.operation {
|
||||
Ok(Arc::clone(sigactions))
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
}
|
||||
extern "C" fn clone_handler() {
|
||||
let context_lock = Arc::clone(context::contexts().current().expect("expected the current context to be set in a spawn closure"));
|
||||
|
||||
@@ -65,11 +65,7 @@ pub fn exit(status: usize) -> ! {
|
||||
ptrace::breakpoint_callback(PTRACE_STOP_EXIT, Some(ptrace_event!(PTRACE_STOP_EXIT, status)));
|
||||
|
||||
{
|
||||
let context_lock = {
|
||||
let contexts = context::contexts();
|
||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exit failed to find context");
|
||||
Arc::clone(&context_lock)
|
||||
};
|
||||
let context_lock = context::current().expect("exit failed to find context");
|
||||
|
||||
let mut close_files;
|
||||
let pid = {
|
||||
|
||||
Reference in New Issue
Block a user