Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions nvx-rs/src/guest/console_pending.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,17 @@ fn run(args: &[CString], out: &mut dyn Write, err: &mut dyn Write) -> Result<(),
b"\n",
],
);
CommandError::Operation
};

let flags =
OpenFlags::O_RDONLY | OpenFlags::O_CLOEXEC | OpenFlags::O_NOCTTY | OpenFlags::O_NONBLOCK;
let descriptor = sys::open(device, flags, Mode::empty()).map_err(|error| {
fail(err, b"open", error);
CommandError::Operation
})?;
let pending = sys::console_pending(&descriptor).map_err(|error| {
fail(err, b"ioctl", error);
CommandError::Operation
})?;
descriptor.close().map_err(|error| {
fail(err, b"close", error);
CommandError::Operation
})?;
let descriptor =
sys::open(device, flags, Mode::empty()).map_err(|error| fail(err, b"open", error))?;
let pending = sys::console_pending(&descriptor).map_err(|error| fail(err, b"ioctl", error))?;
descriptor
.close()
.map_err(|error| fail(err, b"close", error))?;
if let Err(errno) = sys::print(out, format!("{pending}\n").as_bytes()) {
let text = errno.desc().as_bytes();
sys::report(err, &[b"nvx-console-pending: write: ", text, b"\n"]);
Expand Down
30 changes: 12 additions & 18 deletions nvx-rs/src/guest/mmio_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,30 @@ fn run(args: &[CString], memory: &CStr, err: &mut dyn Write) -> Result<(), Comma
}

let descriptor = sys::open(memory, OpenFlags::O_RDWR | OpenFlags::O_SYNC, Mode::empty())
.map_err(|error| {
perror(err, b"open /dev/mem", error);
CommandError::Operation
})?;
.map_err(|error| perror(err, b"open /dev/mem", error))?;
let length = NonZeroUsize::new(page_size).expect("a valid page size is nonzero");
let mut mapping = sys::MemoryMapping::shared_read_write(&descriptor, length, page_base)
.map_err(|error| {
perror(err, b"mmap /dev/mem", error);
CommandError::Operation
})?;
.map_err(|error| perror(err, b"mmap /dev/mem", error))?;
if !mapping.write_u32(page_offset as usize, value) {
// The boundary validation above proves this unreachable, but preserve a typed failure if
// the mapping abstraction and validation ever diverge.
sys::report(err, &[b"MMIO write crosses a page boundary\n"]);
return Err(CommandError::Operation);
}
mapping.unmap().map_err(|error| {
perror(err, b"munmap /dev/mem", error);
CommandError::Operation
})?;
descriptor.close().map_err(|error| {
perror(err, b"close /dev/mem", error);
CommandError::Operation
})?;
mapping
.unmap()
.map_err(|error| perror(err, b"munmap /dev/mem", error))?;
descriptor
.close()
.map_err(|error| perror(err, b"close /dev/mem", error))?;
Ok(())
}

/// Reports `errno` as C's `perror(prefix)` does, with `nix`'s description.
fn perror(err: &mut dyn Write, prefix: &[u8], errno: Errno) {
/// Reports `errno` as C's `perror(prefix)` does, with `nix`'s description, and returns the
/// operation failure.
fn perror(err: &mut dyn Write, prefix: &[u8], errno: Errno) -> CommandError {
sys::report(err, &[prefix, b": ", errno.desc().as_bytes(), b"\n"]);
CommandError::Operation
}

#[cfg(test)]
Expand Down
40 changes: 15 additions & 25 deletions nvx-rs/src/guest/reseed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,7 @@ fn reseed(random: &CStr, seed: &[u8; SEED_BYTES], err: &mut dyn Write) -> Result
OpenFlags::O_WRONLY | OpenFlags::O_CLOEXEC,
Mode::empty(),
)
.map_err(|errno| {
let path = random.to_bytes();
let text = errno.desc().as_bytes();
sys::report(err, &[b"nvx-reseed: open ", path, b": ", text, b"\n"]);
CommandError::Operation
})?;
.map_err(|errno| file_failure(err, b"open", random, errno.desc().as_bytes()))?;
sys::reseed_random(&descriptor, seed).map_err(|errno| {
let text = errno.desc().as_bytes();
sys::report(err, &[b"nvx-reseed: random ioctl: ", text, b"\n"]);
Expand All @@ -109,40 +104,35 @@ fn reseed(random: &CStr, seed: &[u8; SEED_BYTES], err: &mut dyn Write) -> Result

/// Reads exactly `bytes.len()` bytes from the file at `path`, without retrying after `EINTR`.
fn read_seed(path: &CStr, bytes: &mut [u8], err: &mut dyn Write) -> Result<(), CommandError> {
let fail = |err: &mut dyn Write, operation: &[u8], reason: &[u8]| {
let path = path.to_bytes();
sys::report(
err,
&[b"nvx-reseed: ", operation, b" ", path, b": ", reason, b"\n"],
);
};
let descriptor = sys::open(
path,
OpenFlags::O_RDONLY | OpenFlags::O_CLOEXEC,
Mode::empty(),
)
.map_err(|errno| {
fail(err, b"open", errno.desc().as_bytes());
CommandError::Operation
})?;
.map_err(|errno| file_failure(err, b"open", path, errno.desc().as_bytes()))?;
let mut offset = 0;
while offset < bytes.len() {
let rest = &mut bytes[offset..];
match descriptor.read(rest) {
Ok(0) => {
fail(err, b"read", b"unexpected end of file");
return Err(CommandError::Operation);
}
Ok(0) => return Err(file_failure(err, b"read", path, b"unexpected end of file")),
Ok(count) => offset += count,
Err(errno) => {
fail(err, b"read", errno.desc().as_bytes());
return Err(CommandError::Operation);
}
Err(errno) => return Err(file_failure(err, b"read", path, errno.desc().as_bytes())),
}
}
Ok(())
}

/// Reports that `operation` on the file at `path` failed for `reason`, and returns the operation
/// failure.
fn file_failure(err: &mut dyn Write, operation: &[u8], path: &CStr, reason: &[u8]) -> CommandError {
let path = path.to_bytes();
sys::report(
err,
&[b"nvx-reseed: ", operation, b" ", path, b": ", reason, b"\n"],
);
CommandError::Operation
}

/// Checks that `previous` is 32 hexadecimal digits that differ from `generation_id`.
fn validate_generation_change(
previous: &[u8],
Expand Down
Loading