-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Sanitize file/directory symlinks in path_symlinks on Windows #1359
Conversation
Do you have any idea if we can add any regression test here? We'd probably need to invoke some low-level Windows API, I think. |
@sunfishcode @kubkon ping, can you please review the change? |
crates/wasi-common/src/old/snapshot_0/sys/windows/hostcalls_impl/fs.rs
Outdated
Show resolved
Hide resolved
let res = if use_dir_symlink { | ||
symlink_dir(&old_path, &new_path) | ||
} else { | ||
symlink_file(&old_path, &new_path) | ||
}; |
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.
Hmm, I'm somewhat confused here. Why do we need this check? Or put it another way, if we're doing this check already here, is creating a dir symlink on error ERROR_NOT_A_REPARSE_POINT
still needed? Is the current approach of try and fail and try something else not working?
Some context on why we've originally had symlink_dir
call after a failing symlink_file
call. As @sunfishcode explained a long time ago, from atomicity point of view, it seems virtually always better to try and fail and then correct, rather than invoke another syscall (in this case via fs::metadata
) which would check what the resource (in this case the symlink) is since in between the check and actual call to symlink_file
etc. the path might change, or whatnot.
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 was unable to encounter ERROR_NOT_A_REPARSE_POINT
while using symlink_file
with the symlink target being a directory. As far as I have tested, the current approach of try and fail doesn't work and a file symlink will always be created.
I agree that try and fail would be preferable, but it appears that CreateSymbolicLinkA
doesn't check if the symlink target is a file or directory. I don't know if ERROR_NOT_A_REPARSE_POINT
may be returned by CreateSymbolicLinkA
at all.
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.
Hmm, sounds like a bug then. I thought that ERROR_NOT_A_REPARSE_POINT
played some role in this, but alas I cannot remember the exact test conditions now. Anyhow, I thought it was covered by our test programs, but from what I understand, you've proved that they were not properly testing this behaviour on Windows? Would the test work fine if we got rid ERROR_NOT_A_REPARSE_POINT
match altogether? And would they still work without both the match and your upfront check?
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.
Oh, and here's another thought. What would happen if we reversed the order of ops, i.e., started with symlink_dir
, and if failed, tried symlink_file
. Would that make it possible to apply the "try-catch" approach rather than an upfront check?
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.
Trying to create a symlink to a file using symlink_dir
succeeds too.
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.
Interesting, but then the symlinks are obviously invalid if the user would try to act on them in say Windows Explorer or whatnot?
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.
Yes, Windows Explorer will show an error, claiming that the directory is invalid.
The patch looks reasonable within the current WASI API. What should we do in WASI itself here? One option I'm thinking about is to replace WASI's |
FWIW, I think that this is the best way to go 👍 |
Subscribe to Label ActionThis issue or pull request has been labeled: "wasi" Users Subscribed to "wasi"To subscribe or unsubscribe from this label, edit the |
I'm not quite sure if it's a good idea. Such API change will make it non-trivial to compile POSIX programs to WASM and run them on Windows. Suppose with have a program written for Linux using
Instead, we could allow an optional hint argument to |
Hmm, I don't think that's what @sunfishcode meant. While WASI embedder would have to provide two syscalls namely |
Isn't wasi-libc eventually compiled to WebAssembly and doesn't it eventually become a part of the resulting wasm binary? With this solution we'd need different syscall selection logic depending on the OS used by the host executing the wasm binary. |
It is, but why would you need different logic at the WASI libc level? I assumed that the libc |
Why should |
Oh sorry, what I meant is that both |
Hmmm, but then, shouldn't we require the implementation of |
My suggestion is that we:
|
Sounds good! |
Based from my experience,
symlink_file
will not return an error if we try to create a file symlink to a directory. I used the following Rust program to verify it:If
dir
is an existing directory, and the binary as executed withcargo run dir target
, the program will succeed and create a file symlink.For details on file vs. directory symlinks on Windows see #1358.
@kubkon: I'm also unsure about the correctness of the following error mappings:
https://github.com/marmistrz/wasmtime/blob/1c61210025c00f0d397be86d752717ab20642f53/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs#L527-L536
In which cases are they expected to be encountered? What's the scenario they're there for?