@@ -25,25 +25,28 @@ struct FileHandle {
25
25
trait FileDescriptor < ' tcx > : std:: fmt:: Debug {
26
26
fn as_file_handle ( & self ) -> InterpResult < ' tcx , & FileHandle > ;
27
27
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 > > ;
31
31
}
32
32
33
33
impl < ' tcx > FileDescriptor < ' tcx > for FileHandle {
34
34
fn as_file_handle ( & self ) -> InterpResult < ' tcx , & FileHandle > {
35
35
Ok ( & self )
36
36
}
37
37
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" ) ;
39
40
Ok ( self . file . read ( bytes) )
40
41
}
41
42
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" ) ;
43
45
Ok ( self . file . write ( bytes) )
44
46
}
45
47
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" ) ;
47
50
Ok ( self . file . seek ( offset) )
48
51
}
49
52
}
@@ -53,15 +56,19 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdin {
53
56
throw_unsup_format ! ( "stdin cannot be used as FileHandle" ) ;
54
57
}
55
58
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
+ }
57
64
Ok ( Read :: read ( self , bytes) )
58
65
}
59
66
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 > > {
61
68
throw_unsup_format ! ( "cannot write to stdin" ) ;
62
69
}
63
70
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 > > {
65
72
throw_unsup_format ! ( "cannot seek on stdin" ) ;
66
73
}
67
74
}
@@ -71,11 +78,12 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout {
71
78
throw_unsup_format ! ( "stdout cannot be used as FileHandle" ) ;
72
79
}
73
80
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 > > {
75
82
throw_unsup_format ! ( "cannot read from stdout" ) ;
76
83
}
77
84
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.
79
87
let result = Write :: write ( self , bytes) ;
80
88
// Stdout is buffered, flush to make sure it appears on the
81
89
// screen. This is the write() syscall of the interpreted
@@ -87,7 +95,7 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout {
87
95
Ok ( result)
88
96
}
89
97
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 > > {
91
99
throw_unsup_format ! ( "cannot seek on stdout" ) ;
92
100
}
93
101
}
@@ -97,15 +105,16 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stderr {
97
105
throw_unsup_format ! ( "stdout cannot be used as FileHandle" ) ;
98
106
}
99
107
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 > > {
101
109
throw_unsup_format ! ( "cannot read from stderr" ) ;
102
110
}
103
111
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.
105
114
Ok ( Write :: write ( self , bytes) )
106
115
}
107
116
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 > > {
109
118
throw_unsup_format ! ( "cannot seek on stderr" ) ;
110
119
}
111
120
}
@@ -553,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
553
562
) -> InterpResult < ' tcx , i64 > {
554
563
let this = self . eval_context_mut ( ) ;
555
564
556
- this . check_no_isolation ( "read" ) ? ;
565
+ // Isolation check is done via `FileDescriptor` trait.
557
566
558
567
trace ! ( "Reading from FD {}, size {}" , fd, count) ;
559
568
@@ -577,7 +586,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
577
586
// `File::read` never returns a value larger than `count`,
578
587
// so this cannot fail.
579
588
let result = file_descriptor
580
- . read ( & mut bytes) ?
589
+ . read ( this . machine . communicate , & mut bytes) ?
581
590
. map ( |c| i64:: try_from ( c) . unwrap ( ) ) ;
582
591
583
592
match result {
@@ -605,9 +614,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
605
614
) -> InterpResult < ' tcx , i64 > {
606
615
let this = self . eval_context_mut ( ) ;
607
616
608
- if fd >= 3 {
609
- this. check_no_isolation ( "write" ) ?;
610
- }
617
+ // Isolation check is done via `FileDescriptor` trait.
611
618
612
619
// Check that the *entire* buffer is actually valid memory.
613
620
this. memory . check_ptr_access (
@@ -623,7 +630,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
623
630
if let Some ( file_descriptor) = this. machine . file_handler . handles . get_mut ( & fd) {
624
631
let bytes = this. memory . read_bytes ( buf, Size :: from_bytes ( count) ) ?;
625
632
let result = file_descriptor
626
- . write ( & bytes) ?
633
+ . write ( this . machine . communicate , & bytes) ?
627
634
. map ( |c| i64:: try_from ( c) . unwrap ( ) ) ;
628
635
this. try_unwrap_io_result ( result)
629
636
} else {
@@ -639,7 +646,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
639
646
) -> InterpResult < ' tcx , i64 > {
640
647
let this = self . eval_context_mut ( ) ;
641
648
642
- this . check_no_isolation ( "lseek64" ) ? ;
649
+ // Isolation check is done via `FileDescriptor` trait.
643
650
644
651
let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
645
652
let offset = this. read_scalar ( offset_op) ?. to_i64 ( ) ?;
@@ -659,7 +666,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
659
666
660
667
if let Some ( file_descriptor) = this. machine . file_handler . handles . get_mut ( & fd) {
661
668
let result = file_descriptor
662
- . seek ( seek_from) ?
669
+ . seek ( this . machine . communicate , seek_from) ?
663
670
. map ( |offset| i64:: try_from ( offset) . unwrap ( ) ) ;
664
671
this. try_unwrap_io_result ( result)
665
672
} else {
0 commit comments