aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend/fs.go34
-rw-r--r--internal/syscallcompat/sys_darwin.go5
-rw-r--r--internal/syscallcompat/sys_linux.go23
3 files changed, 34 insertions, 28 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index 2cd4630..2c6ac5a 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -238,15 +238,11 @@ 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
+ // Make sure context is nil if we don't want to preserve the owner
+ if !fs.args.PreserveOwner {
+ context = nil
+ }
// Handle long file name
if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {
// Create ".name"
@@ -255,14 +251,14 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
return nil, fuse.ToStatus(err)
}
// Create content
- fd, err = syscallcompat.Openat(dirfd, cName, newFlags|os.O_CREATE|os.O_EXCL, mode)
+ fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|os.O_CREATE|os.O_EXCL, mode, context)
if err != nil {
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)
+ fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, context)
if err != nil {
// xfstests generic/488 triggers this
if err == syscall.EMFILE {
@@ -273,24 +269,6 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
return nil, fuse.ToStatus(err)
}
}
- // Set owner
- if fs.args.PreserveOwner {
- err = syscall.Fchown(fd, int(context.Owner.Uid), int(context.Owner.Gid))
- if err != nil {
- 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)
return NewFile(f, fs)
}
diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go
index 993c229..7defc5f 100644
--- a/internal/syscallcompat/sys_darwin.go
+++ b/internal/syscallcompat/sys_darwin.go
@@ -46,6 +46,11 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
return emulateOpenat(dirfd, path, flags, mode)
}
+func OpenatUser(dirfd int, path string, flags int, mode uint32, context *fuse.Context) (fd int, err error) {
+ // FIXME: take into account context.Owner
+ return Openat(dirfd, path, flags, mode)
+}
+
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
return emulateRenameat(olddirfd, oldpath, newdirfd, newpath)
}
diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go
index 5c180ec..595aa1d 100644
--- a/internal/syscallcompat/sys_linux.go
+++ b/internal/syscallcompat/sys_linux.go
@@ -3,6 +3,7 @@ package syscallcompat
import (
"fmt"
+ "runtime"
"sync"
"syscall"
@@ -75,6 +76,28 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
return syscall.Openat(dirfd, path, flags, mode)
}
+// OpenatUser runs the Openat syscall in the context of a different user.
+func OpenatUser(dirfd int, path string, flags int, mode uint32, context *fuse.Context) (fd int, err error) {
+ if context != nil {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err = syscall.Setregid(-1, int(context.Owner.Gid))
+ if err != nil {
+ return -1, err
+ }
+ defer syscall.Setregid(-1, 0)
+
+ err = syscall.Setreuid(-1, int(context.Owner.Uid))
+ if err != nil {
+ return -1, err
+ }
+ defer syscall.Setreuid(-1, 0)
+ }
+
+ return Openat(dirfd, path, flags, mode)
+}
+
// Renameat wraps the Renameat syscall.
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
return syscall.Renameat(olddirfd, oldpath, newdirfd, newpath)