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 native_flags.insert(CloneFlags::CLONE_PARENT);
83 }
84
85 if flags.contains(CloneFlags::CLONE_SIGHAND) {
86 if !flags.contains(CloneFlags::CLONE_VM) {
90 debug!("Missing CLONE_VM");
91 return Err(Errno::EINVAL);
92 }
93 handled_flags.insert(CloneFlags::CLONE_SIGHAND);
96 }
97
98 if flags.contains(CloneFlags::CLONE_FS) {
99 handled_flags.insert(CloneFlags::CLONE_FS);
102 }
103
104 let desc_table = if flags.contains(CloneFlags::CLONE_FILES) {
105 RootedRc::clone(ctx.objs.thread.descriptor_table(), ctx.objs.host.root())
107 } else {
108 let root = ctx.objs.host.root();
110 let table: DescriptorTable = ctx
111 .objs
112 .thread
113 .descriptor_table_borrow(ctx.objs.host)
114 .clone();
115 RootedRc::new(root, RootedRefCell::new(root, table))
116 };
117 let desc_table = ExplicitDropper::new(desc_table, |desc_table| {
118 let d = DropPosixRecordLocks::False;
122 desc_table.explicit_drop_recursive(ctx.objs.host.root(), (ctx.objs.host, d));
123 });
124 handled_flags.insert(CloneFlags::CLONE_FILES);
125
126 if flags.contains(CloneFlags::CLONE_SETTLS) {
127 native_flags.insert(CloneFlags::CLONE_SETTLS);
128 handled_flags.insert(CloneFlags::CLONE_SETTLS);
129 }
130
131 if flags.contains(CloneFlags::CLONE_VFORK) {
132 warn_once_then_debug!(
140 "Ignoring CLONE_VFORK (and CLONE_VM if set). In *typical* usage this won't \
141 result in incorrect behavior."
142 );
143 handled_flags.insert(CloneFlags::CLONE_VFORK);
144 }
145
146 if flags.contains(CloneFlags::CLONE_VM) {
147 if flags.contains(CloneFlags::CLONE_THREAD) {
148 native_flags.insert(CloneFlags::CLONE_VM);
149 } else if flags.contains(CloneFlags::CLONE_VFORK) {
150 } else {
152 warn!("CLONE_VM without CLONE_THREAD and without CLONE_VFORK unsupported");
159 return Err(Errno::ENOTSUP);
160 }
161 handled_flags.insert(CloneFlags::CLONE_VM);
162 }
163
164 if flags.contains(CloneFlags::CLONE_SYSVSEM) {
165 handled_flags.insert(CloneFlags::CLONE_SYSVSEM);
167 }
168
169 let do_parent_settid = flags.contains(CloneFlags::CLONE_PARENT_SETTID);
171 handled_flags.insert(CloneFlags::CLONE_PARENT_SETTID);
172
173 let do_child_settid = flags.contains(CloneFlags::CLONE_CHILD_SETTID);
175 handled_flags.insert(CloneFlags::CLONE_CHILD_SETTID);
176
177 let do_child_cleartid = flags.contains(CloneFlags::CLONE_CHILD_CLEARTID);
179 handled_flags.insert(CloneFlags::CLONE_CHILD_CLEARTID);
180
181 let do_copy_sighandlers = if flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) {
182 if flags.contains(CloneFlags::CLONE_SIGHAND) {
185 return Err(Errno::EINVAL);
186 }
187 false
188 } else {
189 !flags.contains(CloneFlags::CLONE_SIGHAND)
191 };
192 handled_flags.insert(CloneFlags::CLONE_CLEAR_SIGHAND);
193
194 if flags.contains(CloneFlags::CLONE_PARENT) {
195 handled_flags.insert(CloneFlags::CLONE_PARENT);
198 }
199
200 let unhandled_flags = flags.difference(handled_flags);
201 if !unhandled_flags.is_empty() {
202 warn!("Unhandled clone flags: {unhandled_flags:?}");
203 return Err(Errno::ENOTSUP);
204 }
205
206 let child_mthread = ctx.objs.thread.mthread().native_clone(
207 ctx.objs,
208 native_flags,
209 native_child_stack,
210 native_ptid,
211 native_ctid,
212 native_newtls,
213 )?;
214
215 let child_tid = ctx.objs.host.get_new_thread_id();
216 let child_pid = if flags.contains(CloneFlags::CLONE_THREAD) {
217 ctx.objs.process.id()
218 } else {
219 ProcessId::from(child_tid)
220 };
221
222 let child_thread = Thread::wrap_mthread(
223 ctx.objs.host,
224 child_mthread,
225 desc_table.into_value(),
226 child_pid,
227 child_tid,
228 );
229
230 let childrc = ExplicitDropper::new(
231 RootedRc::new(
232 ctx.objs.host.root(),
233 RootedRefCell::new(ctx.objs.host.root(), child_thread),
234 ),
235 |childrc| {
236 childrc.explicit_drop_recursive(ctx.objs.host.root(), ctx.objs.host);
237 },
238 );
239
240 let child_process_rc;
241 let child_process_borrow;
242 let child_process;
243 if flags.contains(CloneFlags::CLONE_THREAD) {
244 child_process_borrow = None;
245 child_process = ctx.objs.process;
246 ctx.objs
247 .process
248 .add_thread(ctx.objs.host, childrc.into_value());
249 } else {
250 let process = ctx
251 .objs
252 .process
253 .borrow_as_runnable()
254 .unwrap()
255 .new_forked_process(ctx.objs.host, flags, exit_signal, childrc.into_value());
256 child_process_rc = Some(ExplicitDropper::new(
257 process.clone(ctx.objs.host.root()),
258 |x| {
259 x.explicit_drop_recursive(ctx.objs.host.root(), ctx.objs.host);
260 },
261 ));
262 child_process_borrow = Some(
263 child_process_rc
264 .as_ref()
265 .unwrap()
266 .borrow(ctx.objs.host.root()),
267 );
268 child_process = child_process_borrow.as_ref().unwrap();
269 ctx.objs
270 .host
271 .add_and_schedule_forked_process(ctx.objs.host, process);
272 }
273
274 if do_parent_settid {
275 ctx.objs
276 .process
277 .memory_borrow_mut()
278 .write(ptid, &kernel_pid_t::from(child_tid))?;
279 }
280
281 if do_child_settid {
282 child_process
284 .memory_borrow_mut()
285 .write(ctid, &kernel_pid_t::from(child_tid))?;
286 }
287
288 if do_child_cleartid {
289 let childrc = child_process.thread_borrow(child_tid).unwrap();
290 let child = childrc.borrow(ctx.objs.host.root());
291 child.set_tid_address(ctid);
292 }
293
294 if do_copy_sighandlers {
295 let shmem_lock = ctx.objs.host.shim_shmem_lock_borrow_mut().unwrap();
296
297 let parent_shmem = ctx.objs.process.shmem();
298 let parent_shmem_prot = parent_shmem.protected.borrow(&shmem_lock.root);
299
300 let child_shmem = child_process_borrow.as_ref().unwrap().shmem();
301 let mut child_shmem_prot = child_shmem.protected.borrow_mut(&shmem_lock.root);
302 unsafe { child_shmem_prot.clone_signal_actions(&parent_shmem_prot) };
304 }
305
306 Ok(kernel_pid_t::from(child_tid))
307 }
308
309 log_syscall!(
312 clone,
313 kernel_pid_t,
314 CloneFlags,
315 *const std::ffi::c_void,
316 *const kernel_pid_t,
317 *const kernel_pid_t,
318 *const std::ffi::c_void,
319 );
320 pub fn clone(
321 ctx: &mut SyscallContext,
322 flags_and_exit_signal: i32,
323 child_stack: ForeignPtr<()>,
324 ptid: ForeignPtr<kernel_pid_t>,
325 ctid: ForeignPtr<kernel_pid_t>,
326 newtls: u64,
327 ) -> Result<kernel_pid_t, Errno> {
328 let raw_flags = flags_and_exit_signal as u32 & !0xff;
329 let raw_exit_signal = (flags_and_exit_signal as u32 & 0xff) as i32;
330
331 let Some(flags) = CloneFlags::from_bits(raw_flags as u64) else {
332 debug!("Couldn't parse clone flags: {raw_flags:x}");
333 return Err(Errno::EINVAL);
334 };
335
336 let exit_signal = if raw_exit_signal == 0 {
337 None
338 } else {
339 let Ok(exit_signal) = Signal::try_from(raw_exit_signal) else {
340 debug!("Bad exit signal: {raw_exit_signal:?}");
341 return Err(Errno::EINVAL);
342 };
343 Some(exit_signal)
344 };
345
346 Self::clone_internal(ctx, flags, exit_signal, child_stack, ptid, ctid, newtls)
347 }
348
349 log_syscall!(
350 clone3,
351 kernel_pid_t,
352 *const linux_api::sched::clone_args,
353 usize,
354 );
355 pub fn clone3(
356 ctx: &mut SyscallContext,
357 args: ForeignPtr<linux_api::sched::clone_args>,
358 args_size: usize,
359 ) -> Result<kernel_pid_t, Errno> {
360 if args_size != std::mem::size_of::<linux_api::sched::clone_args>() {
361 return Err(Errno::EINVAL);
364 }
365 let args = ctx.objs.process.memory_borrow().read(args)?;
366 trace!("clone3 args: {args:?}");
367 let Some(flags) = CloneFlags::from_bits(args.flags) else {
368 debug!("Couldn't parse clone flags: {:x}", args.flags);
369 return Err(Errno::EINVAL);
370 };
371 let exit_signal = if args.exit_signal == 0 {
372 None
373 } else {
374 let Ok(exit_signal) = Signal::try_from(args.exit_signal as i32) else {
375 debug!("Bad signal number: {}", args.exit_signal);
376 return Err(Errno::EINVAL);
377 };
378 Some(exit_signal)
379 };
380 Self::clone_internal(
381 ctx,
382 flags,
383 exit_signal,
384 ForeignPtr::<()>::from(args.stack + args.stack_size),
385 ForeignPtr::<kernel_pid_t>::from_raw_ptr(args.parent_tid as *mut kernel_pid_t),
386 ForeignPtr::<kernel_pid_t>::from_raw_ptr(args.child_tid as *mut kernel_pid_t),
387 args.tls,
388 )
389 }
390
391 log_syscall!(fork, kernel_pid_t);
392 pub fn fork(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
393 Self::clone_internal(
396 ctx,
397 CloneFlags::empty(),
398 Some(Signal::SIGCHLD),
399 ForeignPtr::<()>::null(),
400 ForeignPtr::<kernel_pid_t>::null(),
401 ForeignPtr::<kernel_pid_t>::null(),
402 0,
403 )
404 }
405
406 log_syscall!(vfork, kernel_pid_t);
407 pub fn vfork(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
408 Self::clone_internal(
411 ctx,
412 CloneFlags::CLONE_VFORK | CloneFlags::CLONE_VM,
413 Some(Signal::SIGCHLD),
414 ForeignPtr::<()>::null(),
415 ForeignPtr::<kernel_pid_t>::null(),
416 ForeignPtr::<kernel_pid_t>::null(),
417 0,
418 )
419 }
420
421 log_syscall!(gettid, kernel_pid_t);
422 pub fn gettid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
423 Ok(kernel_pid_t::from(ctx.objs.thread.id()))
424 }
425
426 log_syscall!(
427 capget,
428 std::ffi::c_int,
429 *const std::ffi::c_void,
430 *const std::ffi::c_void,
431 );
432 pub fn capget(
433 ctx: &mut SyscallContext,
434 hdrp: ForeignPtr<user_cap_header>,
435 datap: ForeignPtr<[user_cap_data; 2]>,
436 ) -> Result<(), Errno> {
437 let hdrp = ctx.objs.process.memory_borrow().read(hdrp)?;
439 if hdrp.version != LINUX_CAPABILITY_VERSION_3 {
440 warn_once_then_debug!(
441 "The version of Linux capabilities is not supported ({})",
442 hdrp.version
443 );
444 return Err(Errno::EINVAL);
445 }
446
447 if !datap.is_null() {
448 let empty = user_cap_data {
451 effective: 0,
452 permitted: 0,
453 inheritable: 0,
454 };
455 ctx.objs
456 .process
457 .memory_borrow_mut()
458 .write(datap, &[empty, empty])?;
459 }
460 Ok(())
461 }
462
463 log_syscall!(
464 capset,
465 std::ffi::c_int,
466 *const std::ffi::c_void,
467 *const std::ffi::c_void,
468 );
469 pub fn capset(
470 ctx: &mut SyscallContext,
471 hdrp: ForeignPtr<user_cap_header>,
472 datap: ForeignPtr<[user_cap_data; 2]>,
473 ) -> Result<(), Errno> {
474 let hdrp = ctx.objs.process.memory_borrow().read(hdrp)?;
476 if hdrp.version != LINUX_CAPABILITY_VERSION_3 {
477 warn_once_then_debug!(
478 "The version of Linux capabilities is not supported ({})",
479 hdrp.version
480 );
481 return Err(Errno::EINVAL);
482 }
483
484 let datap: [_; 2] = ctx.objs.process.memory_borrow().read(datap)?;
485 for data in &datap {
486 if data.effective != 0 || data.permitted != 0 || data.inheritable != 0 {
488 warn_once_then_debug!("Setting Linux capabilities is not supported");
489 return Err(Errno::EINVAL);
490 }
491 }
492 Ok(())
493 }
494}