Skip to content
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

Add a test and a hotfix for path_open read rights #618

Closed
wants to merge 16 commits into from

Conversation

marmistrz
Copy link
Contributor

@marmistrz marmistrz commented Nov 21, 2019

With current implementation new file descriptors may have RIGHT_FD_READ even after it was dropped on the parent descriptor beforehand. This makes it possible to read the file content when it should be denied. (on Unix)

Connected with #570 & #617.

@marmistrz
Copy link
Contributor Author

I created a hotfix, but this is blocked by #632.

sunfishcode and others added 9 commits November 26, 2019 22:26
Add a routine for obtaining an `OsFile` containing a file descriptor for
stdin/stdout/stderr so that we can do fd_fdstat_get on them.
This commits renames `OsFile` to `OsHandle` which seems to make
more sense semantically as it is permitted to hold a valid OS handle
to OS entities other than simply file/dir (e.g., socket, stream, etc.).
As such, this commit also renames methods on `Descriptor` struct
from `as_actual_file` to `as_file` as this in reality does pertain
ops on FS entities such as files/dirs, and `as_file` to `as_os_handle`
as in this case it can be anything, from file, through a socket, to
a stream.
To prevent a `ManuallyDrop<OsHandleRef>` from outliving the resource it
holds on to, create an `OsHandleRef` class parameterized on the lifetime
of the `Descriptor`.
While we are waiting for the Rust toolchain to use the new ABI,
I thought it might be useful to sync `snapshot_0` with the latest
code in `wasi-common` "upstream". This mainly includes the latest
refactoring effort to unify the machinery for `fd_readdir` between
Linux, Windows and BSD.
@marmistrz marmistrz changed the title Add a test for path_open read rights Add a test and a hotfix for path_open read rights Nov 28, 2019
Also, remove a no-op restriction of rights to the ones returned by
`determine_type_rights`. It was redundant, because `FdEntry:from`
internally also called `determine_type_rights` and only dropped some of
them.
@marmistrz
Copy link
Contributor Author

The hotfix works for me locally and is ready for review. See the commit message for the reason why determine_type_rights was removed.
cc @kubkon @sunfishcode @peterhuene

This PR builds upon #647, hence the merge conflicts.

@marmistrz
Copy link
Contributor Author

@kubkon @sunfishcode @peterhuene could you please review this change?

@peterhuene peterhuene added the wasi:impl Issues pertaining to WASI implementation in Wasmtime label Dec 16, 2019
Copy link
Member

@peterhuene peterhuene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me! Some minor feedback provided. Let's get @kubkon and @sunfishcode's feedback before moving forward.

@@ -0,0 +1,96 @@
use std::{env, process};
use wasi_old::wasi_unstable;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we update this to use the wasi crate given it's a new test program?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm quite confused how to cope with the snapshot stuff or wasi vs wasi_old, so any input is appreciated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an example, the test program added for #711 uses the wasi crate, which will currently target the preview1 impl.

I assume we'll be moving all the test programs over to the wasi crate sooner or later.

Additionally, I think we'll want dedicated tests targeted at previous previews for the sole purpose of testing backwards compatibility for WASI interface changes so we don't have to snapshot all of the test programs themselves for every snapshot of WASI, but perhaps @sunfishcode @alexcrichton @kubkon know more regarding that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the current trend is to use wasi in tests as @peterhuene suggested. As far as I remember, @alexcrichton has already started porting some of the tests to using wasi instead of wasi_old.

In the future, I definitely agree we should have a way to test different versions of the snapshot, preferably in a way that's automatic.

@@ -52,3 +52,32 @@ pub unsafe fn cleanup_file(dir_fd: wasi_unstable::Fd, file_name: &str) {
pub unsafe fn close_fd(fd: wasi_unstable::Fd) {
assert!(wasi_unstable::fd_close(fd).is_ok(), "closing a file");
}

// Returns: (rights_base, rights_inheriting)
pub unsafe fn fd_get_rights(fd: wasi_unstable::Fd) -> (wasi_unstable::Rights, wasi_unstable::Rights) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function may not be necessary if we do update the test propram to use wasi given how it greatly simplifies things.

(fdstat.fs_rights_base, fdstat.fs_rights_inheriting)
}

pub unsafe fn drop_rights(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise for this function, although a utility function that does the same thing using wasi would make sense.

// This should not be needed, but currently determine_type_and_access_rights,
// which is used by FdEntry::from, may grant more rights than requested.
//
// This is a hotfix. It needs to be discussed whether or not `path_open`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have that discussion here so we don't add a comment with this is a hotfix.

I think @sunfishcode is more qualified to answer this than I. On the surface it sounds wrong to me, though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could change "This is a hotfix." for "TODO"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intend to remove the it needs to be discussed part when we'll have discussed it ;)

@sunfishcode
Copy link
Member

The documentation for path_open says that we're allowed to return fewer rights if and only if those rights don't apply to the type of file being opened. So if the user has requested rights that are not in the parent directory's inheriting set, we should return an ERRNO_NOTCAPABLE rather than silently return a file descriptor with those rights masked out.

Code which doesn't know exactly which rights it will need can do an fd_fdstat on the parent file descriptor; this is the case in WASI libc, and it already does do this.

@marmistrz
Copy link
Contributor Author

@sunfishcode but the documentation says nothing about granting more rights than requested. Those rights were not requested by the user, but were implicitly granted by the runtime, as per #617. The file was opened as

     let status = wasi_path_open(dir_fd, 0, TEST_FILENAME, 0, 0, 0, 0, &mut fd); 

and we still have the right to fd_read.

The resaon is that, in the current codebase, FdEntry::from will call determine_type_and_access_rights internally to infer the access rights from the fd open mode.

@sunfishcode
Copy link
Member

We shouldn't grant more rights than the user requests. I think the algorithm for path_open should be:

  • start with the rights_base and rights_inheriting parameters passed in
  • if either of those has any flag set that isn't set in dirfd's rights_inheriting field, return ERRNO_NOTCAPABLE.
  • then, silently clear any flags not set in the sets computed by determine_type_rights

@marmistrz
Copy link
Contributor Author

I agree that such semantics are desirable.

This in particular means that some of the tests are incorrect. For instance in file_allocate.rs the fd is opened without explicit RIGHT_FD_ALLOCATE:

let status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);

but later on fd_allocate is expected to succeed:
assert!(
wasi_unstable::fd_allocate(file_fd, 0, 100).is_ok(),
"allocating size"
);

I'll change tests like this one to explicitly pass in the required rights.


One tricky question: if path_open is called with O_TRUNC, do we require the caller to pass in RIGHT_PATH_FILESTAT_SET_SIZE in fs_rights_base or is it enough to only have the right on the parent file descriptor. In other words, should we expect this call to succeed:

status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_TRUNC,
0,
0,
0,
&mut file_fd,
);

or should we rather change it to:

        status = wasi_path_open(
            dir_fd,
            0,
            "file",
            wasi_unstable::O_TRUNC,
            wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE,
            0,
            0,
            &mut file_fd,
        );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasi:impl Issues pertaining to WASI implementation in Wasmtime
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants