From be67b8e75b9bedb28fc8502c9295fb5f4b3fbb5f Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 Jan 2023 12:47:01 -0800 Subject: [PATCH] ssh/tailssh: fix Tailscale SSH to non-root tailscaled Fix regression from 337c77964bd1701e6562f388d2d71fcad6470ddd where tailscaled started calling Setgroups. Prior to that, SSH to a non-root tailscaled was working. Instead, ignore any failure calling Setgroups if the groups are already correct. Fixes #6888 Change-Id: I561991ddb37eaf2620759c6bcaabd36e0fb2a22d Signed-off-by: Brad Fitzpatrick --- ssh/tailssh/incubator.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/ssh/tailssh/incubator.go b/ssh/tailssh/incubator.go index 40bc2eaf1..828873eba 100644 --- a/ssh/tailssh/incubator.go +++ b/ssh/tailssh/incubator.go @@ -24,6 +24,7 @@ import ( "os/user" "path/filepath" "runtime" + "sort" "strconv" "strings" "syscall" @@ -33,6 +34,7 @@ import ( "github.com/u-root/u-root/pkg/termios" "go4.org/mem" gossh "golang.org/x/crypto/ssh" + "golang.org/x/exp/slices" "golang.org/x/sys/unix" "tailscale.com/cmd/tailscaled/childproc" "tailscale.com/envknob" @@ -727,5 +729,25 @@ func setGroups(groupIDs []int) error { // this to work for more things than it previously did. groupIDs = groupIDs[:16] } - return syscall.Setgroups(groupIDs) + + err := syscall.Setgroups(groupIDs) + if err != nil && os.Geteuid() != 0 && groupsMatchCurrent(groupIDs) { + // If we're not root, ignore a Setgroups failure if all groups are the same. + return nil + } + return err +} + +func groupsMatchCurrent(groupIDs []int) bool { + existing, err := syscall.Getgroups() + if err != nil { + return false + } + if len(existing) != len(groupIDs) { + return false + } + groupIDs = slices.Clone(groupIDs) + sort.Ints(groupIDs) + sort.Ints(existing) + return slices.Equal(groupIDs, existing) }