shadow_rs/host/syscall/handler/
clone.rs1use linux_api::capability::{LINUX_CAPABILITY_VERSION_3, user_cap_data, user_cap_header};
2use linux_api::errno::Errno;
3use linux_api::posix_types::kernel_pid_t;
4use linux_api::sched::CloneFlags;
5use linux_api::signal::Signal;
6use log::{debug, trace, warn};
7use shadow_shim_helper_rs::explicit_drop::ExplicitDropper;
8use shadow_shim_helper_rs::rootedcell::rc::RootedRc;
9use shadow_shim_helper_rs::rootedcell::refcell::RootedRefCell;
10use shadow_shim_helper_rs::syscall_types::ForeignPtr;
11
12use crate::host::descriptor::DropPosixRecordLocks;
13use crate::host::descriptor::descriptor_table::DescriptorTable;
14use crate::host::process::ProcessId;
15use crate::host::thread::Thread;
16
17use super::{SyscallContext, SyscallHandler};
18
19impl SyscallHandler {
20 fn clone_internal(
21 ctx: &mut SyscallContext,
22 flags: CloneFlags,
23 exit_signal: Option<Signal>,
24 child_stack: ForeignPtr<()>,
25 ptid: ForeignPtr<kernel_pid_t>,
26 ctid: ForeignPtr<kernel_pid_t>,
27 newtls: u64,
28 ) -> Result<kernel_pid_t, Errno> {
29 trace!(
30 "flags:{flags:?} exit_signal:{exit_signal:?} child_stack:{child_stack:?} ptid:{ptid:?} ctid:{ctid:?} newtls:{newtls:?}"
31 );
32 let mut handled_flags = CloneFlags::empty();
35
36 let mut native_flags = CloneFlags::empty();
38
39 let native_ctid = ForeignPtr::<kernel_pid_t>::null();
42 let native_ptid = ForeignPtr::<kernel_pid_t>::null();
43
44 let native_child_stack = child_stack;
46
47 let native_newtls = newtls;
49
50 if flags.contains(CloneFlags::CLONE_THREAD) {
51 if !flags.contains(CloneFlags::CLONE_SIGHAND) {
55 debug!("Missing CLONE_SIGHAND");
56 return Err(Errno::EINVAL);
57 }
58 if !flags.contains(CloneFlags::CLONE_SETTLS) {
59 warn!("CLONE_THREAD without CLONE_TLS not supported by shadow");
61 return Err(Errno::ENOTSUP);
62 }
63 if exit_signal.is_some() {
64 warn!("Exit signal is unimplemented");
65 return Err(Errno::ENOTSUP);
66 }
67 native_flags.insert(CloneFlags::CLONE_THREAD);
70 native_flags.insert(CloneFlags::CLONE_SIGHAND);
72 native_flags.insert(CloneFlags::CLONE_FS);
74 native_flags.insert(CloneFlags::CLONE_FILES);
76 native_flags.insert(CloneFlags::CLONE_SYSVSEM);
78
79 handled_flags.insert(CloneFlags::CLONE_THREAD);
80 } else {
81 if ctx.objs.process.memory_borrow().has_mapper() {
82 warn!("Fork with memory mapper unimplemented");
83 return Err(Errno::ENOTSUP);
84 }
85 native_flags.insert(CloneFlags::CLONE_PARENT);
87 }
88
89 if flags.contains(CloneFlags::CLONE_SIGHAND) {
90 if !flags.contains(CloneFlags::CLONE_VM) {
94 debug!("Missing CLONE_VM");
95 return Err(Errno::EINVAL);
96 }
97 handled_flags.insert(CloneFlags::CLONE_SIGHAND);
100 }
101
102 if flags.contains(CloneFlags::CLONE_FS) {
103 handled_flags.insert(CloneFlags::CLONE_FS);
106 }
107
108 let desc_table = if flags.contains(CloneFlags::CLONE_FILES) {
109 RootedRc::clone(ctx.objs.thread.descriptor_table(), ctx.objs.host.root())
111 } else {
112 let root = ctx.objs.host.root();
114 let table: DescriptorTable = ctx
115 .objs
116 .thread
117 .descriptor_table_borrow(ctx.objs.host)
118 .clone();
119 RootedRc::new(root, RootedRefCell::new(root, table))
120 };
121 let desc_table = ExplicitDropper::new(desc_table, |desc_table| {
122 let d = DropPosixRecordLocks::False;
126 desc_table.explicit_drop_recursive(ctx.objs.host.root(), (ctx.objs.host, d));
127 });
128 handled_flags.insert(CloneFlags::CLONE_FILES);
129
130 if flags.contains(CloneFlags::CLONE_SETTLS) {
131 native_flags.insert(CloneFlags::CLONE_SETTLS);
132 handled_flags.insert(CloneFlags::CLONE_SETTLS);
133 }
134
135 if flags.contains(CloneFlags::CLONE_VFORK) {
136 warn_once_then_debug!(
144 "Ignoring CLONE_VFORK (and CLONE_VM if set). In *typical* usage this won't \
145 result in incorrect behavior."
146 );
147 handled_flags.insert(CloneFlags::CLONE_VFORK);
148 }
149
150 if flags.contains(CloneFlags::CLONE_VM) {
151 if flags.contains(CloneFlags::CLONE_THREAD) {
152 native_flags.insert(CloneFlags::CLONE_VM);
153 } else if flags.contains(CloneFlags::CLONE_VFORK) {
154 } else {
156 warn!("CLONE_VM without CLONE_THREAD and without CLONE_VFORK unsupported");
163 return Err(Errno::ENOTSUP);
164 }
165 handled_flags.insert(CloneFlags::CLONE_VM);
166 }
167
168 if flags.contains(CloneFlags::CLONE_SYSVSEM) {
169 handled_flags.insert(CloneFlags::CLONE_SYSVSEM);
171 }
172
173 let do_parent_settid = flags.contains(CloneFlags::CLONE_PARENT_SETTID);
175 handled_flags.insert(CloneFlags::CLONE_PARENT_SETTID);
176
177 let do_child_settid = flags.contains(CloneFlags::CLONE_CHILD_SETTID);
179 handled_flags.insert(CloneFlags::CLONE_CHILD_SETTID);
180
181 let do_child_cleartid = flags.contains(CloneFlags::CLONE_CHILD_CLEARTID);
183 handled_flags.insert(CloneFlags::CLONE_CHILD_CLEARTID);
184
185 let do_copy_sighandlers = if flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) {
186 if flags.contains(CloneFlags::CLONE_SIGHAND) {
189 return Err(Errno::EINVAL);
190 }
191 false
192 } else {
193 !flags.contains(CloneFlags::CLONE_SIGHAND)
195 };
196 handled_flags.insert(CloneFlags::CLONE_CLEAR_SIGHAND);
197
198 if flags.contains(CloneFlags::CLONE_PARENT) {
199 handled_flags.insert(CloneFlags::CLONE_PARENT);
202 }
203
204 let unhandled_flags = flags.difference(handled_flags);
205 if !unhandled_flags.is_empty() {
206 warn!("Unhandled clone flags: {unhandled_flags:?}");
207 return Err(Errno::ENOTSUP);
208 }
209
210 let child_mthread = ctx.objs.thread.mthread().native_clone(
211 ctx.objs,
212 native_flags,
213 native_child_stack,
214 native_ptid,
215 native_ctid,
216 native_newtls,
217 )?;
218
219 let child_tid = ctx.objs.host.get_new_thread_id();
220 let child_pid = if flags.contains(CloneFlags::CLONE_THREAD) {
221 ctx.objs.process.id()
222 } else {
223 ProcessId::from(child_tid)
224 };
225
226 let child_thread = Thread::wrap_mthread(
227 ctx.objs.host,
228 child_mthread,
229 desc_table.into_value(),
230 child_pid,
231 child_tid,
232 );
233
234 let childrc = ExplicitDropper::new(
235 RootedRc::new(
236 ctx.objs.host.root(),
237 RootedRefCell::new(ctx.objs.host.root(), child_thread),
238 ),
239 |childrc| {
240 childrc.explicit_drop_recursive(ctx.objs.host.root(), ctx.objs.host);
241 },
242 );
243
244 let child_process_rc;
245 let child_process_borrow;
246 let child_process;
247 if flags.contains(CloneFlags::CLONE_THREAD) {
248 child_process_borrow = None;
249 child_process = ctx.objs.process;
250 ctx.objs
251 .process
252 .add_thread(ctx.objs.host, childrc.into_value());
253 } else {
254 let process = ctx
255 .objs
256 .process
257 .borrow_as_runnable()
258 .unwrap()
259 .new_forked_process(ctx.objs.host, flags, exit_signal, childrc.into_value());
260 child_process_rc = Some(ExplicitDropper::new(
261 process.clone(ctx.objs.host.root()),
262 |x| {
263 x.explicit_drop_recursive(ctx.objs.host.root(), ctx.objs.host);
264 },
265 ));
266 child_process_borrow = Some(
267 child_process_rc
268 .as_ref()
269 .unwrap()
270 .borrow(ctx.objs.host.root()),
271 );
272 child_process = child_process_borrow.as_ref().unwrap();
273 ctx.objs
274 .host
275 .add_and_schedule_forked_process(ctx.objs.host, process);
276 }
277
278 if do_parent_settid {
279 ctx.objs
280 .process
281 .memory_borrow_mut()
282 .write(ptid, &kernel_pid_t::from(child_tid))?;
283 }
284
285 if do_child_settid {
286 child_process
288 .memory_borrow_mut()
289 .write(ctid, &kernel_pid_t::from(child_tid))?;
290 }
291
292 if do_child_cleartid {
293 let childrc = child_process.thread_borrow(child_tid).unwrap();
294 let child = childrc.borrow(ctx.objs.host.root());
295 child.set_tid_address(ctid);
296 }
297
298 if do_copy_sighandlers {
299 let shmem_lock = ctx.objs.host.shim_shmem_lock_borrow_mut().unwrap();
300
301 let parent_shmem = ctx.objs.process.shmem();
302 let parent_shmem_prot = parent_shmem.protected.borrow(&shmem_lock.root);
303
304 let child_shmem = child_process_borrow.as_ref().unwrap().shmem();
305 let mut child_shmem_prot = child_shmem.protected.borrow_mut(&shmem_lock.root);
306 unsafe { child_shmem_prot.clone_signal_actions(&parent_shmem_prot) };
308 }
309
310 Ok(kernel_pid_t::from(child_tid))
311 }
312
313 log_syscall!(
316 clone,
317 kernel_pid_t,
318 CloneFlags,
319 *const std::ffi::c_void,
320 *const kernel_pid_t,
321 *const kernel_pid_t,
322 *const std::ffi::c_void,
323 );
324 pub fn clone(
325 ctx: &mut SyscallContext,
326 flags_and_exit_signal: i32,
327 child_stack: ForeignPtr<()>,
328 ptid: ForeignPtr<kernel_pid_t>,
329 ctid: ForeignPtr<kernel_pid_t>,
330 newtls: u64,
331 ) -> Result<kernel_pid_t, Errno> {
332 let raw_flags = flags_and_exit_signal as u32 & !0xff;
333 let raw_exit_signal = (flags_and_exit_signal as u32 & 0xff) as i32;
334
335 let Some(flags) = CloneFlags::from_bits(raw_flags as u64) else {
336 debug!("Couldn't parse clone flags: {raw_flags:x}");
337 return Err(Errno::EINVAL);
338 };
339
340 let exit_signal = if raw_exit_signal == 0 {
341 None
342 } else {
343 let Ok(exit_signal) = Signal::try_from(raw_exit_signal) else {
344 debug!("Bad exit signal: {raw_exit_signal:?}");
345 return Err(Errno::EINVAL);
346 };
347 Some(exit_signal)
348 };
349
350 Self::clone_internal(ctx, flags, exit_signal, child_stack, ptid, ctid, newtls)
351 }
352
353 log_syscall!(
354 clone3,
355 kernel_pid_t,
356 *const linux_api::sched::clone_args,
357 usize,
358 );
359 pub fn clone3(
360 ctx: &mut SyscallContext,
361 args: ForeignPtr<linux_api::sched::clone_args>,
362 args_size: usize,
363 ) -> Result<kernel_pid_t, Errno> {
364 if args_size != std::mem::size_of::<linux_api::sched::clone_args>() {
365 return Err(Errno::EINVAL);
368 }
369 let args = ctx.objs.process.memory_borrow().read(args)?;
370 trace!("clone3 args: {args:?}");
371 let Some(flags) = CloneFlags::from_bits(args.flags) else {
372 debug!("Couldn't parse clone flags: {:x}", args.flags);
373 return Err(Errno::EINVAL);
374 };
375 let exit_signal = if args.exit_signal == 0 {
376 None
377 } else {
378 let Ok(exit_signal) = Signal::try_from(args.exit_signal as i32) else {
379 debug!("Bad signal number: {}", args.exit_signal);
380 return Err(Errno::EINVAL);
381 };
382 Some(exit_signal)
383 };
384 Self::clone_internal(
385 ctx,
386 flags,
387 exit_signal,
388 ForeignPtr::<()>::from(args.stack + args.stack_size),
389 ForeignPtr::<kernel_pid_t>::from_raw_ptr(args.parent_tid as *mut kernel_pid_t),
390 ForeignPtr::<kernel_pid_t>::from_raw_ptr(args.child_tid as *mut kernel_pid_t),
391 args.tls,
392 )
393 }
394
395 log_syscall!(fork, kernel_pid_t);
396 pub fn fork(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
397 Self::clone_internal(
400 ctx,
401 CloneFlags::empty(),
402 Some(Signal::SIGCHLD),
403 ForeignPtr::<()>::null(),
404 ForeignPtr::<kernel_pid_t>::null(),
405 ForeignPtr::<kernel_pid_t>::null(),
406 0,
407 )
408 }
409
410 log_syscall!(vfork, kernel_pid_t);
411 pub fn vfork(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
412 Self::clone_internal(
415 ctx,
416 CloneFlags::CLONE_VFORK | CloneFlags::CLONE_VM,
417 Some(Signal::SIGCHLD),
418 ForeignPtr::<()>::null(),
419 ForeignPtr::<kernel_pid_t>::null(),
420 ForeignPtr::<kernel_pid_t>::null(),
421 0,
422 )
423 }
424
425 log_syscall!(gettid, kernel_pid_t);
426 pub fn gettid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
427 Ok(kernel_pid_t::from(ctx.objs.thread.id()))
428 }
429
430 log_syscall!(
431 capget,
432 std::ffi::c_int,
433 *const std::ffi::c_void,
434 *const std::ffi::c_void,
435 );
436 pub fn capget(
437 ctx: &mut SyscallContext,
438 hdrp: ForeignPtr<user_cap_header>,
439 datap: ForeignPtr<[user_cap_data; 2]>,
440 ) -> Result<(), Errno> {
441 let hdrp = ctx.objs.process.memory_borrow().read(hdrp)?;
443 if hdrp.version != LINUX_CAPABILITY_VERSION_3 {
444 warn_once_then_debug!(
445 "The version of Linux capabilities is not supported ({})",
446 hdrp.version
447 );
448 return Err(Errno::EINVAL);
449 }
450
451 if !datap.is_null() {
452 let empty = user_cap_data {
455 effective: 0,
456 permitted: 0,
457 inheritable: 0,
458 };
459 ctx.objs
460 .process
461 .memory_borrow_mut()
462 .write(datap, &[empty, empty])?;
463 }
464 Ok(())
465 }
466
467 log_syscall!(
468 capset,
469 std::ffi::c_int,
470 *const std::ffi::c_void,
471 *const std::ffi::c_void,
472 );
473 pub fn capset(
474 ctx: &mut SyscallContext,
475 hdrp: ForeignPtr<user_cap_header>,
476 datap: ForeignPtr<[user_cap_data; 2]>,
477 ) -> Result<(), Errno> {
478 let hdrp = ctx.objs.process.memory_borrow().read(hdrp)?;
480 if hdrp.version != LINUX_CAPABILITY_VERSION_3 {
481 warn_once_then_debug!(
482 "The version of Linux capabilities is not supported ({})",
483 hdrp.version
484 );
485 return Err(Errno::EINVAL);
486 }
487
488 let datap: [_; 2] = ctx.objs.process.memory_borrow().read(datap)?;
489 for data in &datap {
490 if data.effective != 0 || data.permitted != 0 || data.inheritable != 0 {
492 warn_once_then_debug!("Setting Linux capabilities is not supported");
493 return Err(Errno::EINVAL);
494 }
495 }
496 Ok(())
497 }
498}