shadow_rs/host/syscall/handler/
prctl.rs

1use linux_api::errno::Errno;
2use linux_api::prctl::PrctlOp;
3use linux_api::sched::SuidDump;
4use shadow_shim_helper_rs::syscall_types::ForeignPtr;
5
6use crate::host::syscall::handler::{SyscallContext, SyscallHandler};
7use crate::host::syscall::types::SyscallError;
8
9impl SyscallHandler {
10    log_syscall!(
11        prctl,
12        /* rv */ std::ffi::c_int,
13        /* option */ PrctlOp,
14        /* arg2 */ std::ffi::c_ulong,
15        /* arg3 */ std::ffi::c_ulong,
16        /* arg4 */ std::ffi::c_ulong,
17        /* arg5 */ std::ffi::c_ulong,
18    );
19    pub fn prctl(
20        ctx: &mut SyscallContext,
21        option: PrctlOp,
22        arg2: std::ffi::c_ulong,
23        _arg3: std::ffi::c_ulong,
24        _arg4: std::ffi::c_ulong,
25        _arg5: std::ffi::c_ulong,
26    ) -> Result<std::ffi::c_int, SyscallError> {
27        match option {
28            PrctlOp::PR_CAP_AMBIENT
29            | PrctlOp::PR_CAPBSET_READ
30            | PrctlOp::PR_CAPBSET_DROP
31            | PrctlOp::PR_SET_CHILD_SUBREAPER
32            | PrctlOp::PR_GET_CHILD_SUBREAPER
33            | PrctlOp::PR_SET_ENDIAN
34            | PrctlOp::PR_GET_ENDIAN
35            | PrctlOp::PR_SET_FP_MODE
36            | PrctlOp::PR_GET_FP_MODE
37            | PrctlOp::PR_SET_FPEMU
38            | PrctlOp::PR_GET_FPEMU
39            | PrctlOp::PR_SET_FPEXC
40            | PrctlOp::PR_GET_FPEXC
41            | PrctlOp::PR_SET_KEEPCAPS
42            | PrctlOp::PR_GET_KEEPCAPS
43            | PrctlOp::PR_MCE_KILL
44            | PrctlOp::PR_MCE_KILL_GET
45            | PrctlOp::PR_MPX_ENABLE_MANAGEMENT
46            | PrctlOp::PR_MPX_DISABLE_MANAGEMENT
47            | PrctlOp::PR_SET_NAME
48            | PrctlOp::PR_GET_NAME
49            | PrctlOp::PR_SET_NO_NEW_PRIVS
50            | PrctlOp::PR_GET_NO_NEW_PRIVS
51            | PrctlOp::PR_SET_MM
52            | PrctlOp::PR_SET_PTRACER
53            | PrctlOp::PR_SET_SECUREBITS
54            | PrctlOp::PR_GET_SECUREBITS
55            | PrctlOp::PR_GET_SPECULATION_CTRL
56            | PrctlOp::PR_SET_THP_DISABLE
57            | PrctlOp::PR_TASK_PERF_EVENTS_DISABLE
58            | PrctlOp::PR_TASK_PERF_EVENTS_ENABLE
59            | PrctlOp::PR_GET_THP_DISABLE
60            | PrctlOp::PR_GET_TIMERSLACK
61            | PrctlOp::PR_SET_TIMING
62            | PrctlOp::PR_GET_TIMING
63            | PrctlOp::PR_GET_TSC
64            | PrctlOp::PR_GET_UNALIGN => {
65                log::trace!("prctl {option} executing natively");
66                Err(SyscallError::Native)
67            }
68            PrctlOp::PR_SET_SECCOMP | PrctlOp::PR_GET_SECCOMP => {
69                log::warn!("Not allowing seccomp prctl {option}");
70                Err(Errno::EINVAL.into())
71            }
72            // Needs emulation to have the desired effect, but also N/A on x86_64.
73            PrctlOp::PR_SET_UNALIGN
74            // Executing natively could interfere with shadow's interception of rdtsc. Needs
75            // emulation.
76            | PrctlOp::PR_SET_TSC
77            // Executing natively wouldn't directly hurt anything, but wouldn't have the desired
78            // effect.
79            | PrctlOp::PR_SET_TIMERSLACK
80            // Wouldn't actually hurt correctness, but could significantly hurt performance.
81            | PrctlOp::PR_SET_SPECULATION_CTRL
82            // We use this signal to ensure managed processes die when Shadow does. Allowing the
83            // process to override it could end up allowing orphaned managed processes to live on
84            // after shadow exits.
85            | PrctlOp::PR_SET_PDEATHSIG => {
86                log::warn!("Not allowing unimplemented prctl {option}");
87                Err(Errno::EINVAL.into())
88            }
89            PrctlOp::PR_GET_TID_ADDRESS => {
90                let out_ptr = ForeignPtr::from(arg2)
91                    .cast::<ForeignPtr<linux_api::posix_types::kernel_pid_t>>();
92                let tid_addr = ctx.objs.thread.get_tid_address();
93                ctx.objs.process.memory_borrow_mut().write(out_ptr, &tid_addr)?;
94                Ok(0)
95            }
96            PrctlOp::PR_SET_DUMPABLE => {
97                let dumpable = SuidDump::new(arg2.try_into().or(Err(Errno::EINVAL))?);
98                if [SuidDump::SUID_DUMP_DISABLE, SuidDump::SUID_DUMP_USER].contains(&dumpable) {
99                    ctx.objs.process.set_dumpable(dumpable);
100                    Ok(0)
101                } else {
102                    Err(Errno::EINVAL.into())
103                }
104            }
105            PrctlOp::PR_GET_DUMPABLE => {
106                Ok(ctx.objs.process.dumpable().val())
107            }
108            _ => {
109                log::warn!("Unknown prctl operation {option}");
110                Err(Errno::EINVAL.into())
111            }
112        }
113    }
114}