Skip to content

Commit 068a699

Browse files
author
Jakub Konka
committed
Check if filetype of OS handle matches WASI filetype when creating
It seems prudent to check if the passed in `File` instance is of type matching that of the requested WASI filetype. In other words, we'd like to avoid situations where `OsFile` is created from a pipe.
1 parent a367cec commit 068a699

File tree

10 files changed

+70
-43
lines changed

10 files changed

+70
-43
lines changed

crates/wasi-common/src/ctx.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::entry::{Entry, EntryHandle};
22
use crate::fdpool::FdPool;
33
use crate::handle::Handle;
4-
use crate::sys::osfile::{OsFile, OsFileExt};
4+
use crate::sys::osdir::OsDir;
5+
use crate::sys::osother::{OsOther, OsOtherExt};
56
use crate::sys::stdio::{Stdio, StdioExt};
67
use crate::virtfs::{VirtualDir, VirtualDirEntry};
78
use crate::wasi::types;
@@ -120,9 +121,9 @@ pub struct WasiCtxBuilder {
120121
impl WasiCtxBuilder {
121122
/// Builder for a new `WasiCtx`.
122123
pub fn new() -> Self {
123-
let stdin = Some(PendingEntry::Thunk(OsFile::from_null));
124-
let stdout = Some(PendingEntry::Thunk(OsFile::from_null));
125-
let stderr = Some(PendingEntry::Thunk(OsFile::from_null));
124+
let stdin = Some(PendingEntry::Thunk(OsOther::from_null));
125+
let stdout = Some(PendingEntry::Thunk(OsOther::from_null));
126+
let stderr = Some(PendingEntry::Thunk(OsOther::from_null));
126127

127128
Self {
128129
stdin,
@@ -253,7 +254,7 @@ impl WasiCtxBuilder {
253254
pub fn preopened_dir<P: AsRef<Path>>(&mut self, dir: File, guest_path: P) -> &mut Self {
254255
self.preopens.as_mut().unwrap().push((
255256
guest_path.as_ref().to_owned(),
256-
<Box<dyn Handle>>::try_from(dir).expect("valid handle"),
257+
Box::new(OsDir::try_from(dir).expect("valid OsDir handle")),
257258
));
258259
self
259260
}
@@ -345,8 +346,8 @@ impl WasiCtxBuilder {
345346
.ok_or(WasiCtxBuilderError::TooManyFilesOpen)?
346347
}
347348
PendingEntry::File(f) => {
348-
let handle = <Box<dyn Handle>>::try_from(f)?;
349-
let handle = EntryHandle::from(handle);
349+
let handle = OsOther::try_from(f)?;
350+
let handle = EntryHandle::new(handle);
350351
let entry = Entry::new(handle);
351352
entries
352353
.insert(entry)

crates/wasi-common/src/entry.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ use std::rc::Rc;
88
pub(crate) struct EntryHandle(Rc<dyn Handle>);
99

1010
impl EntryHandle {
11+
pub(crate) fn new<T: Handle + 'static>(handle: T) -> Self {
12+
Self(Rc::new(handle))
13+
}
14+
1115
pub(crate) fn get(&self) -> Self {
1216
Self(Rc::clone(&self.0))
1317
}

crates/wasi-common/src/sys/osfile.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ use std::fs::File;
88
use std::io::{self, Read, Seek, SeekFrom, Write};
99
use std::ops::Deref;
1010

11-
pub(crate) trait OsFileExt {
12-
/// Create `OsFile` as `dyn Handle` from null device.
13-
fn from_null() -> io::Result<Box<dyn Handle>>;
14-
}
15-
1611
#[derive(Debug)]
1712
pub(crate) struct OsFile {
1813
rights: Cell<HandleRights>,

crates/wasi-common/src/sys/osother.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ use std::fs::File;
1010
use std::io::{self, Read, Write};
1111
use std::ops::Deref;
1212

13+
pub(crate) trait OsOtherExt {
14+
/// Create `OsOther` as `dyn Handle` from null device.
15+
fn from_null() -> io::Result<Box<dyn Handle>>;
16+
}
17+
1318
#[derive(Debug)]
1419
pub(crate) struct OsOther {
1520
file_type: Filetype,

crates/wasi-common/src/sys/unix/osdir.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ impl TryFrom<File> for OsDir {
1212
type Error = io::Error;
1313

1414
fn try_from(file: File) -> io::Result<Self> {
15+
let ft = file.metadata()?.file_type();
16+
if !ft.is_dir() {
17+
return Err(io::Error::from_raw_os_error(libc::EINVAL));
18+
}
1519
let rights = get_rights(&file)?;
1620
let handle = unsafe { OsHandle::from_raw_fd(file.into_raw_fd()) };
1721
Self::new(rights, handle)
Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
use super::oshandle::OsHandle;
2-
use crate::handle::{Handle, HandleRights};
3-
use crate::sys::osfile::{OsFile, OsFileExt};
2+
use crate::handle::HandleRights;
3+
use crate::sys::osfile::OsFile;
44
use crate::wasi::{types, RightsExt};
55
use std::convert::TryFrom;
6-
use std::fs::{File, OpenOptions};
6+
use std::fs::File;
77
use std::io;
88
use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd};
99

1010
impl TryFrom<File> for OsFile {
1111
type Error = io::Error;
1212

1313
fn try_from(file: File) -> io::Result<Self> {
14+
let ft = file.metadata()?.file_type();
15+
if !ft.is_file() {
16+
return Err(io::Error::from_raw_os_error(libc::EINVAL));
17+
}
1418
let rights = get_rights(&file)?;
1519
let handle = unsafe { OsHandle::from_raw_fd(file.into_raw_fd()) };
1620
Ok(Self::new(rights, handle))
@@ -32,14 +36,3 @@ fn get_rights(file: &File) -> io::Result<HandleRights> {
3236
}
3337
Ok(rights)
3438
}
35-
36-
impl OsFileExt for OsFile {
37-
fn from_null() -> io::Result<Box<dyn Handle>> {
38-
let file = OpenOptions::new()
39-
.read(true)
40-
.write(true)
41-
.open("/dev/null")?;
42-
let file = Self::try_from(file)?;
43-
Ok(Box::new(file))
44-
}
45-
}

crates/wasi-common/src/sys/unix/osother.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use super::get_file_type;
22
use super::oshandle::OsHandle;
3-
use crate::handle::HandleRights;
4-
use crate::sys::osother::OsOther;
3+
use crate::handle::{Handle, HandleRights};
4+
use crate::sys::osother::{OsOther, OsOtherExt};
55
use crate::wasi::{types, RightsExt};
66
use std::convert::TryFrom;
7-
use std::fs::File;
7+
use std::fs::{File, OpenOptions};
88
use std::io;
99
use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd};
1010

@@ -13,6 +13,9 @@ impl TryFrom<File> for OsOther {
1313

1414
fn try_from(file: File) -> io::Result<Self> {
1515
let file_type = get_file_type(&file)?;
16+
if file_type == types::Filetype::RegularFile || file_type == types::Filetype::Directory {
17+
return Err(io::Error::from_raw_os_error(libc::EINVAL));
18+
}
1619
let rights = get_rights(&file, &file_type)?;
1720
let handle = unsafe { OsHandle::from_raw_fd(file.into_raw_fd()) };
1821
Ok(Self::new(file_type, rights, handle))
@@ -57,3 +60,14 @@ fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result<HandleRigh
5760
}
5861
Ok(rights)
5962
}
63+
64+
impl OsOtherExt for OsOther {
65+
fn from_null() -> io::Result<Box<dyn Handle>> {
66+
let file = OpenOptions::new()
67+
.read(true)
68+
.write(true)
69+
.open("/dev/null")?;
70+
let file = Self::try_from(file)?;
71+
Ok(Box::new(file))
72+
}
73+
}

crates/wasi-common/src/sys/windows/osdir.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ impl TryFrom<File> for OsDir {
2424
type Error = io::Error;
2525

2626
fn try_from(file: File) -> io::Result<Self> {
27+
let ft = file.metadata()?.file_type();
28+
if !ft.is_dir() {
29+
return Err(io::Error::from_raw_os_error(libc::EINVAL));
30+
}
2731
let rights = get_rights(&file)?;
2832
let handle = unsafe { OsHandle::from_raw_handle(file.into_raw_handle()) };
2933
Self::new(rights, handle)

crates/wasi-common/src/sys/windows/osfile.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
use super::oshandle::OsHandle;
2-
use crate::handle::{Handle, HandleRights};
3-
use crate::sys::osfile::{OsFile, OsFileExt};
2+
use crate::handle::HandleRights;
3+
use crate::sys::osfile::OsFile;
44
use crate::wasi::{types, RightsExt};
55
use std::convert::TryFrom;
6-
use std::fs::{File, OpenOptions};
6+
use std::fs::File;
77
use std::io;
88
use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle};
99

1010
impl TryFrom<File> for OsFile {
1111
type Error = io::Error;
1212

1313
fn try_from(file: File) -> io::Result<Self> {
14+
let ft = file.metadata()?.file_type();
15+
if !ft.is_file() {
16+
return Err(io::Error::from_raw_os_error(libc::EINVAL));
17+
}
1418
let rights = get_rights(&file)?;
1519
let handle = unsafe { OsHandle::from_raw_handle(file.into_raw_handle()) };
1620
Ok(Self::new(rights, handle))
@@ -32,11 +36,3 @@ fn get_rights(file: &File) -> io::Result<HandleRights> {
3236
}
3337
Ok(rights)
3438
}
35-
36-
impl OsFileExt for OsFile {
37-
fn from_null() -> io::Result<Box<dyn Handle>> {
38-
let file = OpenOptions::new().read(true).write(true).open("NUL")?;
39-
let file = Self::try_from(file)?;
40-
Ok(Box::new(file))
41-
}
42-
}

crates/wasi-common/src/sys/windows/osother.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use super::get_file_type;
22
use super::oshandle::OsHandle;
3-
use crate::handle::HandleRights;
4-
use crate::sys::osother::OsOther;
3+
use crate::handle::{Handle, HandleRights};
4+
use crate::sys::osother::{OsOther, OsOtherExt};
55
use crate::wasi::{types, RightsExt};
66
use std::convert::TryFrom;
7-
use std::fs::File;
7+
use std::fs::{File, OpenOptions};
88
use std::io;
99
use std::os::windows::prelude::{FromRawHandle, IntoRawHandle};
1010

@@ -13,6 +13,9 @@ impl TryFrom<File> for OsOther {
1313

1414
fn try_from(file: File) -> io::Result<Self> {
1515
let file_type = get_file_type(&file)?;
16+
if file_type == types::Filetype::RegularFile || file_type == types::Filetype::Directory {
17+
return Err(io::Error::from_raw_os_error(libc::EINVAL));
18+
}
1619
let rights = get_rights(&file_type)?;
1720
let handle = unsafe { OsHandle::from_raw_handle(file.into_raw_handle()) };
1821
Ok(Self::new(file_type, rights, handle))
@@ -39,3 +42,11 @@ fn get_rights(file_type: &types::Filetype) -> io::Result<HandleRights> {
3942
let rights = HandleRights::new(base, inheriting);
4043
Ok(rights)
4144
}
45+
46+
impl OsOtherExt for OsOther {
47+
fn from_null() -> io::Result<Box<dyn Handle>> {
48+
let file = OpenOptions::new().read(true).write(true).open("NUL")?;
49+
let file = Self::try_from(file)?;
50+
Ok(Box::new(file))
51+
}
52+
}

0 commit comments

Comments
 (0)