Skip to content

Commit 3fafb83

Browse files
committed
Auto merge of #1570 - RalfJung:syscalls, r=RalfJung
check that all syscall arguments are scalars `@m-ou-se` do you think this check makes sense? The `abi` of a layout contains everything needed for the calling convention (as far as I know), so this should ensure that all the ignored arguments are passed like integers and do not otherwise mess up argument passing. The one thing I am not sure about is what happens when more arguments are passed than fit in registers. The `syscall` man page says that all calling conventions support at least 6 arguments, except for "mips/o32" where it says that ``` [1] The mips/o32 system call convention passes arguments 5 through 8 on the user stack. ``` If we assume that passing these extra arguments to futex is legal even with that calling convention, that would mean that those user stack arguments are just silently ignored as well, which seems plausible to me -- but I know very little about calling conventions.
2 parents 5620ad0 + 2b2a3a0 commit 3fafb83

File tree

3 files changed

+23
-21
lines changed

3 files changed

+23
-21
lines changed

src/bin/miri.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ fn main() {
221221
),
222222
FromHexError::OddLength =>
223223
panic!("-Zmiri-seed should have an even number of digits"),
224-
err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err),
224+
err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err),
225225
});
226226
if seed_raw.len() > 8 {
227227
panic!(format!(

src/shims/posix/linux/foreign_items.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
113113

114114
// Dynamically invoked syscalls
115115
"syscall" => {
116-
// FIXME: The libc syscall() function is a variadic function.
117-
// It's valid to call it with more arguments than a syscall
118-
// needs, so none of these syscalls should use check_arg_count.
119-
// It's even valid to call it with the wrong type of arguments,
120-
// as long as they'd end up in the same place with the calling
121-
// convention used. (E.g. using a `usize` instead of a pointer.)
122-
// It's not directly clear which number, size, and type of arguments
123-
// are acceptable in which cases and which aren't. (E.g. some
124-
// types might take up the space of two registers.)
125-
// So this needs to be researched first.
116+
// The syscall variadic function is legal to call with more arguments than needed,
117+
// extra arguments are simply ignored. However, all arguments need to be scalars;
118+
// other types might be treated differently by the calling convention.
119+
for arg in args {
120+
if !matches!(arg.layout.abi, rustc_target::abi::Abi::Scalar(_)) {
121+
throw_ub_format!("`syscall` arguments must all have scalar layout, but {} does not", arg.layout.ty);
122+
}
123+
}
126124

127125
let sys_getrandom = this
128126
.eval_libc("SYS_getrandom")?
@@ -144,22 +142,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
144142
// is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
145143
id if id == sys_getrandom => {
146144
// The first argument is the syscall id, so skip over it.
147-
let &[_, ptr, len, flags] = check_arg_count(args)?;
148-
getrandom(this, ptr, len, flags, dest)?;
145+
if args.len() < 4 {
146+
throw_ub_format!("incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len());
147+
}
148+
getrandom(this, args[1], args[2], args[3], dest)?;
149149
}
150150
// `statx` is used by `libstd` to retrieve metadata information on `linux`
151151
// instead of using `stat`,`lstat` or `fstat` as on `macos`.
152152
id if id == sys_statx => {
153153
// The first argument is the syscall id, so skip over it.
154-
let &[_, dirfd, pathname, flags, mask, statxbuf] = check_arg_count(args)?;
155-
let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
154+
if args.len() < 6 {
155+
throw_ub_format!("incorrect number of arguments for `statx` syscall: got {}, expected at least 6", args.len());
156+
}
157+
let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?;
156158
this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?;
157159
}
158160
// `futex` is used by some synchonization primitives.
159161
id if id == sys_futex => {
160162
futex(this, args, dest)?;
161163
}
162-
id => throw_unsup_format!("miri does not support syscall ID {}", id),
164+
id => throw_unsup_format!("Miri does not support syscall ID {}", id),
163165
}
164166
}
165167

src/shims/posix/linux/sync.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ pub fn futex<'tcx>(
1717
// may or may not be left out from the `syscall()` call.
1818
// Therefore we don't use `check_arg_count` here, but only check for the
1919
// number of arguments to fall within a range.
20-
if !(4..=7).contains(&args.len()) {
21-
throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len());
20+
if args.len() < 4 {
21+
throw_ub_format!("incorrect number of arguments for `futex` syscall: got {}, expected at least 4", args.len());
2222
}
2323

2424
// The first three arguments (after the syscall number itself) are the same to all futex operations:
@@ -49,13 +49,13 @@ pub fn futex<'tcx>(
4949
// or *timeout expires. `timeout == null` for an infinite timeout.
5050
op if op & !futex_realtime == futex_wait => {
5151
if args.len() < 5 {
52-
throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len());
52+
throw_ub_format!("incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", args.len());
5353
}
5454
let timeout = args[4];
5555
let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? {
5656
None
5757
} else {
58-
this.check_no_isolation("`syscall(SYS_FUTEX, op=FUTEX_WAIT)` with timeout")?;
58+
this.check_no_isolation("`futex` syscall with `op=FUTEX_WAIT` and non-null timeout")?;
5959
let duration = match this.read_timespec(timeout)? {
6060
Some(duration) => duration,
6161
None => {
@@ -126,7 +126,7 @@ pub fn futex<'tcx>(
126126
}
127127
this.write_scalar(Scalar::from_machine_isize(n, this), dest)?;
128128
}
129-
op => throw_unsup_format!("miri does not support SYS_futex operation {}", op),
129+
op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
130130
}
131131

132132
Ok(())

0 commit comments

Comments
 (0)