Initial support for securing tty I/O. (#684)

* Initial support for securing tty I/O.

* Update the tests.

* Fix warnings

* Update crates/wasi-common/src/fdentry.rs

Co-Authored-By: Jakub Konka <jakub.konka@golem.network>

* Properly sandbox stderr.

* Document why the scratch buffer is 4 elements long.

* Update crates/wasi-common/src/sandboxed_tty_writer.rs

Co-Authored-By: Jakub Konka <jakub.konka@golem.network>

* Update crates/wasi-common/src/sandboxed_tty_writer.rs

Co-Authored-By: Jakub Konka <jakub.konka@golem.network>

* Add comments explaining how we report the number of bytes written.

* Always sanitize stderr.

* Port the changes to the snapshot_0 directory.

* Fix snapshot_0 compilation error.

* Replace the scratch buffer with a temporary buffer.

* Update crates/wasi-common/src/sandboxed_tty_writer.rs

Co-Authored-By: bjorn3 <bjorn3@users.noreply.github.com>

* Format with latest stable rustfmt.

Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
Co-authored-by: bjorn3 <bjorn3@users.noreply.github.com>
This commit is contained in:
Dan Gohman
2020-01-02 04:53:26 -06:00
committed by Jakub Konka
parent 1f8921ef09
commit 1d810a5de9
6 changed files with 243 additions and 16 deletions

View File

@@ -162,6 +162,14 @@ impl FdEntry {
Ok(())
}
}
/// Test whether this descriptor is considered a tty within WASI.
/// Note that since WASI itself lacks an `isatty` syscall and relies
/// on a conservative approximation, we use the same approximation here.
pub(crate) fn isatty(&self) -> bool {
self.file_type == wasi::__WASI_FILETYPE_CHARACTER_DEVICE
&& (self.rights_base & (wasi::__WASI_RIGHTS_FD_SEEK | wasi::__WASI_RIGHTS_FD_TELL)) == 0
}
}
/// This allows an `OsHandle` to be temporarily borrowed from a

View File

@@ -8,10 +8,12 @@ use crate::old::snapshot_0::sys::fdentry_impl::determine_type_rights;
use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::path_open_rights;
use crate::old::snapshot_0::sys::{host_impl, hostcalls_impl};
use crate::old::snapshot_0::{helpers, host, wasi, wasi32, Error, Result};
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
use filetime::{set_file_handle_times, FileTime};
use log::trace;
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::ops::DerefMut;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub(crate) unsafe fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasi::__wasi_fd_t) -> Result<()> {
@@ -160,7 +162,7 @@ pub(crate) unsafe fn fd_read(
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_READ, 0)?
{
Descriptor::OsHandle(file) => file.read_vectored(&mut iovs),
Descriptor::Stdin => io::stdin().lock().read_vectored(&mut iovs),
Descriptor::Stdin => io::stdin().read_vectored(&mut iovs),
_ => return Err(Error::EBADF),
};
@@ -357,21 +359,35 @@ pub(crate) unsafe fn fd_write(
let iovs: Vec<io::IoSlice> = iovs.iter().map(|vec| host::ciovec_to_host(vec)).collect();
// perform unbuffered writes
let host_nwritten = match wasi_ctx
.get_fd_entry_mut(fd)?
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_WRITE, 0)?
{
Descriptor::OsHandle(file) => file.write_vectored(&iovs)?,
let entry = wasi_ctx.get_fd_entry_mut(fd)?;
let isatty = entry.isatty();
let desc = entry.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_WRITE, 0)?;
let host_nwritten = match desc {
Descriptor::OsHandle(file) => {
if isatty {
SandboxedTTYWriter::new(file.deref_mut()).write_vectored(&iovs)?
} else {
file.write_vectored(&iovs)?
}
}
Descriptor::Stdin => return Err(Error::EBADF),
Descriptor::Stdout => {
// lock for the duration of the scope
let stdout = io::stdout();
let mut stdout = stdout.lock();
let nwritten = stdout.write_vectored(&iovs)?;
let nwritten = if isatty {
SandboxedTTYWriter::new(&mut stdout).write_vectored(&iovs)?
} else {
stdout.write_vectored(&iovs)?
};
stdout.flush()?;
nwritten
}
Descriptor::Stderr => io::stderr().lock().write_vectored(&iovs)?,
// Always sanitize stderr, even if it's not directly connected to a tty,
// because stderr is meant for diagnostics rather than binary output,
// and may be redirected to a file which could end up being displayed
// on a tty later.
Descriptor::Stderr => SandboxedTTYWriter::new(&mut io::stderr()).write_vectored(&iovs)?,
};
trace!(" | *nwritten={:?}", host_nwritten);