fusefrontend: run acl Setxattr in user context

The result of setting an acl depends on who runs the
operation!

Fixes fuse-xfstests generic/375
(see https://github.com/rfjakob/fuse-xfstests/wiki/results_2021-05-19)
This commit is contained in:
Jakob Unterwurzacher 2021-06-02 19:10:36 +02:00
parent b23e21f61f
commit a38e5988ba
4 changed files with 35 additions and 5 deletions

View File

@ -7,6 +7,8 @@ import (
"strings"
"syscall"
"github.com/hanwen/go-fuse/v2/fuse"
"github.com/rfjakob/gocryptfs/internal/tlog"
)
@ -90,7 +92,12 @@ func (n *Node) Setxattr(ctx context.Context, attr string, data []byte, flags uin
// ACLs are passed through without encryption
if isAcl(attr) {
return n.setXAttr(attr, data, flags)
// result of setting an acl depends on the user doing it
var context *fuse.Context
if rn.args.PreserveOwner {
context = toFuseCtx(ctx)
}
return n.setXAttr(context, attr, data, flags)
}
cAttr, err := rn.encryptXattrName(attr)
@ -98,7 +105,7 @@ func (n *Node) Setxattr(ctx context.Context, attr string, data []byte, flags uin
return syscall.EINVAL
}
cData := rn.encryptXattrValue(data)
return n.setXAttr(cAttr, cData, flags)
return n.setXAttr(nil, cAttr, cData, flags)
}
// RemoveXAttr - FUSE call.

View File

@ -6,6 +6,7 @@ import (
"golang.org/x/sys/unix"
"github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
)
@ -40,7 +41,7 @@ func (n *Node) getXAttr(cAttr string) (out []byte, errno syscall.Errno) {
return cData, 0
}
func (n *Node) setXAttr(cAttr string, cData []byte, flags uint32) (errno syscall.Errno) {
func (n *Node) setXAttr(context *fuse.Context, cAttr string, cData []byte, flags uint32) (errno syscall.Errno) {
dirfd, cName, errno := n.prepareAtSyscall("")
if errno != 0 {
return

View File

@ -7,6 +7,7 @@ import (
"golang.org/x/sys/unix"
"github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
)
@ -30,7 +31,7 @@ func (n *Node) getXAttr(cAttr string) (out []byte, errno syscall.Errno) {
return cData, 0
}
func (n *Node) setXAttr(cAttr string, cData []byte, flags uint32) (errno syscall.Errno) {
func (n *Node) setXAttr(context *fuse.Context, cAttr string, cData []byte, flags uint32) (errno syscall.Errno) {
dirfd, cName, errno := n.prepareAtSyscall("")
if errno != 0 {
return
@ -38,7 +39,8 @@ func (n *Node) setXAttr(cAttr string, cData []byte, flags uint32) (errno syscall
defer syscall.Close(dirfd)
procPath := fmt.Sprintf("/proc/self/fd/%d/%s", dirfd, cName)
return fs.ToErrno(unix.Lsetxattr(procPath, cAttr, cData, int(flags)))
return fs.ToErrno(syscallcompat.LsetxattrUser(procPath, cAttr, cData, int(flags), context))
}
func (n *Node) removeXAttr(cAttr string) (errno syscall.Errno) {

View File

@ -130,6 +130,9 @@ func asUser(f func() (int, error), context *fuse.Context) (int, error) {
//
// It switches the current thread to the new user, performs the syscall,
// and switches back.
//
// If `context` is nil, this function behaves like ordinary Openat (no
// user switching).
func OpenatUser(dirfd int, path string, flags int, mode uint32, context *fuse.Context) (fd int, err error) {
f := func() (int, error) {
return Openat(dirfd, path, flags, mode)
@ -143,6 +146,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
}
// MknodatUser runs the Mknodat syscall in the context of a different user.
// If `context` is nil, this function behaves like ordinary Mknodat.
//
// See OpenatUser() for how this works.
func MknodatUser(dirfd int, path string, mode uint32, dev int, context *fuse.Context) (err error) {
@ -195,6 +199,7 @@ func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) {
}
// SymlinkatUser runs the Symlinkat syscall in the context of a different user.
// If `context` is nil, this function behaves like ordinary Symlinkat.
//
// See OpenatUser() for how this works.
func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.Context) (err error) {
@ -207,6 +212,7 @@ func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.C
}
// MkdiratUser runs the Mkdirat syscall in the context of a different user.
// If `context` is nil, this function behaves like ordinary Mkdirat.
//
// See OpenatUser() for how this works.
func MkdiratUser(dirfd int, path string, mode uint32, context *fuse.Context) (err error) {
@ -218,6 +224,20 @@ func MkdiratUser(dirfd int, path string, mode uint32, context *fuse.Context) (er
return err
}
// LsetxattrUser runs the Lsetxattr syscall in the context of a different user.
// This is useful when setting ACLs, as the result depends on the user running
// the operation (see fuse-xfstests generic/375).
//
// If `context` is nil, this function behaves like ordinary Lsetxattr.
func LsetxattrUser(path string, attr string, data []byte, flags int, context *fuse.Context) (err error) {
f := func() (int, error) {
err := unix.Lsetxattr(path, attr, data, flags)
return -1, err
}
_, err = asUser(f, context)
return err
}
func timesToTimespec(a *time.Time, m *time.Time) []unix.Timespec {
ts := make([]unix.Timespec, 2)
ts[0] = unix.Timespec(fuse.UtimeToTimespec(a))