aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Lackner2019-01-12 20:42:05 +0100
committerSebastian Lackner2019-01-12 20:54:39 +0100
commit03b9d65cce53fb95b7d489ecd03d0853b9b923fb (patch)
tree77f4bd028ab950861a6fa7af274fb56b271f1930
parent669322482a9be3d62abbe0361a8cc2e10e99fc3e (diff)
fusefrontend: -allow_other: Use OpenatUser in Create FUSE call.
Revert commit b22cc03c7516b2003880db8375d26c76d6dff093. Instead of manually adjusting the user and mode after creating the file, adjust effective permissions and let the kernel deal with it. Related to https://github.com/rfjakob/gocryptfs/issues/338.
-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)