Skip to content

Commit 4c1beb2

Browse files
committed
Ensure buffer for reading from Stdin is smaller than machine usize
Also, set appropriate error code on failure
1 parent 74ff4f8 commit 4c1beb2

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

src/shims/posix/foreign_items.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::convert::TryFrom;
2+
use std::io::{self, Read, Write};
23

34
use log::trace;
45

@@ -11,6 +12,7 @@ use shims::posix::fs::EvalContextExt as _;
1112
use shims::posix::sync::EvalContextExt as _;
1213
use shims::posix::thread::EvalContextExt as _;
1314

15+
1416
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
1517
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
1618
fn emulate_foreign_item_by_name(
@@ -67,10 +69,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
6769
let buf = this.read_scalar(buf)?.not_undef()?;
6870
let count = this.read_scalar(count)?.to_machine_usize(this)?;
6971
let result = if fd == 0 {
70-
use std::io::{self, Read};
7172

7273
this.check_no_isolation("read")?;
7374

75+
// We cap the number of read bytes to the largest
76+
// value that we are able to fit in both the
77+
// host's and target's `isize`. This saves us from
78+
// having to handle overflows later.
79+
let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64);
80+
// This can never fail because `count` was capped
81+
// to be smaller than `isize::MAX`.
82+
let count = isize::try_from(count).unwrap();
83+
84+
// We want to read at most `count` bytes. We are
85+
// sure that `count` is not negative because it
86+
// was a target's `usize`. Also we are sure that
87+
// its smaller than `usize::MAX` because it is a
88+
// host's `isize`.
7489
let mut buffer = vec![0; count as usize];
7590
let res = io::stdin()
7691
.read(&mut buffer)
@@ -83,8 +98,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
8398
this.memory.write_bytes(buf, buffer)?;
8499
i64::try_from(bytes).unwrap()
85100
},
86-
// FIXME: set errno to appropriate value
87-
Err(_) => -1,
101+
Err(e) => {
102+
this.set_last_error_from_io_error(e)?;
103+
-1
104+
},
88105
}
89106
} else if fd == 1 || fd == 2 {
90107
throw_unsup_format!("cannot read from stdout/stderr")
@@ -103,7 +120,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
103120
throw_unsup_format!("cannot write to stdin")
104121
} else if fd == 1 || fd == 2 {
105122
// stdout/stderr
106-
use std::io::{self, Write};
107123

108124
let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?;
109125
// We need to flush to make sure this actually appears on the screen

0 commit comments

Comments
 (0)