I am looking at the spec for path_open
and I don't see anything regarding whether it resolves symlinks or not when it internally calls open
. Node.js doesn't seem to call open with O_FOLLOW
and that flag doesn't seem to be checked at all whereas wasmtime and wasmer seem to respect that flag. What is the correct behavior? Am I missing something from the spec?
Resolution to the host path can resolve symlinks but if you say that it should not follow symlinks then the host path will point e.g. to the symlink itself but then the open
call would resolve it. I am not sure what the correct behavior is here.
https://github.com/WebAssembly/wasi-filesystem/pull/127 is a PR adding documentation about this.
Oh! Interesting, thanks for sharing that
So if I understand correctly it means that symlinks in the middle are resolved and the last is not resolved if the last component is a symlink?
From the perspective of a user of wasi-filesystem, symlinks are resolved in all positions, just like in Unix.
In the implementation, unless we have optimizations like Linux's RESOLVE_BENEATH
, we disable host symlink resolution and do it "in userspace" to enforce sandboxing.
Hm interesting, that means that Node.js behaves correctly in that it resolves all symlinks in all components but wasmer doesn't I guess.
wasmtime seems to take into account O_NOFOLLOW
for the open
call whereas Node.js does not.
And if you try to open a file with O_NOFOLLOW
wasmtime throws with "symbolic link loop"
How do I open a symlink then without resolving it?
Just using lstat
then in C?
You can't "open" a symlink itself, only the file it points to
You might want readlink
?
Hm ok got it. Is that default posix behavior?
That you can't open a symlink only the target?
Oh sorry, that was a terrible explanation :sweat_smile:
wasi-libc
should open the file pointed to by a symlink by default, I believe
When I say "you can't open a symlink itself" I mean for example if the symlink doesn't point at an existing file then there isn't anything to open
If your platform isn't following symlinks by default, one option is to resolve them yourself, and a POSIXy way to do that is readlink
Yea that makes sense
Ah right
Cause POSIX will also return with an ELOOP if the last component is a symlink and O_NOFOLLOW was specified
Right
So you can't really open a symlink
Thanks!
So the difference here than with Node.js is that it just doesn't even pass along O_NOFOLLOW
whereas wasmtime does which is why it throws with a "symbolic link loop"
But Node doesn't because it never passes O_NOFOLLOW
What is the right behavior then?
Cause here it also doesn't mention anything of O_NOFOLLOW
https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#fdflags
And those are the flags that Node also passes along
Its on lookupflags
: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-lookupflags-record
(path-flags
in preview2)
Yes, but that only determines the resolution to the host path no?
So in case you'd specify O_NOFOLLOW
then the host path will not be the symlink target but the symlink itself
And that path is then passed to open
which will basically resolve the symlink
Cause O_NOFOLLOW
is not passed to open
as well.
The host gets to decide how to map a host filesystem into a wasi guest filesystem. The most obvious thing to do with symlinks is to convert them into guest symlinks, but this is tricky since a host symlink may try to "escape" the source directory of your mapping, which is why wasmtime does its own symlink resolution
The guest doesn't get to decide what the host does, only whether or not to follow what the host has presented as a symlink
So I guess the answer to "What is the right behavior?" is that the host gets to decide, as long as any symlinks it presents to the guest behave correctly
Ok, so saying that resolving to a host path would not resolve the symlink when O_NOFOLLOW is passed, but open
would resolve it then is also "correct" behavior then?
Cause it's up to the host?
Is that somewhere in the spec that this is up to the host?
It kind of just flows from the big picture with WASI. wasi-filesystem isn't giving you access to "The Filesystem"; it's giving you access to something that can be presented as a filesystem. That might be "The Filesystem" on the host, or it might be something that's not a filesystem at all, or it might be an attenuated version of the host filesystem where everything is presented as readonly, or, indeed, it could even be a view where symlinks are presented as non-symlinks.
Ah okay got it. So the bottom line is that it's really up to the host then?
Thanks all!
Last updated: Dec 23 2024 at 12:05 UTC