summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend/fs.go22
1 files changed, 20 insertions, 2 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index 7671215..7beeb4f 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -239,6 +239,14 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
return nil, fuse.ToStatus(err)
}
defer syscall.Close(dirfd)
+ // Don't set full mode before we have set the correct owner. Files with SUID/SGID
+ // mode belonging to the wrong owner would be a security risk. Even for other
+ // modes, we don't want anyone else to open the file in the meantime: the fd would
+ // stay open and could later be used to read the file.
+ origMode := mode
+ if fs.args.PreserveOwner {
+ mode = 0000
+ }
fd := -1
// Handle long file name
if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {
@@ -253,7 +261,6 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
nametransform.DeleteLongNameAt(dirfd, cName)
return nil, fuse.ToStatus(err)
}
-
} else {
// Create content, normal (short) file name
fd, err = syscallcompat.Openat(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode)
@@ -271,7 +278,18 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
if fs.args.PreserveOwner {
err = syscall.Fchown(fd, int(context.Owner.Uid), int(context.Owner.Gid))
if err != nil {
- tlog.Warn.Printf("Create: Fchown() failed: %v", err)
+ tlog.Warn.Printf("Create %q: Fchown %d:%d failed: %v", cName, context.Owner.Uid, context.Owner.Gid, err)
+ // In case of a failure, we don't want to proceed setting more
+ // permissive modes.
+ syscall.Close(fd)
+ return nil, fuse.ToStatus(err)
+ }
+ }
+ // Set mode
+ if mode != origMode {
+ err = syscall.Fchmod(fd, origMode)
+ if err != nil {
+ tlog.Warn.Printf("Create %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err)
}
}
f := os.NewFile(uintptr(fd), cName)