fix: enforce permission checks for allow_other mounts#11
Open
ShukantPal wants to merge 1 commit intomasterfrom
Open
fix: enforce permission checks for allow_other mounts#11ShukantPal wants to merge 1 commit intomasterfrom
ShukantPal wants to merge 1 commit intomasterfrom
Conversation
|
|
de12e39 to
db9066c
Compare
When default_permissions is not set and allow_other is enabled, the
kernel's fuse_permission() returns 0 for most permission checks without
consulting userspace. This means that after a chmod 000, cached dentries
still allow access by other users — the kernel never sends FUSE_ACCESS
to verify permissions.
This is a two-layer problem requiring fixes in both the kernel and the
FUSE daemon:
Daemon fix (example/passthrough.c):
Fix xmp_access() to check permissions as the requesting user (via
fuse_get_context()) rather than as root. Uses raw SYS_setresuid/
SYS_setresgid syscalls for per-thread credential switching, since
glibc wrappers synchronize across all threads.
Associated kernel patch (fs/fuse/dir.c fuse_permission):
When allow_other is set and default_permissions is not, add an
else-if branch that sends FUSE_ACCESS to userspace for all
permission checks. Includes a MAY_NOT_BLOCK guard that returns
-ECHILD to force retry outside RCU walk mode, since fuse_access()
sends a blocking request to userspace.
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1607,6 +1607,17 @@ static int fuse_permission(...)
} else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
err = fuse_access(inode, mask);
+ } else if (fc->allow_other) {
+ /*
+ * With allow_other, multiple users can access this mount.
+ * Verify permissions via userspace to prevent user A from
+ * accessing files/directories owned by user B with
+ * restrictive permissions.
+ */
+ if (mask & MAY_NOT_BLOCK)
+ return -ECHILD;
+
+ err = fuse_access(inode, mask);
} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
Tests (xfail without kernel patch):
- test_perm_cache_dir_traversal: chmod 000 dir, verify files inside
are denied
- test_perm_cache_file_truncate: chmod 000 file, verify truncate is
denied
- test_perm_cache_dir_read_after_noexec: remove dir execute bit,
verify traversal is denied
Closes: libfuse#15
db9066c to
5a5a61a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes libfuse#15
When default_permissions is not set and allow_other is enabled, the kernel's fuse_permission() returns 0 for most permission checks without consulting userspace. This means that after a chmod 000, cached dentries still allow access by other users — the kernel never sends FUSE_ACCESS to verify permissions.
This is a two-layer problem requiring fixes in both the kernel and the FUSE daemon:
Daemon fix (example/passthrough.c):
Fix xmp_access() to check permissions as the requesting user (via fuse_get_context()) rather than as root. Uses raw SYS_setresuid/SYS_setresgid syscalls for per-thread credential switching, since glibc wrappers synchronize across all threads.
Associated kernel patch (fs/fuse/dir.c fuse_permission):
When allow_other is set and default_permissions is not, add an else-if branch that sends FUSE_ACCESS to userspace for all permission checks. Includes a MAY_NOT_BLOCK guard that returns -ECHILD to force retry outside RCU walk mode, since fuse_access() sends a blocking request to userspace.
Tests (xfail without kernel patch):