Auto merge of #1838 - atsmtat:fs-isolation, r=RalfJung
Fix use of deprecated `check_no_isolation` in posix fs shims Update posix fs shims to use new API `reject_in_isolation`, which allows rejection with error code instead of always forcing abort. Error code chosen for each op is the most appropriate one from the list in corresponding syscall's manual. Updated helper APIs to not use quotes (\`) around input name while preparing the message. This allows callers to pass multi-word string like -- "\`read\` from stdin". Cc https://github.com/rust-lang/miri/issues/1034
This commit is contained in:
commit
1677946d74
@ -328,7 +328,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id),
|
||||
FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id),
|
||||
RejectedIsolatedOp(ref op) =>
|
||||
format!("`{}` was made to return an error due to isolation", op),
|
||||
format!("{} was made to return an error due to isolation", op),
|
||||
};
|
||||
|
||||
let (title, diag_level) = match e {
|
||||
|
@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
RejectOpWith::WarningWithoutBacktrace => {
|
||||
this.tcx
|
||||
.sess
|
||||
.warn(&format!("`{}` was made to return an error due to isolation", op_name));
|
||||
.warn(&format!("{} was made to return an error due to isolation", op_name));
|
||||
Ok(())
|
||||
}
|
||||
RejectOpWith::Warning => {
|
||||
|
@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
|
||||
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("getcwd", reject_with)?;
|
||||
this.reject_in_isolation("`getcwd`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(Pointer::null());
|
||||
}
|
||||
@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let buf = this.read_pointer(buf_op)?;
|
||||
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?;
|
||||
this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(0);
|
||||
}
|
||||
@ -380,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
|
||||
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("chdir", reject_with)?;
|
||||
this.reject_in_isolation("`chdir`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
|
||||
return Ok(-1);
|
||||
@ -408,7 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let path = this.read_path_from_wide_str(this.read_pointer(path_op)?)?;
|
||||
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?;
|
||||
this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
|
||||
return Ok(0);
|
||||
|
@ -4,7 +4,7 @@ use std::convert::{TryFrom, TryInto};
|
||||
use std::fs::{
|
||||
read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir,
|
||||
};
|
||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||
use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||
use std::path::Path;
|
||||
use std::time::SystemTime;
|
||||
|
||||
@ -304,28 +304,6 @@ impl<'tcx> FileHandler {
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||
/// Emulate `stat` or `lstat` on `macos`. This function is not intended to be
|
||||
/// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is
|
||||
/// disabled or if the target OS is the correct one. Please use `macos_stat` or
|
||||
/// `macos_lstat` instead.
|
||||
fn macos_stat_or_lstat(
|
||||
&mut self,
|
||||
follow_symlink: bool,
|
||||
path_op: &OpTy<'tcx, Tag>,
|
||||
buf_op: &OpTy<'tcx, Tag>,
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let path_scalar = this.read_pointer(path_op)?;
|
||||
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
|
||||
|
||||
let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? {
|
||||
Some(metadata) => metadata,
|
||||
None => return Ok(-1),
|
||||
};
|
||||
this.macos_stat_write_buf(metadata, buf_op)
|
||||
}
|
||||
|
||||
fn macos_stat_write_buf(
|
||||
&mut self,
|
||||
metadata: FileMetadata,
|
||||
@ -504,8 +482,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`open`")?;
|
||||
|
||||
let flag = this.read_scalar(flag_op)?.to_i32()?;
|
||||
|
||||
// Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but
|
||||
@ -583,6 +559,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
|
||||
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`open`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let fd = options.open(&path).map(|file| {
|
||||
let fh = &mut this.machine.file_handler;
|
||||
fh.insert_fd(Box::new(FileHandle { file, writable }))
|
||||
@ -594,8 +577,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`fcntl`")?;
|
||||
|
||||
if args.len() < 2 {
|
||||
throw_ub_format!(
|
||||
"incorrect number of arguments for fcntl: got {}, expected at least 2",
|
||||
@ -604,6 +585,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
}
|
||||
let fd = this.read_scalar(&args[0])?.to_i32()?;
|
||||
let cmd = this.read_scalar(&args[1])?.to_i32()?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`fcntl`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
// We only support getting the flags for a descriptor.
|
||||
if cmd == this.eval_libc_i32("F_GETFD")? {
|
||||
// Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
|
||||
@ -785,10 +774,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`unlink`")?;
|
||||
|
||||
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`unlink`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let result = remove_file(path).map(|_| 0);
|
||||
this.try_unwrap_io_result(result)
|
||||
}
|
||||
@ -810,12 +804,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
}
|
||||
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`symlink`")?;
|
||||
|
||||
let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?;
|
||||
let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`symlink`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let result = create_link(&target, &linkpath).map(|_| 0);
|
||||
this.try_unwrap_io_result(result)
|
||||
}
|
||||
@ -827,9 +825,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os("macos", "stat");
|
||||
this.check_no_isolation("`stat`")?;
|
||||
|
||||
let path_scalar = this.read_pointer(path_op)?;
|
||||
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`stat`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
// `stat` always follows symlinks.
|
||||
this.macos_stat_or_lstat(true, path_op, buf_op)
|
||||
let metadata = match FileMetadata::from_path(this, &path, true)? {
|
||||
Some(metadata) => metadata,
|
||||
None => return Ok(-1),
|
||||
};
|
||||
|
||||
this.macos_stat_write_buf(metadata, buf_op)
|
||||
}
|
||||
|
||||
// `lstat` is used to get symlink metadata.
|
||||
@ -840,8 +854,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os("macos", "lstat");
|
||||
this.check_no_isolation("`lstat`")?;
|
||||
this.macos_stat_or_lstat(false, path_op, buf_op)
|
||||
|
||||
let path_scalar = this.read_pointer(path_op)?;
|
||||
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`lstat`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let metadata = match FileMetadata::from_path(this, &path, false)? {
|
||||
Some(metadata) => metadata,
|
||||
None => return Ok(-1),
|
||||
};
|
||||
|
||||
this.macos_stat_write_buf(metadata, buf_op)
|
||||
}
|
||||
|
||||
fn macos_fstat(
|
||||
@ -852,10 +882,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.assert_target_os("macos", "fstat");
|
||||
this.check_no_isolation("`fstat`")?;
|
||||
|
||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`fstat`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
let metadata = match FileMetadata::from_fd(this, fd)? {
|
||||
Some(metadata) => metadata,
|
||||
None => return Ok(-1),
|
||||
@ -874,7 +910,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.assert_target_os("linux", "statx");
|
||||
this.check_no_isolation("`statx`")?;
|
||||
|
||||
let statxbuf_ptr = this.read_pointer(statxbuf_op)?;
|
||||
let pathname_ptr = this.read_pointer(pathname_op)?;
|
||||
@ -924,6 +959,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
)
|
||||
}
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`statx`", reject_with)?;
|
||||
let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? {
|
||||
// since `path` is provided, either absolute or
|
||||
// relative to CWD, `EACCES` is the most relevant.
|
||||
this.eval_libc("EACCES")?
|
||||
} else {
|
||||
// `dirfd` is set to target file, and `path` is empty
|
||||
// (or we would have hit the `throw_unsup_format`
|
||||
// above). `EACCES` would violate the spec.
|
||||
assert!(empty_path_flag);
|
||||
this.eval_libc("EBADF")?
|
||||
};
|
||||
this.set_last_error(ecode)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
// the `_mask_op` paramter specifies the file information that the caller requested.
|
||||
// However `statx` is allowed to return information that was not requested or to not
|
||||
// return information that was requested. This `mask` represents the information we can
|
||||
@ -1032,8 +1085,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`rename`")?;
|
||||
|
||||
let oldpath_ptr = this.read_pointer(oldpath_op)?;
|
||||
let newpath_ptr = this.read_pointer(newpath_op)?;
|
||||
|
||||
@ -1046,6 +1097,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
|
||||
let newpath = this.read_path_from_c_str(newpath_ptr)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`rename`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let result = rename(oldpath, newpath).map(|_| 0);
|
||||
|
||||
this.try_unwrap_io_result(result)
|
||||
@ -1058,8 +1116,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`mkdir`")?;
|
||||
|
||||
#[cfg_attr(not(unix), allow(unused_variables))]
|
||||
let mode = if this.tcx.sess.target.os == "macos" {
|
||||
u32::from(this.read_scalar(mode_op)?.to_u16()?)
|
||||
@ -1069,6 +1125,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
|
||||
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`mkdir`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
#[cfg_attr(not(unix), allow(unused_mut))]
|
||||
let mut builder = DirBuilder::new();
|
||||
|
||||
@ -1088,10 +1151,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`rmdir`")?;
|
||||
|
||||
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`rmdir`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let result = remove_dir(path).map(|_| 0i32);
|
||||
|
||||
this.try_unwrap_io_result(result)
|
||||
@ -1100,10 +1168,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`opendir`")?;
|
||||
|
||||
let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`opendir`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(Scalar::null_ptr(this));
|
||||
}
|
||||
|
||||
let result = read_dir(name);
|
||||
|
||||
match result {
|
||||
@ -1131,10 +1205,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.assert_target_os("linux", "readdir64_r");
|
||||
this.check_no_isolation("`readdir64_r`")?;
|
||||
|
||||
let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`readdir64_r`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| {
|
||||
err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir")
|
||||
})?;
|
||||
@ -1224,10 +1304,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.assert_target_os("macos", "readdir_r");
|
||||
this.check_no_isolation("`readdir_r`")?;
|
||||
|
||||
let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`readdir_r`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| {
|
||||
err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir")
|
||||
})?;
|
||||
@ -1313,10 +1399,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`closedir`")?;
|
||||
|
||||
let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`closedir`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) {
|
||||
drop(dir_iter);
|
||||
Ok(0)
|
||||
@ -1332,10 +1423,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`ftruncate64`")?;
|
||||
|
||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||
let length = this.read_scalar(length_op)?.to_i64()?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`ftruncate64`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
|
||||
// FIXME: Support ftruncate64 for all FDs
|
||||
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
|
||||
@ -1367,9 +1464,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`fsync`")?;
|
||||
|
||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`fsync`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
|
||||
// FIXME: Support fsync for all FDs
|
||||
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
|
||||
@ -1383,9 +1486,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`fdatasync`")?;
|
||||
|
||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`fdatasync`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
|
||||
// FIXME: Support fdatasync for all FDs
|
||||
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
|
||||
@ -1405,8 +1514,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("`sync_file_range`")?;
|
||||
|
||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||
let offset = this.read_scalar(offset_op)?.to_i64()?;
|
||||
let nbytes = this.read_scalar(nbytes_op)?.to_i64()?;
|
||||
@ -1426,6 +1533,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`sync_file_range`", reject_with)?;
|
||||
// Set error code as "EBADF" (bad fd)
|
||||
return this.handle_not_found();
|
||||
}
|
||||
|
||||
if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
|
||||
// FIXME: Support sync_data_range for all FDs
|
||||
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
|
||||
@ -1444,12 +1558,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, i64> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.check_no_isolation("readlink")?;
|
||||
|
||||
let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?;
|
||||
let buf = this.read_pointer(buf_op)?;
|
||||
let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?;
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`readlink`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let result = std::fs::read_link(pathname);
|
||||
match result {
|
||||
Ok(resolved) => {
|
||||
|
54
tests/run-pass/fs_with_isolation.rs
Normal file
54
tests/run-pass/fs_with_isolation.rs
Normal file
@ -0,0 +1,54 @@
|
||||
// ignore-windows: File handling is not implemented yet
|
||||
// compile-flags: -Zmiri-isolation-error=warn-nobacktrace
|
||||
// normalize-stderr-test "(stat(x)?)" -> "$$STAT"
|
||||
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::unix;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Error, ErrorKind};
|
||||
|
||||
fn main() {
|
||||
// test `open`
|
||||
assert_eq!(File::create("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
|
||||
// test `fcntl`
|
||||
unsafe {
|
||||
assert_eq!(libc::fcntl(1, libc::F_DUPFD, 0), -1);
|
||||
assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EPERM));
|
||||
}
|
||||
|
||||
// test `unlink`
|
||||
assert_eq!(fs::remove_file("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
|
||||
// test `symlink`
|
||||
assert_eq!(unix::fs::symlink("foo.txt", "foo_link.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
|
||||
// test `readlink`
|
||||
let symlink_c_str = CString::new("foo.txt").unwrap();
|
||||
let mut buf = vec![0; "foo_link.txt".len() + 1];
|
||||
unsafe {
|
||||
assert_eq!(libc::readlink(symlink_c_str.as_ptr(), buf.as_mut_ptr(), buf.len()), -1);
|
||||
assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES));
|
||||
}
|
||||
|
||||
// test `stat`
|
||||
assert_eq!(fs::metadata("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES));
|
||||
|
||||
// test `rename`
|
||||
assert_eq!(fs::rename("a.txt", "b.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
|
||||
// test `mkdir`
|
||||
assert_eq!(fs::create_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
|
||||
// test `rmdir`
|
||||
assert_eq!(fs::remove_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
|
||||
// test `opendir`
|
||||
assert_eq!(fs::read_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied);
|
||||
assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES));
|
||||
}
|
20
tests/run-pass/fs_with_isolation.stderr
Normal file
20
tests/run-pass/fs_with_isolation.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
warning: `open` was made to return an error due to isolation
|
||||
|
||||
warning: `fcntl` was made to return an error due to isolation
|
||||
|
||||
warning: `unlink` was made to return an error due to isolation
|
||||
|
||||
warning: `symlink` was made to return an error due to isolation
|
||||
|
||||
warning: `readlink` was made to return an error due to isolation
|
||||
|
||||
warning: `$STAT` was made to return an error due to isolation
|
||||
|
||||
warning: `rename` was made to return an error due to isolation
|
||||
|
||||
warning: `mkdir` was made to return an error due to isolation
|
||||
|
||||
warning: `rmdir` was made to return an error due to isolation
|
||||
|
||||
warning: `opendir` was made to return an error due to isolation
|
||||
|
Loading…
x
Reference in New Issue
Block a user