mount: skip redundant permission checks under default_permissions (#10089)

With default_permissions (the mount default) the kernel enforces unix
permission bits from the getattr/lookup attributes before it ever calls
Open, Create, or Mknod. The mount was re-checking permissions in
AcquireHandle and createRegularFile anyway, which duplicated the kernel's
work and kept the supplementary-group lookup on the per-file hot path.

Gate only the mode-bit access check on default_permissions being off, so
a non-root copy does no permission work on open/create. createRegularFile
still loads the parent to validate it exists, since the create RPC skips
the filer-side parent check. With default_permissions off the mount
remains the sole enforcer, so the full check still runs.
This commit is contained in:
Chris Lu
2026-06-24 14:24:51 -07:00
committed by GitHub
parent ef109fe9e1
commit 5112da98a2
5 changed files with 92 additions and 11 deletions
+1
View File
@@ -359,6 +359,7 @@ func RunMount(option *MountOptions, umask os.FileMode) bool {
Cipher: cipher,
UidGidMapper: uidGidMapper,
IncludeSystemEntries: *option.includeSystemEntries,
DefaultPermissions: *option.defaultPermissions,
DisableXAttr: *option.disableXAttr,
IsMacOs: runtime.GOOS == "darwin",
MetadataFlushSeconds: *option.metadataFlushSeconds,
+7
View File
@@ -71,6 +71,13 @@ type Option struct {
UidGidMapper *meta_cache.UidGidMapper
IncludeSystemEntries bool
// DefaultPermissions mirrors the FUSE default_permissions mount option.
// When set, the kernel enforces unix permission bits from the getattr/
// lookup attributes before it ever calls Open/Create/Mknod, so the mount
// skips its own redundant permission checks (and the group lookups behind
// them) on those hot paths.
DefaultPermissions bool
// Periodic metadata flush interval in seconds (0 to disable)
// This protects chunks from being purged by volume.fsck for long-running writes
MetadataFlushSeconds int
+14 -9
View File
@@ -320,7 +320,10 @@ func (wfs *WFS) createRegularFile(dirFullPath util.FullPath, name string, mode u
return 0, nil, fuse.Status(syscall.ENOSPC)
}
// Verify write+search permission on the parent directory.
// Load the parent directory to validate it exists (the create RPC sets
// SkipCheckParentDirectory, so this is the only parent check). With
// default_permissions the kernel already verified write+search on it before
// Create/Mknod, so skip only the mode-bit check and its group lookup.
parentEntry, parentStatus := wfs.maybeLoadEntry(dirFullPath)
if parentStatus != fuse.OK {
return 0, nil, parentStatus
@@ -328,14 +331,16 @@ func (wfs *WFS) createRegularFile(dirFullPath util.FullPath, name string, mode u
if parentEntry == nil || parentEntry.Attributes == nil {
return 0, nil, fuse.EIO
}
// Map parent dir uid/gid from filer-space to local-space so the
// permission check compares like with like (caller uid/gid are local).
parentUid, parentGid := parentEntry.Attributes.Uid, parentEntry.Attributes.Gid
if wfs.option.UidGidMapper != nil {
parentUid, parentGid = wfs.option.UidGidMapper.FilerToLocal(parentUid, parentGid)
}
if !hasAccess(uid, gid, parentUid, parentGid, parentEntry.Attributes.FileMode, fuse.W_OK|fuse.X_OK) {
return 0, nil, fuse.Status(syscall.EACCES)
if !wfs.option.DefaultPermissions {
// Map parent dir uid/gid from filer-space to local-space so the
// permission check compares like with like (caller uid/gid are local).
parentUid, parentGid := parentEntry.Attributes.Uid, parentEntry.Attributes.Gid
if wfs.option.UidGidMapper != nil {
parentUid, parentGid = wfs.option.UidGidMapper.FilerToLocal(parentUid, parentGid)
}
if !hasAccess(uid, gid, parentUid, parentGid, parentEntry.Attributes.FileMode, fuse.W_OK|fuse.X_OK) {
return 0, nil, fuse.Status(syscall.EACCES)
}
}
entryFullPath := dirFullPath.Child(name)
+66
View File
@@ -487,3 +487,69 @@ func TestCreateExistingFileIgnoresQuotaPreflight(t *testing.T) {
t.Fatalf("Create status = %v, want EEXIST", status)
}
}
// With default_permissions the kernel enforces unix bits before it calls
// Open, so AcquireHandle must skip its own check (and the group lookup behind
// it). Without it, AcquireHandle stays the enforcer.
func TestAcquireHandleHonorsDefaultPermissions(t *testing.T) {
for _, tc := range []struct {
name string
defaultPermissions bool
want fuse.Status
}{
{"kernel enforces", true, fuse.OK},
{"mount enforces", false, fuse.EACCES},
} {
t.Run(tc.name, func(t *testing.T) {
wfs, _ := newCreateTestWFS(t)
wfs.option.DefaultPermissions = tc.defaultPermissions
oldLookup := lookupSupplementaryGroupIDs
lookupSupplementaryGroupIDs = func(uint32) ([]string, error) { return nil, nil }
clearSupplementaryGroupCache()
t.Cleanup(func() {
lookupSupplementaryGroupIDs = oldLookup
clearSupplementaryGroupCache()
})
entry := &filer_pb.Entry{
Name: "secret.txt",
Attributes: &filer_pb.FuseAttributes{
FileMode: 0o600, // owner-only: an "other" uid has no read
Inode: 202,
Crtime: 1,
Mtime: 1,
Uid: 123,
Gid: 456,
},
}
if err := wfs.metaCache.InsertEntry(context.Background(), filer.FromPbEntry("/", entry)); err != nil {
t.Fatalf("InsertEntry: %v", err)
}
inode := wfs.inodeToPath.Lookup(util.FullPath("/secret.txt"), entry.Attributes.Crtime, false, false, entry.Attributes.Inode, true)
fh, status := wfs.AcquireHandle(inode, syscall.O_RDONLY, 999, 999)
if status != tc.want {
t.Fatalf("AcquireHandle status = %v, want %v", status, tc.want)
}
if status == fuse.OK {
if fh == nil {
t.Fatal("AcquireHandle returned nil handle on OK")
}
wfs.ReleaseHandle(fh.fh)
}
})
}
}
// default_permissions skips only the mode-bit check, not parent-existence
// validation: the create RPC sets SkipCheckParentDirectory, so the mount's
// own parent lookup is the only thing guarding against an orphaned entry.
func TestCreateRegularFileValidatesParentUnderDefaultPermissions(t *testing.T) {
wfs, _ := newCreateTestWFS(t)
wfs.option.DefaultPermissions = true
if _, _, code := wfs.createRegularFile(util.FullPath("/ghost"), "f.txt", 0o644, 99, 100, 0, false, false); code == fuse.OK {
t.Fatal("createRegularFile returned OK for a missing parent directory")
}
}
+4 -2
View File
@@ -24,8 +24,10 @@ func (wfs *WFS) AcquireHandle(inode uint64, flags, uid, gid uint32) (fileHandle
if wormEnforced, _ := wfs.wormEnforcedForEntry(path, entry); wormEnforced && flags&fuse.O_ANYWRITE != 0 {
return nil, fuse.EPERM
}
// Check unix permission bits for the requested access mode.
if entry != nil && entry.Attributes != nil {
// Check unix permission bits for the requested access mode. With
// default_permissions the kernel already enforced them before this
// open, so the check (and its supplementary-group lookup) is redundant.
if !wfs.option.DefaultPermissions && entry != nil && entry.Attributes != nil {
fileUid, fileGid := entry.Attributes.Uid, entry.Attributes.Gid
if wfs.option.UidGidMapper != nil {
fileUid, fileGid = wfs.option.UidGidMapper.FilerToLocal(fileUid, fileGid)