Skip to content

Commit 52c7b8e

Browse files
committed
Auto merge of #1502 - RalfJung:isolation, r=RalfJung
fs: move isolation handling to inside trait
2 parents eaf5d32 + 5657f08 commit 52c7b8e

File tree

3 files changed

+52
-27
lines changed

3 files changed

+52
-27
lines changed

src/helpers.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,13 +376,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
376376
/// case.
377377
fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> {
378378
if !self.eval_context_ref().machine.communicate {
379-
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
380-
"`{}` not available when isolation is enabled",
381-
name,
382-
)))
379+
isolation_error(name)?;
383380
}
384381
Ok(())
385382
}
383+
386384
/// Helper function used inside the shims of foreign functions to assert that the target OS
387385
/// is `target_os`. It panics showing a message with the `name` of the foreign function
388386
/// if this is not the case.
@@ -509,6 +507,13 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) ->
509507
throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
510508
}
511509

510+
pub fn isolation_error(name: &str) -> InterpResult<'static> {
511+
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
512+
"`{}` not available when isolation is enabled",
513+
name,
514+
)))
515+
}
516+
512517
pub fn immty_from_int_checked<'tcx>(
513518
int: impl Into<i128>,
514519
layout: TyAndLayout<'tcx>,

src/shims/posix/fs.rs

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,28 @@ struct FileHandle {
2525
trait FileDescriptor<'tcx> : std::fmt::Debug {
2626
fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>;
2727

28-
fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>>;
29-
fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>>;
30-
fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>>;
28+
fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>>;
29+
fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>>;
30+
fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>>;
3131
}
3232

3333
impl<'tcx> FileDescriptor<'tcx> for FileHandle {
3434
fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> {
3535
Ok(&self)
3636
}
3737

38-
fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
38+
fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
39+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
3940
Ok(self.file.read(bytes))
4041
}
4142

42-
fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
43+
fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
44+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
4345
Ok(self.file.write(bytes))
4446
}
4547

46-
fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
48+
fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
49+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
4750
Ok(self.file.seek(offset))
4851
}
4952
}
@@ -53,15 +56,19 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdin {
5356
throw_unsup_format!("stdin cannot be used as FileHandle");
5457
}
5558

56-
fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
59+
fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
60+
if !communicate_allowed {
61+
// We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
62+
helpers::isolation_error("read")?;
63+
}
5764
Ok(Read::read(self, bytes))
5865
}
5966

60-
fn write(&mut self, _bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
67+
fn write(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
6168
throw_unsup_format!("cannot write to stdin");
6269
}
6370

64-
fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
71+
fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
6572
throw_unsup_format!("cannot seek on stdin");
6673
}
6774
}
@@ -71,11 +78,12 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout {
7178
throw_unsup_format!("stdout cannot be used as FileHandle");
7279
}
7380

74-
fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
81+
fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
7582
throw_unsup_format!("cannot read from stdout");
7683
}
7784

78-
fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
85+
fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
86+
// We allow writing to stderr even with isolation enabled.
7987
let result = Write::write(self, bytes);
8088
// Stdout is buffered, flush to make sure it appears on the
8189
// screen. This is the write() syscall of the interpreted
@@ -87,7 +95,7 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout {
8795
Ok(result)
8896
}
8997

90-
fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
98+
fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
9199
throw_unsup_format!("cannot seek on stdout");
92100
}
93101
}
@@ -97,15 +105,16 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stderr {
97105
throw_unsup_format!("stdout cannot be used as FileHandle");
98106
}
99107

100-
fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
108+
fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
101109
throw_unsup_format!("cannot read from stderr");
102110
}
103111

104-
fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
112+
fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
113+
// We allow writing to stderr even with isolation enabled.
105114
Ok(Write::write(self, bytes))
106115
}
107116

108-
fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
117+
fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
109118
throw_unsup_format!("cannot seek on stderr");
110119
}
111120
}
@@ -553,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
553562
) -> InterpResult<'tcx, i64> {
554563
let this = self.eval_context_mut();
555564

556-
this.check_no_isolation("read")?;
565+
// Isolation check is done via `FileDescriptor` trait.
557566

558567
trace!("Reading from FD {}, size {}", fd, count);
559568

@@ -577,7 +586,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
577586
// `File::read` never returns a value larger than `count`,
578587
// so this cannot fail.
579588
let result = file_descriptor
580-
.read(&mut bytes)?
589+
.read(this.machine.communicate, &mut bytes)?
581590
.map(|c| i64::try_from(c).unwrap());
582591

583592
match result {
@@ -605,9 +614,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
605614
) -> InterpResult<'tcx, i64> {
606615
let this = self.eval_context_mut();
607616

608-
if fd >= 3 {
609-
this.check_no_isolation("write")?;
610-
}
617+
// Isolation check is done via `FileDescriptor` trait.
611618

612619
// Check that the *entire* buffer is actually valid memory.
613620
this.memory.check_ptr_access(
@@ -623,7 +630,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
623630
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
624631
let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?;
625632
let result = file_descriptor
626-
.write(&bytes)?
633+
.write(this.machine.communicate, &bytes)?
627634
.map(|c| i64::try_from(c).unwrap());
628635
this.try_unwrap_io_result(result)
629636
} else {
@@ -639,7 +646,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
639646
) -> InterpResult<'tcx, i64> {
640647
let this = self.eval_context_mut();
641648

642-
this.check_no_isolation("lseek64")?;
649+
// Isolation check is done via `FileDescriptor` trait.
643650

644651
let fd = this.read_scalar(fd_op)?.to_i32()?;
645652
let offset = this.read_scalar(offset_op)?.to_i64()?;
@@ -659,7 +666,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
659666

660667
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
661668
let result = file_descriptor
662-
.seek(seek_from)?
669+
.seek(this.machine.communicate, seek_from)?
663670
.map(|offset| i64::try_from(offset).unwrap());
664671
this.try_unwrap_io_result(result)
665672
} else {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// ignore-windows: No libc on Windows
2+
3+
#![feature(rustc_private)]
4+
5+
extern crate libc;
6+
7+
fn main() -> std::io::Result<()> {
8+
let mut bytes = [0u8; 512];
9+
unsafe {
10+
libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` not available when isolation is enabled
11+
}
12+
Ok(())
13+
}

0 commit comments

Comments
 (0)