Skip to main content

miri/shims/unix/linux_like/
syscall.rs

1use rustc_abi::CanonAbi;
2use rustc_middle::ty::Ty;
3use rustc_span::Symbol;
4use rustc_target::callconv::FnAbi;
5
6use crate::shims::sig::check_min_vararg_count;
7use crate::shims::unix::env::EvalContextExt;
8use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
9use crate::shims::unix::linux_like::sync::futex;
10use crate::shims::unix::socket::EvalContextExt as _;
11use crate::*;
12
13pub fn syscall<'tcx>(
14    ecx: &mut MiriInterpCx<'tcx>,
15    link_name: Symbol,
16    abi: &FnAbi<'tcx, Ty<'tcx>>,
17    args: &[OpTy<'tcx>],
18    dest: &MPlaceTy<'tcx>,
19) -> InterpResult<'tcx> {
20    let ([op], varargs) = ecx.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
21    // The syscall variadic function is legal to call with more arguments than needed,
22    // extra arguments are simply ignored. The important check is that when we use an
23    // argument, we have to also check all arguments *before* it to ensure that they
24    // have the right type.
25
26    let sys_getrandom = ecx.eval_libc("SYS_getrandom").to_target_usize(ecx)?;
27    let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?;
28    let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?;
29    let sys_gettid = ecx.eval_libc("SYS_gettid").to_target_usize(ecx)?;
30    let sys_accept4 = ecx.eval_libc("SYS_accept4").to_target_usize(ecx)?;
31
32    match ecx.read_target_usize(op)? {
33        // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
34        // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
35        num if num == sys_getrandom => {
36            // Used by getrandom 0.1
37            // The first argument is the syscall id, so skip over it.
38            let [ptr, len, flags] = check_min_vararg_count("syscall(SYS_getrandom, ...)", varargs)?;
39
40            let ptr = ecx.read_pointer(ptr)?;
41            let len = ecx.read_target_usize(len)?;
42            // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
43            // neither of which have any effect on our current PRNG.
44            // See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
45            let _flags = ecx.read_scalar(flags)?.to_i32()?;
46
47            ecx.gen_random(ptr, len)?;
48            ecx.write_scalar(Scalar::from_target_usize(len, ecx), dest)?;
49        }
50        // `futex` is used by some synchronization primitives.
51        num if num == sys_futex => {
52            futex(ecx, varargs, dest)?;
53        }
54        num if num == sys_eventfd2 => {
55            let [initval, flags] = check_min_vararg_count("syscall(SYS_evetfd2, ...)", varargs)?;
56
57            let result = ecx.eventfd(initval, flags)?;
58            ecx.write_int(result.to_i32()?, dest)?;
59        }
60        num if num == sys_gettid => {
61            let result = ecx.unix_gettid("SYS_gettid")?;
62            ecx.write_int(result.to_u32()?, dest)?;
63        }
64        num if num == sys_accept4 => {
65            // Used on Android.
66            let [socket, address, address_len, flags] =
67                check_min_vararg_count("syscall(SYS_accept4, ...)", varargs)?;
68            ecx.accept4(socket, address, address_len, Some(flags), dest)?;
69        }
70        num => {
71            throw_unsup_format!("syscall: unsupported syscall number {num}");
72        }
73    };
74
75    interp_ok(())
76}