diff options
author | Sebastian Lackner | 2019-01-12 20:57:31 +0100 |
---|---|---|
committer | Sebastian Lackner | 2019-01-12 21:20:07 +0100 |
commit | a525e33eaa59c6561653a5fc40e5c4d5a9a3184b (patch) | |
tree | b07cb803ad0f6fe3db093200084f841a93b7b52e /internal/fusefrontend/fs_dir.go | |
parent | 03b9d65cce53fb95b7d489ecd03d0853b9b923fb (diff) |
fusefrontend: -allow_other: Use MkdiratUser in Mkdir FUSE call.
Revert commit fcaca5fc94d981aa637beb752edc8cb3c2265e96.
Instead of manually adjusting the user and mode after creating the
directory, adjust effective permissions and let the kernel deal with it.
Related to https://github.com/rfjakob/gocryptfs/issues/338.
Diffstat (limited to 'internal/fusefrontend/fs_dir.go')
-rw-r--r-- | internal/fusefrontend/fs_dir.go | 79 |
1 files changed, 33 insertions, 46 deletions
diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go index afcc5e5..880f271 100644 --- a/internal/fusefrontend/fs_dir.go +++ b/internal/fusefrontend/fs_dir.go @@ -24,13 +24,13 @@ const dsStoreName = ".DS_Store" // mkdirWithIv - create a new directory and corresponding diriv file. dirfd // should be a handle to the parent directory, cName is the name of the new // directory and mode specifies the access permissions to use. -func (fs *FS) mkdirWithIv(dirfd int, cName string, mode uint32) error { +func (fs *FS) mkdirWithIv(dirfd int, cName string, mode uint32, context *fuse.Context) error { // Between the creation of the directory and the creation of gocryptfs.diriv // the directory is inconsistent. Take the lock to prevent other readers // from seeing it. fs.dirIVLock.Lock() defer fs.dirIVLock.Unlock() - err := syscallcompat.Mkdirat(dirfd, cName, mode) + err := syscallcompat.MkdiratUser(dirfd, cName, mode, context) if err != nil { return err } @@ -63,40 +63,20 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu return fuse.ToStatus(err) } defer syscall.Close(dirfd) - // Don't set the full mode before we have set the correct owner. - // See Create FUSE call for more details. - origMode := mode - if fs.args.PreserveOwner { - mode = 0000 + // Make sure context is nil if we don't want to preserve the owner + if !fs.args.PreserveOwner { + context = nil } if fs.args.PlaintextNames { - err = syscallcompat.Mkdirat(dirfd, cName, mode) - if err != nil { - return fuse.ToStatus(err) - } - // Set owner - if fs.args.PreserveOwner { - err = syscallcompat.Fchownat(dirfd, cName, int(context.Owner.Uid), - int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW) - if err != nil { - tlog.Warn.Printf("Mkdir %q: Fchownat %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. - return fuse.ToStatus(err) - } - } - // Set mode - if origMode != mode { - err = syscallcompat.Fchmodat(dirfd, cName, origMode, unix.AT_SYMLINK_NOFOLLOW) - if err != nil { - tlog.Warn.Printf("Mkdir %q: Fchmodat %#o -> %#o failed: %v", cName, mode, origMode, err) - } - } - return fuse.OK + err = syscallcompat.MkdiratUser(dirfd, cName, mode, context) + return fuse.ToStatus(err) } - // We need write and execute permissions to create gocryptfs.diriv - mode = mode | 0300 + // We need write and execute permissions to create gocryptfs.diriv. + // Also, we need read permissions to open the directory (to avoid + // race-conditions between getting and setting the mode). + origMode := mode + mode = mode | 0700 // Handle long file name if nametransform.IsLongContent(cName) { @@ -107,33 +87,40 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu } // Create directory - err = fs.mkdirWithIv(dirfd, cName, mode) + err = fs.mkdirWithIv(dirfd, cName, mode, context) if err != nil { nametransform.DeleteLongNameAt(dirfd, cName) return fuse.ToStatus(err) } } else { - err = fs.mkdirWithIv(dirfd, cName, mode) + err = fs.mkdirWithIv(dirfd, cName, mode, context) if err != nil { return fuse.ToStatus(err) } } - // Set owner - if fs.args.PreserveOwner { - err = syscallcompat.Fchownat(dirfd, cName, int(context.Owner.Uid), - int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW) + // Set mode + if origMode != mode { + dirfd2, err := syscallcompat.Openat(dirfd, cName, + syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) if err != nil { - tlog.Warn.Printf("Mkdir %q: Fchownat %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. + tlog.Warn.Printf("Mkdir %q: Openat failed: %v", cName, err) return fuse.ToStatus(err) } - } - // Set mode - if origMode != mode { - err = syscallcompat.Fchmodat(dirfd, cName, origMode, unix.AT_SYMLINK_NOFOLLOW) + defer syscall.Close(dirfd2) + + var st syscall.Stat_t + err = syscall.Fstat(dirfd2, &st) + if err != nil { + tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err) + return fuse.ToStatus(err) + } + + // Preserve SGID bit if it was set due to inheritance. + origMode = uint32(st.Mode&^0777) | origMode + err = syscall.Fchmod(dirfd2, origMode) if err != nil { - tlog.Warn.Printf("Mkdir %q: Fchmodat %#o -> %#o failed: %v", cName, mode, origMode, err) + tlog.Warn.Printf("Mkdir %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err) + return fuse.ToStatus(err) } } return fuse.OK |