Skip to content

Commit

Permalink
syscallcompat: MknodatUser: work around changed syscall.Setgroups sem…
Browse files Browse the repository at this point in the history
…antics

Since go1.16beta1 (commit d1b1145cace8b968307f9311ff611e4bb810710c ,
https://go-review.googlesource.com/c/go/+/210639 )
syscall.{Setgroups,Setregid,Setreuid} affects all threads, which
is exactly what we not want.

We now use unix.{Setgroups,Setregid,Setreuid} instead.

Workarounds golang/go#1435 .
  • Loading branch information
rfjakob committed Feb 6, 2021
1 parent 3ab1bcf commit 80a651a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 25 deletions.
64 changes: 40 additions & 24 deletions internal/syscallcompat/sys_linux.go
Expand Up @@ -92,28 +92,38 @@ func getSupplementaryGroups(pid uint32) (gids []int) {
}

// 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.
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.Setgroups(getSupplementaryGroups(context.Pid))
// Since go1.16beta1 (commit d1b1145cace8b968307f9311ff611e4bb810710c ,
// https://go-review.googlesource.com/c/go/+/210639 )
// syscall.{Setgroups,Setregid,Setreuid} affects all threads, which
// is exactly what we not want.
//
// We now use unix.{Setgroups,Setregid,Setreuid} instead.

err = unix.Setgroups(getSupplementaryGroups(context.Pid))
if err != nil {
return -1, err
}
defer syscall.Setgroups(nil)
defer unix.Setgroups(nil)

err = syscall.Setregid(-1, int(context.Owner.Gid))
err = unix.Setregid(-1, int(context.Owner.Gid))
if err != nil {
return -1, err
}
defer syscall.Setregid(-1, 0)
defer unix.Setregid(-1, 0)

err = syscall.Setreuid(-1, int(context.Owner.Uid))
err = unix.Setreuid(-1, int(context.Owner.Uid))
if err != nil {
return -1, err
}
defer syscall.Setreuid(-1, 0)
defer unix.Setreuid(-1, 0)
}

return Openat(dirfd, path, flags, mode)
Expand All @@ -125,28 +135,30 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
}

// MknodatUser runs the Mknodat syscall in the context of a different user.
//
// See OpenatUser() for how this works.
func MknodatUser(dirfd int, path string, mode uint32, dev int, context *fuse.Context) (err error) {
if context != nil {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

err = syscall.Setgroups(getSupplementaryGroups(context.Pid))
err = unix.Setgroups(getSupplementaryGroups(context.Pid))
if err != nil {
return err
}
defer syscall.Setgroups(nil)
defer unix.Setgroups(nil)

err = syscall.Setregid(-1, int(context.Owner.Gid))
err = unix.Setregid(-1, int(context.Owner.Gid))
if err != nil {
return err
}
defer syscall.Setregid(-1, 0)
defer unix.Setregid(-1, 0)

err = syscall.Setreuid(-1, int(context.Owner.Uid))
err = unix.Setreuid(-1, int(context.Owner.Uid))
if err != nil {
return err
}
defer syscall.Setreuid(-1, 0)
defer unix.Setreuid(-1, 0)
}

return Mknodat(dirfd, path, mode, dev)
Expand Down Expand Up @@ -193,56 +205,60 @@ func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) {
}

// SymlinkatUser runs the Symlinkat syscall in the context of a different user.
//
// See OpenatUser() for how this works.
func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.Context) (err error) {
if context != nil {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

err = syscall.Setgroups(getSupplementaryGroups(context.Pid))
err = unix.Setgroups(getSupplementaryGroups(context.Pid))
if err != nil {
return err
}
defer syscall.Setgroups(nil)
defer unix.Setgroups(nil)

err = syscall.Setregid(-1, int(context.Owner.Gid))
err = unix.Setregid(-1, int(context.Owner.Gid))
if err != nil {
return err
}
defer syscall.Setregid(-1, 0)
defer unix.Setregid(-1, 0)

err = syscall.Setreuid(-1, int(context.Owner.Uid))
err = unix.Setreuid(-1, int(context.Owner.Uid))
if err != nil {
return err
}
defer syscall.Setreuid(-1, 0)
defer unix.Setreuid(-1, 0)
}

return Symlinkat(oldpath, newdirfd, newpath)
}

// MkdiratUser runs the Mkdirat syscall in the context of a different user.
//
// See OpenatUser() for how this works.
func MkdiratUser(dirfd int, path string, mode uint32, caller *fuse.Caller) (err error) {
if caller != nil {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

err = syscall.Setgroups(getSupplementaryGroups(caller.Pid))
err = unix.Setgroups(getSupplementaryGroups(caller.Pid))
if err != nil {
return err
}
defer syscall.Setgroups(nil)
defer unix.Setgroups(nil)

err = syscall.Setregid(-1, int(caller.Gid))
err = unix.Setregid(-1, int(caller.Gid))
if err != nil {
return err
}
defer syscall.Setregid(-1, 0)
defer unix.Setregid(-1, 0)

err = syscall.Setreuid(-1, int(caller.Uid))
err = unix.Setreuid(-1, int(caller.Uid))
if err != nil {
return err
}
defer syscall.Setreuid(-1, 0)
defer unix.Setreuid(-1, 0)
}

return Mkdirat(dirfd, path, mode)
Expand Down
9 changes: 8 additions & 1 deletion test.bash
Expand Up @@ -80,7 +80,14 @@ else
fi

if grep -R "panic(" ./*.go internal ; then
echo "Please use log.Panic instead of naked panic!"
echo "$MYNAME: Please use log.Panic instead of naked panic!"
exit 1
fi

# All functions from the commit msg in https://go-review.googlesource.com/c/go/+/210639
if grep -R -E 'syscall.(Setegid|Seteuid|Setgroups|Setgid|Setregid|Setreuid|Setresgid|Setresuid|Setuid)\(' \
./*.go internal ; then
echo "$MYNAME: You probably want to use unix.Setgroups and friends. See the comments in OpenatUser() for why."
exit 1
fi

Expand Down

0 comments on commit 80a651a

Please sign in to comment.