diff options
| author | Jakob Unterwurzacher | 2025-02-26 21:12:56 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2025-02-26 21:27:29 +0100 | 
| commit | 22cd9cf174e8a93787b01f6dd7b09247f9642286 (patch) | |
| tree | a0503f917b4354eef61452d9a9c6976fdaca5393 /internal | |
| parent | 49d797effbc0888975c51ac45371d91fc59ea2dc (diff) | |
syscallcompat: add asUser for darwin and make OpenatUser and friends shared
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/syscallcompat/asuser.go | 59 | ||||
| -rw-r--r-- | internal/syscallcompat/asuser_darwin.go | 46 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_darwin.go | 75 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_linux.go | 53 | 
4 files changed, 105 insertions, 128 deletions
diff --git a/internal/syscallcompat/asuser.go b/internal/syscallcompat/asuser.go new file mode 100644 index 0000000..0c083ec --- /dev/null +++ b/internal/syscallcompat/asuser.go @@ -0,0 +1,59 @@ +package syscallcompat + +import ( +	"golang.org/x/sys/unix" + +	"github.com/hanwen/go-fuse/v2/fuse" +) + +// OpenatUser runs the Openat syscall in the context of a different user. +// 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) +	} +	return asUser(f, context) +} + +// 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) { +	f := func() (int, error) { +		err := Mknodat(dirfd, path, mode, dev) +		return -1, err +	} +	_, err = asUser(f, context) +	return err +} + +// 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) { +	f := func() (int, error) { +		err := unix.Symlinkat(oldpath, newdirfd, newpath) +		return -1, err +	} +	_, err = asUser(f, context) +	return err +} + +// 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) { +	f := func() (int, error) { +		err := unix.Mkdirat(dirfd, path, mode) +		return -1, err +	} +	_, err = asUser(f, context) +	return err +} diff --git a/internal/syscallcompat/asuser_darwin.go b/internal/syscallcompat/asuser_darwin.go new file mode 100644 index 0000000..5da2782 --- /dev/null +++ b/internal/syscallcompat/asuser_darwin.go @@ -0,0 +1,46 @@ +package syscallcompat + +import ( +	"runtime" +	"syscall" + +	"github.com/hanwen/go-fuse/v2/fuse" +) + +// asUser runs `f()` under the effective uid, gid, groups specified +// in `context`. +// +// If `context` is nil, `f()` is executed directly without switching user id. +func asUser(f func() (int, error), context *fuse.Context) (int, error) { +	if context == nil { +		return f() +	} + +	runtime.LockOSThread() +	defer runtime.UnlockOSThread() + +	err := pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) +	if err != nil { +		return -1, err +	} + +	const ( +		// KAUTH_UID_NONE and KAUTH_GID_NONE are special values to +		// revert permissions to the process credentials. +		KAUTH_UID_NONE = ^uint32(0) - 100 +		KAUTH_GID_NONE = ^uint32(0) - 100 +	) + +	defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) + +	return f() +} + +// Unfortunately pthread_setugid_np does not have a syscall wrapper yet. +func pthread_setugid_np(uid uint32, gid uint32) (err error) { +	_, _, e1 := syscall.RawSyscall(syscall.SYS_SETTID, uintptr(uid), uintptr(gid), 0) +	if e1 != 0 { +		err = e1 +	} +	return +} diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go index 06f09f0..cf2f3f0 100644 --- a/internal/syscallcompat/sys_darwin.go +++ b/internal/syscallcompat/sys_darwin.go @@ -3,7 +3,6 @@ package syscallcompat  import (  	"log"  	"path/filepath" -	"runtime"  	"syscall"  	"time"  	"unsafe" @@ -26,22 +25,8 @@ const (  	RENAME_NOREPLACE = 1  	RENAME_EXCHANGE  = 2  	RENAME_WHITEOUT  = 4 - -	// KAUTH_UID_NONE and KAUTH_GID_NONE are special values to -	// revert permissions to the process credentials. -	KAUTH_UID_NONE = ^uint32(0) - 100 -	KAUTH_GID_NONE = ^uint32(0) - 100  ) -// Unfortunately pthread_setugid_np does not have a syscall wrapper yet. -func pthread_setugid_np(uid uint32, gid uint32) (err error) { -	_, _, e1 := syscall.RawSyscall(syscall.SYS_SETTID, uintptr(uid), uintptr(gid), 0) -	if e1 != 0 { -		err = e1 -	} -	return -} -  // Unfortunately fsetattrlist does not have a syscall wrapper yet.  func fsetattrlist(fd int, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) {  	_, _, e1 := syscall.Syscall6(syscall.SYS_FSETATTRLIST, uintptr(fd), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) @@ -84,74 +69,14 @@ func Dup3(oldfd int, newfd int, flags int) (err error) {  //// Emulated Syscalls (see emulate.go) ////////////////  //////////////////////////////////////////////////////// -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 = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) -		if err != nil { -			return -1, err -		} -		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) -	} - -	return Openat(dirfd, path, flags, mode) -} -  func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {  	return emulateMknodat(dirfd, path, mode, dev)  } -func MknodatUser(dirfd int, path string, mode uint32, dev int, context *fuse.Context) (err error) { -	if context != nil { -		runtime.LockOSThread() -		defer runtime.UnlockOSThread() - -		err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) -		if err != nil { -			return err -		} -		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) -	} - -	return Mknodat(dirfd, path, mode, dev) -} -  func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) {  	return unix.Fchmodat(dirfd, path, mode, unix.AT_SYMLINK_NOFOLLOW)  } -func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.Context) (err error) { -	if context != nil { -		runtime.LockOSThread() -		defer runtime.UnlockOSThread() - -		err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) -		if err != nil { -			return err -		} -		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) -	} - -	return unix.Symlinkat(oldpath, newdirfd, newpath) -} - -func MkdiratUser(dirfd int, path string, mode uint32, context *fuse.Context) (err error) { -	if context != nil { -		runtime.LockOSThread() -		defer runtime.UnlockOSThread() - -		err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) -		if err != nil { -			return err -		} -		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) -	} - -	return unix.Mkdirat(dirfd, path, mode) -} -  type attrList struct {  	bitmapCount uint16  	_           uint16 diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go index d769f96..6414a64 100644 --- a/internal/syscallcompat/sys_linux.go +++ b/internal/syscallcompat/sys_linux.go @@ -92,38 +92,11 @@ func getSupplementaryGroups(pid uint32) (gids []int) {  	return nil  } -// OpenatUser runs the Openat syscall in the context of a different user. -// -// 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) -	} -	return asUser(f, context) -} -  // Mknodat wraps the Mknodat syscall.  func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {  	return syscall.Mknodat(dirfd, path, mode, dev)  } -// 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) { -	f := func() (int, error) { -		err := Mknodat(dirfd, path, mode, dev) -		return -1, err -	} -	_, err = asUser(f, context) -	return err -} -  // Dup3 wraps the Dup3 syscall. We want to use Dup3 rather than Dup2 because Dup2  // is not implemented on arm64.  func Dup3(oldfd int, newfd int, flags int) (err error) { @@ -164,32 +137,6 @@ func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) {  	return syscall.Chmod(procPath, mode)  } -// 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) { -	f := func() (int, error) { -		err := unix.Symlinkat(oldpath, newdirfd, newpath) -		return -1, err -	} -	_, err = asUser(f, context) -	return err -} - -// 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) { -	f := func() (int, error) { -		err := unix.Mkdirat(dirfd, path, mode) -		return -1, err -	} -	_, err = asUser(f, context) -	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).  | 
