-
Notifications
You must be signed in to change notification settings - Fork 305
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
rofiles-fuse: Fix lchown() (and pro-actively NOFOLLOW) #1137
Conversation
src/rofiles-fuse/main.c
Outdated
@@ -231,7 +231,7 @@ callback_chmod (const char *path, mode_t mode) | |||
{ | |||
path = ENSURE_RELPATH (path); | |||
VERIFY_WRITE(path); | |||
if (fchmodat (basefd, path, mode, 0) != 0) | |||
if (fchmodat (basefd, path, mode, AT_SYMLINK_NOFOLLOW) != 0) |
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.
This is tricky; not all *at()
ops support this flag. In particular man-pages-4.09-3.fc26.noarch
says:
AT_SYMLINK_NOFOLLOW If pathname is a symbolic link, do not dereference it: instead operate on the link itself. This flag is not currently implemented.
There was a thread about this recently...
https://marc.info/?l=linux-kernel&m=148830147803162&w=2
https://marc.info/?l=linux-fsdevel&m=149193779929561&w=2
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.
So we probably need to simulate this via openat(...O_NOFOLLOW)
, ignore ELOOP
(meaning symlinks), and for regular files use fchmod()
on the fd.
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 that is overdoing it. Currently (as in the commit message) the kernel will never emit the fuse chmod operation on a symlink, because the kernel does not support it. If, later the kernel starts implementing this it might. However, if it does, then the fchmodat call is likely to work, so the code as it will work.
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.
But today the glibc syscall wrapper returns EINVAL
if any flags are set.
I wrote #1141 and verified that this patch causes the tests to fail.
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.
So let's drop the flag and add a comment with links to the above linux-fsdevel threads?
Prep for ostreedev#1137 where we were incorrectly handling `chown()` on symlinks.
Hmm, i ran into issues with this patch. Without it I get:
But with the patch i get:
So, maybe the patch has issues with fchmod. |
Maybe the safest approach is to only change the parts that we can verify fixes things in the current kernel, rather than pre-empty later kernel changes. |
@alexlarsson See my comments above. |
If you lchown("symlink") then we were incorrectly trying to chown the symlink target, rather than the symlink itself. In particular, this cause cp -a to fail for a broken symlink. Additionally, it was using the symlink target when verifying writability, rather than the symlink itself. To fix this, we need pass AT_SYMLINK_NOFOLLOW in these cases. In general, the kernel itself will always resolve any symlinks for us before calling into the fuse backend, so we should really never do any symlink following in the fuse fs itself. So, we pro-actively add NOFOLLOW flags to a few other places: truncate: In reality this will never be hit, because the kernel will resolve symlinks before calling us. access: It seems the current fuse implementation never calls this (faccessat w/AT_SYMLINK_NOFOLLOW never reaches the fuse fs) but if this ever is implemented this is the correct behaviour. We would ideally do `chmod` but this is not implemented on current kernels. Because we're not multi-threaded, this is OK anyways. Further, our write verification wasn't correctly handling the case of hardlinked symlinks, which can occur for `bare` checkouts but *not* `bare-user` which the tests were using. Change to `bare` mode to verify that.
3ad7c23
to
3c906f9
Compare
OK, I reworked this patch and extended the test suite to cover a lot of this. @alexlarsson can you take a look? Feel free to |
Looks good to me and fixes my usecases |
@alexlarsson: 🔑 Insufficient privileges: Collaborator required |
☀️ Test successful - status-atomicjenkins |
If you lchown("symlink") then we were incorrectly trying to chown the
symlink target, rather than the symlink itself. In particular, this cause
cp -a to fail for a broken symlink. Additionally, it was using the
symlink target when verifying writability, rather than the symlink
itself.
To fix this, we just pass AT_SYMLINK_NOFOLLOW in these cases.
In general, the kernel itself will always resolve any symlinks for us
before calling into the fuse backend, so we should really never do any
symlink following in the fuse fs itself. So, we pro-actively add
NOFOLLOW flags to a few other places:
truncate:
In reality this will never be hit, because
the kernel will resolve symlinks before calling us.
chmod:
Theoretically enable ownership setting on a symlink. This is
not implemented on current kernels, but if it ever is, this
will be required.
access:
It seems the current fuse implementation never calls this
(faccessat w/AT_SYMLINK_NOFOLLOW never reaches the fuse fs)
but if this ever is implemented this is the correct behaviour.