Since users can run tailscaled in a variety of ways (root, non-root, non-root with process capabilities on Linux), this check will print the current process permissions to the log to aid in debugging. Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: Ida93a206123f98271a0c664775d0baba98b330c7main
parent
524f53de89
commit
c98652c333
@ -0,0 +1,56 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package permissions provides a doctor.Check that prints the process
|
||||
// permissions for the running process.
|
||||
package permissions |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"os/user" |
||||
"strings" |
||||
|
||||
"golang.org/x/exp/constraints" |
||||
"tailscale.com/types/logger" |
||||
) |
||||
|
||||
// Check implements the doctor.Check interface.
|
||||
type Check struct{} |
||||
|
||||
func (Check) Name() string { |
||||
return "permissions" |
||||
} |
||||
|
||||
func (Check) Run(_ context.Context, logf logger.Logf) error { |
||||
return permissionsImpl(logf) |
||||
} |
||||
|
||||
func formatUserID[T constraints.Integer](id T) string { |
||||
idStr := fmt.Sprint(id) |
||||
if uu, err := user.LookupId(idStr); err != nil { |
||||
return idStr + "(<unknown>)" |
||||
} else { |
||||
return fmt.Sprintf("%s(%q)", idStr, uu.Username) |
||||
} |
||||
} |
||||
|
||||
func formatGroupID[T constraints.Integer](id T) string { |
||||
idStr := fmt.Sprint(id) |
||||
if g, err := user.LookupGroupId(idStr); err != nil { |
||||
return idStr + "(<unknown>)" |
||||
} else { |
||||
return fmt.Sprintf("%s(%q)", idStr, g.Name) |
||||
} |
||||
} |
||||
|
||||
func formatGroups[T constraints.Integer](groups []T) string { |
||||
var buf strings.Builder |
||||
for i, group := range groups { |
||||
if i > 0 { |
||||
buf.WriteByte(',') |
||||
} |
||||
buf.WriteString(formatGroupID(group)) |
||||
} |
||||
return buf.String() |
||||
} |
||||
@ -0,0 +1,23 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build darwin || freebsd || openbsd
|
||||
|
||||
package permissions |
||||
|
||||
import ( |
||||
"golang.org/x/sys/unix" |
||||
"tailscale.com/types/logger" |
||||
) |
||||
|
||||
func permissionsImpl(logf logger.Logf) error { |
||||
groups, _ := unix.Getgroups() |
||||
logf("uid=%s euid=%s gid=%s egid=%s groups=%s", |
||||
formatUserID(unix.Getuid()), |
||||
formatUserID(unix.Geteuid()), |
||||
formatGroupID(unix.Getgid()), |
||||
formatGroupID(unix.Getegid()), |
||||
formatGroups(groups), |
||||
) |
||||
return nil |
||||
} |
||||
@ -0,0 +1,62 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build linux
|
||||
|
||||
package permissions |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
"unsafe" |
||||
|
||||
"golang.org/x/sys/unix" |
||||
"tailscale.com/types/logger" |
||||
) |
||||
|
||||
func permissionsImpl(logf logger.Logf) error { |
||||
// NOTE: getresuid and getresgid never fail unless passed an
|
||||
// invalid address.
|
||||
var ruid, euid, suid uint64 |
||||
unix.Syscall(unix.SYS_GETRESUID, |
||||
uintptr(unsafe.Pointer(&ruid)), |
||||
uintptr(unsafe.Pointer(&euid)), |
||||
uintptr(unsafe.Pointer(&suid)), |
||||
) |
||||
|
||||
var rgid, egid, sgid uint64 |
||||
unix.Syscall(unix.SYS_GETRESGID, |
||||
uintptr(unsafe.Pointer(&rgid)), |
||||
uintptr(unsafe.Pointer(&egid)), |
||||
uintptr(unsafe.Pointer(&sgid)), |
||||
) |
||||
|
||||
groups, _ := unix.Getgroups() |
||||
|
||||
var buf strings.Builder |
||||
fmt.Fprintf(&buf, "ruid=%s euid=%s suid=%s rgid=%s egid=%s sgid=%s groups=%s", |
||||
formatUserID(ruid), formatUserID(euid), formatUserID(suid), |
||||
formatGroupID(rgid), formatGroupID(egid), formatGroupID(sgid), |
||||
formatGroups(groups), |
||||
) |
||||
|
||||
// Get process capabilities
|
||||
var ( |
||||
capHeader = unix.CapUserHeader{ |
||||
Version: unix.LINUX_CAPABILITY_VERSION_3, |
||||
Pid: 0, // 0 means 'ourselves'
|
||||
} |
||||
capData unix.CapUserData |
||||
) |
||||
|
||||
if err := unix.Capget(&capHeader, &capData); err != nil { |
||||
fmt.Fprintf(&buf, " caperr=%v", err) |
||||
} else { |
||||
fmt.Fprintf(&buf, " cap_effective=%08x cap_permitted=%08x cap_inheritable=%08x", |
||||
capData.Effective, capData.Permitted, capData.Inheritable, |
||||
) |
||||
} |
||||
|
||||
logf("%s", buf.String()) |
||||
return nil |
||||
} |
||||
@ -0,0 +1,17 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !(linux || darwin || freebsd || openbsd)
|
||||
|
||||
package permissions |
||||
|
||||
import ( |
||||
"runtime" |
||||
|
||||
"tailscale.com/types/logger" |
||||
) |
||||
|
||||
func permissionsImpl(logf logger.Logf) error { |
||||
logf("unsupported on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||
return nil |
||||
} |
||||
@ -0,0 +1,12 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package permissions |
||||
|
||||
import "testing" |
||||
|
||||
func TestPermissionsImpl(t *testing.T) { |
||||
if err := permissionsImpl(t.Logf); err != nil { |
||||
t.Error(err) |
||||
} |
||||
} |
||||
Loading…
Reference in new issue