-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create sandbox for host file system access #783
base: main
Are you sure you want to change the base?
Conversation
Tasks that should be done:
Additional ideas:
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #783 +/- ##
==========================================
+ Coverage 67.84% 69.37% +1.52%
==========================================
Files 19 20 +1
Lines 2454 2609 +155
==========================================
+ Hits 1665 1810 +145
- Misses 789 799 +10 ☔ View full report in Codecov by Sentry. |
a8ff49a
to
38e7e46
Compare
// In that case, converting a CStr to str will return a Utf8Error. | ||
// | ||
// See: https://nrc.github.io/big-book-ffi/reference/strings.html | ||
let guest_path = unsafe { CStr::from_ptr(requested_path) }.to_str(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd much prefer a checked safe variant here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any better way of doing this in https://doc.rust-lang.org/std/ffi/struct.CStr.html
I presumed to_str()
to be "good enough" given that the type is a Result(&str, Utf8Error)
and basically relies on Rust itself to protect against malicious input, no?
src/vm.rs
Outdated
@@ -149,6 +151,8 @@ impl<VCpuType: VirtualCPU> UhyveVm<VCpuType> { | |||
"gdbstub is only supported with one CPU" | |||
); | |||
|
|||
let file_map = params.mount.as_deref().and_then(UhyveFileMap::new); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reads a bit more complicated than UhyveFileMap::new(¶ms.mount)
if you ask me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reads a bit more complicated than UhyveFileMap::new(¶ms.mount) if you ask me.
Perhaps. But, if the specific parameter is missing, this helps us spare the function call as well as checking whether the parameter is none within UhyveFileMap::new
itself, as it just straight up instantly returns None
in that case with less lines of code.
Addressing the first round of review comments in https://github.com/n0toose/uhyve/commits/sandbox-uhyvefilemap-review-round-1 Will rebase shortly and force-push to |
fb3de59
to
d14cb43
Compare
* Add --mount parameter for "whitelisting" guest_paths and defining their respective filesystem paths on the host FS * Add UhyveFileMap structure * Add sandbox support to open() syscall A few points that could be further worked are unit tests, handling more of the parsing using the clap library directly and performance optimizations. Helped-by: Çağatay Yiğit Şahin <[email protected]> Helped-by: Jonathan Klimt <[email protected]>
Also removes the "Introduction" header, as the header takes more space than the text itself now. Originally introduced in e7869a9.
d14cb43
to
0b243c1
Compare
// Mind the order. | ||
// TODO: Do this work using clap. | ||
let host_path = OsString::from(partsiter.next().unwrap()); | ||
let guest_path = partsiter.next().unwrap().to_owned(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--file-map ""
results in:
thread 'main' panicked at src/isolation.rs:44:43:
called `Option::unwrap()` on a `None` value
This is "by design" for the time being, but suboptimal - there is definitely room for improvement here. Given that I'm targeting main
, should this be improved later down the line or now?
Something that @cagatay-y brought up to me is that using a bunch of .unwrap()
's to make up for invalid inputs is not explicit enough and could result in future problems during a supposed refactoring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More specifically, I think it is possible that if the function signature is changed to return an Option in the future, it is possible that a None caused by an error in parsing may get confused with the None variant that signifies unsandboxed filesystem access.
TODO for this PR:
|
c4d5c24
to
2246517
Compare
cf4b61a
to
6a11855
Compare
src/bin/uhyve.rs
Outdated
/// Paths that the kernel should be able to view, read or write. | ||
/// | ||
/// Files and directories are separated using commas. | ||
/// Desired mount paths must be explicitly defined after a colon. | ||
/// | ||
/// Example: --file_map host_directory:/root/guest_directory,file.txt:/root/my_file.txt | ||
#[arg(value_delimiter = ',')] | ||
#[clap(long, env = "HERMIT_FILE_MAP")] | ||
file_map: Option<Vec<String>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be a better interface, if we have the separate mounts as separate options. Like uhvye -v a.txt:b.txt -v c.txt:/bla/blub.txt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing with the separate options works by default. I removed the delimiter and the environment variable for now, and changed file_map
into mount
(while still referring to a file_map
internally, leaving room for further extensions in the future).
As described in private (after a discussion with @mkroening), the middle ground that I found for this was to call the parameter --mount
again without introducing a short
. -v
is already taken by --verbose
(just like -m
for --file-map
, only -f
isn't taken but that's a weird choice).
Introduces a test for UhyveFileMap. Some refactoring was done so as to keep the two tests, fs-test and uhyvefilemap, in separate files. Some filesystem-related functions were moved into common.rs, because: - we anticipate that they will be necessary for further filesystem-related tests - putting two test functions in a single test (e.g. fs-test) causes the second test to hang for some mysterious reason - more descriptive errors
- Rename --file_map to --mount - Temporarily remove short parameter - Temporarily remove environment variable - Don't split file_map params with commas - Change documentation, remove references to file_map variable
678b672
to
2f5355f
Compare
Currently working on a proof-of-concept for temporary files tracked under this branch, so as to completely remove unfettered host file system access: https://github.com/n0toose/uhyve/tree/sandbox-uhyvefilemap-tempfile I'll squash the work done and move it under |
My approach so far has been to create a temporary directory and perhaps append the file path to UhyveFileMap, but, as I kind of suspected, this may be an awful idea. I'm using the crate
Using a TempDir seems like a solid approach, because it also allows us to use the created path with e.g. Landlock (which can only whitelist existing paths and not append any new paths in retrospect) and reopen files. However, other processes have the ability to write to it, so there's not a considerable security benefit compared to whitelisting
(Source: https://docs.rs/tempfile/latest/tempfile/#security) The middle-ground solution seems to be allowing the kernel to write into a file, but not store it internally if it needs to be reused at a later point. |
I'll figure out how / if this can be sufficiently prevented: https://owasp.org/www-community/vulnerabilities/Insecure_Temporary_File |
A few points that could be further worked are unit tests, handling more of the parsing using the clap library directly and performance optimizations.
Fixes #767