fusefrontend: -allow_other: Use SymlinkatUser in Symlink FUSE call.

Instead of manually adjusting the user after creating the symlink,
adjust effective permissions and let the kernel deal with it.

Related to https://github.com/rfjakob/gocryptfs/issues/338.
This commit is contained in:
Sebastian Lackner 2019-01-12 21:22:52 +01:00
parent 1fbe7798cf
commit efc280330c
3 changed files with 34 additions and 14 deletions

View File

@ -483,6 +483,10 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
defer syscall.Close(dirfd) defer syscall.Close(dirfd)
// Make sure context is nil if we don't want to preserve the owner
if !fs.args.PreserveOwner {
context = nil
}
cTarget := target cTarget := target
if !fs.args.PlaintextNames { if !fs.args.PlaintextNames {
// Symlinks are encrypted like file contents (GCM) and base64-encoded // Symlinks are encrypted like file contents (GCM) and base64-encoded
@ -495,26 +499,15 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
// Create "gocryptfs.longfile." symlink // Create "gocryptfs.longfile." symlink
err = syscallcompat.Symlinkat(cTarget, dirfd, cName) err = syscallcompat.SymlinkatUser(cTarget, dirfd, cName, context)
if err != nil { if err != nil {
nametransform.DeleteLongNameAt(dirfd, cName) nametransform.DeleteLongNameAt(dirfd, cName)
} }
} else { } else {
// Create symlink // Create symlink
err = syscallcompat.Symlinkat(cTarget, dirfd, cName) err = syscallcompat.SymlinkatUser(cTarget, dirfd, cName, context)
} }
if err != nil { return fuse.ToStatus(err)
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("Symlink: Fchownat failed: %v", err)
}
}
return fuse.OK
} }
// Rename - FUSE call. // Rename - FUSE call.

View File

@ -80,6 +80,11 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
return emulateSymlinkat(oldpath, newdirfd, newpath) return emulateSymlinkat(oldpath, newdirfd, newpath)
} }
func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.Context) (err error) {
// FIXME: take into account context.Owner
return Symlinkat(oldpath, newdirfd, newpath)
}
func Mkdirat(dirfd int, path string, mode uint32) (err error) { func Mkdirat(dirfd int, path string, mode uint32) (err error) {
return emulateMkdirat(dirfd, path, mode) return emulateMkdirat(dirfd, path, mode)
} }

View File

@ -197,6 +197,28 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
return unix.Symlinkat(oldpath, newdirfd, newpath) return unix.Symlinkat(oldpath, newdirfd, newpath)
} }
// SymlinkatUser runs the Symlinkat syscall in the context of a different user.
func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.Context) (err error) {
if context != nil {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
err = syscall.Setregid(-1, int(context.Owner.Gid))
if err != nil {
return err
}
defer syscall.Setregid(-1, 0)
err = syscall.Setreuid(-1, int(context.Owner.Uid))
if err != nil {
return err
}
defer syscall.Setreuid(-1, 0)
}
return Symlinkat(oldpath, newdirfd, newpath)
}
// Mkdirat syscall. // Mkdirat syscall.
func Mkdirat(dirfd int, path string, mode uint32) (err error) { func Mkdirat(dirfd int, path string, mode uint32) (err error) {
return syscall.Mkdirat(dirfd, path, mode) return syscall.Mkdirat(dirfd, path, mode)