Skip to main content

miri/shims/unix/linux_like/
syscall.rs

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