-
Notifications
You must be signed in to change notification settings - Fork 259
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
sysfs: clean paths lexically before use #2322
Conversation
Signed-off-by: Nuno Cruces <[email protected]>
Signed-off-by: Nuno Cruces <[email protected]>
Sorry for coming to this so late, was just randomly thinking about this for some reason even before seeing this new PR. I think to correctly handle symlinks, we would need to recognize them when opening/statting and use the resolved name recursively through the WASI apis rather than directly opening, likely with a recursion limit if not real cycle detector though that's likely too much. I think cleaning paths still doesn't prevent the case where a symlink outside the sandbox is present in the mounted files. Naturally this is a far smaller issue than being to create the symlink in wasm itself. I understand that the WASI implementation won't be fully hardened which makes sense, so the above might be going too far. But just wanted to share in case it didn't seem too hard, but probably is. |
Sorry I noticed the comment is about 3) in the issue, and is probably too much so no worries |
No worries. Yeah, that sounds like doing path resolution ourselves, maybe with some shortcut. But I honestly don't think there's any shortcut possible. ISTM that to do path resolution, you really need to start at the root (there's no CWD in WASI preview 1), then for each path element do That's a lot of syscalls, and a lot of stuff to get wrong, especially if you're doing this for sandboxing/security sake. |
I might not understand the syscalls right, but I didn't really expect CWD to be needed. I thought it could be something like this pseudocode similar to checking whether opening a file matches isDir https://github.com/tetratelabs/wazero/blob/main/imports/wasi_snapshot_preview1/fs.go#L1619 f, ok := fsc.LookupFile(newFD)
if symlinkTarget := f.File.SymlinkTarget(); symlinkTarget != nil { // Calls `os.Lstat` or `os.Readlink`
_ = fsc.CloseFile(newFD)
return doPathOpen(symlinkTarget, etc...) // The contents of pathOpen after pathName is computed from wasm arg
} The biggest problem is that it seems like a fairly large change to have to add symlink lstat to the |
CWD is not needed because WASI preview 1 has no concept of CWD. By the time you get to those lines the file is already opened, and path resolution already happened. The file is opened here: wazero/imports/wasi_snapshot_preview1/fs.go Line 1610 in 111c51a
The lines you're quoting are really only checking if you opened what you wanted to open (a directory) after the fact. That's good because “ask for forgiveness instead of permission” avoids a race. But this doesn't work for symlinks for two reasons:
|
This is intended to close #2321.
W.r.t. security, after consulting the other maintainers, we must say that fully sandboxing our WASI implementation is beyond the current scope of the project. This will be made explicit in the documentation.
We consider Wasm a mature specification, and security issues against our implementation of it will be taken seriously. WASI is not as mature, nor is our implementation of WASI preview 1.
We also provide advanced enough APIs that you can use to implement your own, better locked down, alternative to our WASI implementation.
That said, this PR still sides with breaking POSIX path resolution semantics in WASI vs. allowing trivial root mount escapes, by using
path.Clean
to lexically clean all paths before use.This is a judgement call.
Handling paths lexically is easier to reason about, easier to port, and idiomatic Go. Go provides
path.Clean
andfilepath.Clean
;fs.FS
is even stricter disallowing..
entirely. It's also unlikely to break well, behaving, useful applications.