shadow_rs/host/syscall/handler/
clone.rs
1use 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::descriptor_table::DescriptorTable;
13use crate::host::process::ProcessId;
14use crate::host::thread::Thread;
15
16use super::{SyscallContext, SyscallHandler};
17
18impl SyscallHandler {
19 fn clone_internal(
20 ctx: &mut SyscallContext,
21 flags: CloneFlags,
22 exit_signal: Option<Signal>,
23 child_stack: ForeignPtr<()>,
24 ptid: ForeignPtr<kernel_pid_t>,
25 ctid: ForeignPtr<kernel_pid_t>,
26 newtls: u64,
27 ) -> Result<kernel_pid_t, Errno> {
28 let mut handled_flags = CloneFlags::empty();
31
32 let mut native_flags = CloneFlags::empty();
34
35 let native_ctid = ForeignPtr::<kernel_pid_t>::null();
38 let native_ptid = ForeignPtr::<kernel_pid_t>::null();
39
40 let native_child_stack = child_stack;
42
43 let native_newtls = newtls;
45
46 if flags.contains(CloneFlags::CLONE_THREAD) {
47 if !flags.contains(CloneFlags::CLONE_SIGHAND) {
51 debug!("Missing CLONE_SIGHAND");
52 return Err(Errno::EINVAL);
53 }
54 if !flags.contains(CloneFlags::CLONE_SETTLS) {
55 warn!("CLONE_THREAD without CLONE_TLS not supported by shadow");
57 return Err(Errno::ENOTSUP);
58 }
59 if exit_signal.is_some() {
60 warn!("Exit signal is unimplemented");
61 return Err(Errno::ENOTSUP);
62 }
63 native_flags.insert(CloneFlags::CLONE_THREAD);
66 native_flags.insert(CloneFlags::CLONE_SIGHAND);
68 native_flags.insert(CloneFlags::CLONE_FS);
70 native_flags.insert(CloneFlags::CLONE_FILES);
72 native_flags.insert(CloneFlags::CLONE_SYSVSEM);
74
75 handled_flags.insert(CloneFlags::CLONE_THREAD);
76 } else {
77 if ctx.objs.process.memory_borrow().has_mapper() {
78 warn!("Fork with memory mapper unimplemented");
79 return Err(Errno::ENOTSUP);
80 }
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 desc_table.explicit_drop_recursive(ctx.objs.host.root(), ctx.objs.host);
119 });
120 handled_flags.insert(CloneFlags::CLONE_FILES);
121
122 if flags.contains(CloneFlags::CLONE_SETTLS) {
123 native_flags.insert(CloneFlags::CLONE_SETTLS);
124 handled_flags.insert(CloneFlags::CLONE_SETTLS);
125 }
126
127 if flags.contains(CloneFlags::CLONE_VFORK) {
128 warn_once_then_debug!(
136 "Ignoring CLONE_VFORK (and CLONE_VM if set). In *typical* usage this won't \
137 result in incorrect behavior."
138 );
139 handled_flags.insert(CloneFlags::CLONE_VFORK);
140 }
141
142 if flags.contains(CloneFlags::CLONE_VM) {
143 if flags.contains(CloneFlags::CLONE_THREAD) {
144 native_flags.insert(CloneFlags::CLONE_VM);
145 } else if flags.contains(CloneFlags::CLONE_VFORK) {
146 } else {
148 warn!("CLONE_VM without CLONE_THREAD and without CLONE_VFORK unsupported");
155 return Err(Errno::ENOTSUP);
156 }
157 handled_flags.insert(CloneFlags::CLONE_VM);
158 }
159
160 if flags.contains(CloneFlags::CLONE_SYSVSEM) {
161 handled_flags.insert(CloneFlags::CLONE_SYSVSEM);
163 }
164
165 let do_parent_settid = flags.contains(CloneFlags::CLONE_PARENT_SETTID);
167 handled_flags.insert(CloneFlags::CLONE_PARENT_SETTID);
168
169 let do_child_settid = flags.contains(CloneFlags::CLONE_CHILD_SETTID);
171 handled_flags.insert(CloneFlags::CLONE_CHILD_SETTID);
172
173 let do_child_cleartid = flags.contains(CloneFlags::CLONE_CHILD_CLEARTID);
175 handled_flags.insert(CloneFlags::CLONE_CHILD_CLEARTID);
176
177 let do_copy_sighandlers = if flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) {
178 if flags.contains(CloneFlags::CLONE_SIGHAND) {
181 return Err(Errno::EINVAL);
182 }
183 false
184 } else {
185 !flags.contains(CloneFlags::CLONE_SIGHAND)
187 };
188 handled_flags.insert(CloneFlags::CLONE_CLEAR_SIGHAND);
189
190 if flags.contains(CloneFlags::CLONE_PARENT) {
191 handled_flags.insert(CloneFlags::CLONE_PARENT);
194 }
195
196 let unhandled_flags = flags.difference(handled_flags);
197 if !unhandled_flags.is_empty() {
198 warn!("Unhandled clone flags: {unhandled_flags:?}");
199 return Err(Errno::ENOTSUP);
200 }
201
202 let child_mthread = ctx.objs.thread.mthread().native_clone(
203 ctx.objs,
204 native_flags,
205 native_child_stack,
206 native_ptid,
207 native_ctid,
208 native_newtls,
209 )?;
210
211 let child_tid = ctx.objs.host.get_new_thread_id();
212 let child_pid = if flags.contains(CloneFlags::CLONE_THREAD) {
213 ctx.objs.process.id()
214 } else {
215 ProcessId::from(child_tid)
216 };
217
218 let child_thread = Thread::wrap_mthread(
219 ctx.objs.host,
220 child_mthread,
221 desc_table.into_value(),
222 child_pid,
223 child_tid,
224 )?;
225
226 let childrc = ExplicitDropper::new(
227 RootedRc::new(
228 ctx.objs.host.root(),
229 RootedRefCell::new(ctx.objs.host.root(), child_thread),
230 ),
231 |childrc| {
232 childrc.explicit_drop_recursive(ctx.objs.host.root(), ctx.objs.host);
233 },
234 );
235
236 let child_process_rc;
237 let child_process_borrow;
238 let child_process;
239 if flags.contains(CloneFlags::CLONE_THREAD) {
240 child_process_borrow = None;
241 child_process = ctx.objs.process;
242 ctx.objs
243 .process
244 .add_thread(ctx.objs.host, childrc.into_value());
245 } else {
246 let process = ctx
247 .objs
248 .process
249 .borrow_as_runnable()
250 .unwrap()
251 .new_forked_process(ctx.objs.host, flags, exit_signal, childrc.into_value());
252 child_process_rc = Some(ExplicitDropper::new(
253 process.clone(ctx.objs.host.root()),
254 |x| {
255 x.explicit_drop_recursive(ctx.objs.host.root(), ctx.objs.host);
256 },
257 ));
258 child_process_borrow = Some(
259 child_process_rc
260 .as_ref()
261 .unwrap()
262 .borrow(ctx.objs.host.root()),
263 );
264 child_process = child_process_borrow.as_ref().unwrap();
265 ctx.objs
266 .host
267 .add_and_schedule_forked_process(ctx.objs.host, process);
268 }
269
270 if do_parent_settid {
271 ctx.objs
272 .process
273 .memory_borrow_mut()
274 .write(ptid, &kernel_pid_t::from(child_tid))?;
275 }
276
277 if do_child_settid {
278 child_process
280 .memory_borrow_mut()
281 .write(ctid, &kernel_pid_t::from(child_tid))?;
282 }
283
284 if do_child_cleartid {
285 let childrc = child_process.thread_borrow(child_tid).unwrap();
286 let child = childrc.borrow(ctx.objs.host.root());
287 child.set_tid_address(ctid);
288 }
289
290 if do_copy_sighandlers {
291 let shmem_lock = ctx.objs.host.shim_shmem_lock_borrow_mut().unwrap();
292
293 let parent_shmem = ctx.objs.process.shmem();
294 let parent_shmem_prot = parent_shmem.protected.borrow(&shmem_lock.root);
295
296 let child_shmem = child_process_borrow.as_ref().unwrap().shmem();
297 let mut child_shmem_prot = child_shmem.protected.borrow_mut(&shmem_lock.root);
298 unsafe { child_shmem_prot.clone_signal_actions(&parent_shmem_prot) };
300 }
301
302 Ok(kernel_pid_t::from(child_tid))
303 }
304
305 log_syscall!(
308 clone,
309 kernel_pid_t,
310 CloneFlags,
311 *const std::ffi::c_void,
312 *const kernel_pid_t,
313 *const kernel_pid_t,
314 *const std::ffi::c_void,
315 );
316 pub fn clone(
317 ctx: &mut SyscallContext,
318 flags_and_exit_signal: i32,
319 child_stack: ForeignPtr<()>,
320 ptid: ForeignPtr<kernel_pid_t>,
321 ctid: ForeignPtr<kernel_pid_t>,
322 newtls: u64,
323 ) -> Result<kernel_pid_t, Errno> {
324 let raw_flags = flags_and_exit_signal as u32 & !0xff;
325 let raw_exit_signal = (flags_and_exit_signal as u32 & 0xff) as i32;
326
327 let Some(flags) = CloneFlags::from_bits(raw_flags as u64) else {
328 debug!("Couldn't parse clone flags: {raw_flags:x}");
329 return Err(Errno::EINVAL);
330 };
331
332 let exit_signal = if raw_exit_signal == 0 {
333 None
334 } else {
335 let Ok(exit_signal) = Signal::try_from(raw_exit_signal) else {
336 debug!("Bad exit signal: {raw_exit_signal:?}");
337 return Err(Errno::EINVAL);
338 };
339 Some(exit_signal)
340 };
341
342 Self::clone_internal(ctx, flags, exit_signal, child_stack, ptid, ctid, newtls)
343 }
344
345 log_syscall!(
346 clone3,
347 kernel_pid_t,
348 *const linux_api::sched::clone_args,
349 usize,
350 );
351 pub fn clone3(
352 ctx: &mut SyscallContext,
353 args: ForeignPtr<linux_api::sched::clone_args>,
354 args_size: usize,
355 ) -> Result<kernel_pid_t, Errno> {
356 if args_size != std::mem::size_of::<linux_api::sched::clone_args>() {
357 return Err(Errno::EINVAL);
360 }
361 let args = ctx.objs.process.memory_borrow().read(args)?;
362 trace!("clone3 args: {args:?}");
363 let Some(flags) = CloneFlags::from_bits(args.flags) else {
364 debug!("Couldn't parse clone flags: {:x}", args.flags);
365 return Err(Errno::EINVAL);
366 };
367 let exit_signal = if args.exit_signal == 0 {
368 None
369 } else {
370 let Ok(exit_signal) = Signal::try_from(args.exit_signal as i32) else {
371 debug!("Bad signal number: {}", args.exit_signal);
372 return Err(Errno::EINVAL);
373 };
374 Some(exit_signal)
375 };
376 Self::clone_internal(
377 ctx,
378 flags,
379 exit_signal,
380 ForeignPtr::<()>::from(args.stack + args.stack_size),
381 ForeignPtr::<kernel_pid_t>::from_raw_ptr(args.parent_tid as *mut kernel_pid_t),
382 ForeignPtr::<kernel_pid_t>::from_raw_ptr(args.child_tid as *mut kernel_pid_t),
383 args.tls,
384 )
385 }
386
387 log_syscall!(fork, kernel_pid_t);
388 pub fn fork(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
389 Self::clone_internal(
392 ctx,
393 CloneFlags::empty(),
394 Some(Signal::SIGCHLD),
395 ForeignPtr::<()>::null(),
396 ForeignPtr::<kernel_pid_t>::null(),
397 ForeignPtr::<kernel_pid_t>::null(),
398 0,
399 )
400 }
401
402 log_syscall!(vfork, kernel_pid_t);
403 pub fn vfork(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
404 Self::clone_internal(
407 ctx,
408 CloneFlags::CLONE_VFORK | CloneFlags::CLONE_VM,
409 Some(Signal::SIGCHLD),
410 ForeignPtr::<()>::null(),
411 ForeignPtr::<kernel_pid_t>::null(),
412 ForeignPtr::<kernel_pid_t>::null(),
413 0,
414 )
415 }
416
417 log_syscall!(gettid, kernel_pid_t);
418 pub fn gettid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, Errno> {
419 Ok(kernel_pid_t::from(ctx.objs.thread.id()))
420 }
421
422 log_syscall!(
423 capget,
424 std::ffi::c_int,
425 *const std::ffi::c_void,
426 *const std::ffi::c_void,
427 );
428 pub fn capget(
429 ctx: &mut SyscallContext,
430 hdrp: ForeignPtr<user_cap_header>,
431 datap: ForeignPtr<[user_cap_data; 2]>,
432 ) -> Result<(), Errno> {
433 let hdrp = ctx.objs.process.memory_borrow().read(hdrp)?;
435 if hdrp.version != LINUX_CAPABILITY_VERSION_3 {
436 warn_once_then_debug!(
437 "The version of Linux capabilities is not supported ({})",
438 hdrp.version
439 );
440 return Err(Errno::EINVAL);
441 }
442
443 if !datap.is_null() {
444 let empty = user_cap_data {
447 effective: 0,
448 permitted: 0,
449 inheritable: 0,
450 };
451 ctx.objs
452 .process
453 .memory_borrow_mut()
454 .write(datap, &[empty, empty])?;
455 }
456 Ok(())
457 }
458
459 log_syscall!(
460 capset,
461 std::ffi::c_int,
462 *const std::ffi::c_void,
463 *const std::ffi::c_void,
464 );
465 pub fn capset(
466 ctx: &mut SyscallContext,
467 hdrp: ForeignPtr<user_cap_header>,
468 datap: ForeignPtr<[user_cap_data; 2]>,
469 ) -> Result<(), Errno> {
470 let hdrp = ctx.objs.process.memory_borrow().read(hdrp)?;
472 if hdrp.version != LINUX_CAPABILITY_VERSION_3 {
473 warn_once_then_debug!(
474 "The version of Linux capabilities is not supported ({})",
475 hdrp.version
476 );
477 return Err(Errno::EINVAL);
478 }
479
480 let datap: [_; 2] = ctx.objs.process.memory_borrow().read(datap)?;
481 for data in &datap {
482 if data.effective != 0 || data.permitted != 0 || data.inheritable != 0 {
484 warn_once_then_debug!("Setting Linux capabilities is not supported");
485 return Err(Errno::EINVAL);
486 }
487 }
488 Ok(())
489 }
490}