mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
doctor/permissions: add new check to print process permissions
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: Ida93a206123f98271a0c664775d0baba98b330c7
This commit is contained in:
parent
524f53de89
commit
c98652c333
@ -201,6 +201,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/derp/derphttp from tailscale.com/net/netcheck+
|
tailscale.com/derp/derphttp from tailscale.com/net/netcheck+
|
||||||
tailscale.com/disco from tailscale.com/derp+
|
tailscale.com/disco from tailscale.com/derp+
|
||||||
tailscale.com/doctor from tailscale.com/ipn/ipnlocal
|
tailscale.com/doctor from tailscale.com/ipn/ipnlocal
|
||||||
|
💣 tailscale.com/doctor/permissions from tailscale.com/ipn/ipnlocal
|
||||||
tailscale.com/doctor/routetable from tailscale.com/ipn/ipnlocal
|
tailscale.com/doctor/routetable from tailscale.com/ipn/ipnlocal
|
||||||
tailscale.com/envknob from tailscale.com/control/controlclient+
|
tailscale.com/envknob from tailscale.com/control/controlclient+
|
||||||
tailscale.com/health from tailscale.com/control/controlclient+
|
tailscale.com/health from tailscale.com/control/controlclient+
|
||||||
@ -346,7 +347,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
golang.org/x/crypto/poly1305 from github.com/tailscale/golang-x-crypto/ssh+
|
golang.org/x/crypto/poly1305 from github.com/tailscale/golang-x-crypto/ssh+
|
||||||
golang.org/x/crypto/salsa20/salsa from golang.org/x/crypto/nacl/box+
|
golang.org/x/crypto/salsa20/salsa from golang.org/x/crypto/nacl/box+
|
||||||
LD golang.org/x/crypto/ssh from tailscale.com/ssh/tailssh+
|
LD golang.org/x/crypto/ssh from tailscale.com/ssh/tailssh+
|
||||||
golang.org/x/exp/constraints from golang.org/x/exp/slices
|
golang.org/x/exp/constraints from golang.org/x/exp/slices+
|
||||||
golang.org/x/exp/maps from tailscale.com/wgengine
|
golang.org/x/exp/maps from tailscale.com/wgengine
|
||||||
golang.org/x/exp/slices from tailscale.com/ipn/ipnlocal+
|
golang.org/x/exp/slices from tailscale.com/ipn/ipnlocal+
|
||||||
golang.org/x/net/bpf from github.com/mdlayher/genetlink+
|
golang.org/x/net/bpf from github.com/mdlayher/genetlink+
|
||||||
|
56
doctor/permissions/permissions.go
Normal file
56
doctor/permissions/permissions.go
Normal file
@ -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()
|
||||||
|
}
|
23
doctor/permissions/permissions_bsd.go
Normal file
23
doctor/permissions/permissions_bsd.go
Normal file
@ -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
|
||||||
|
}
|
62
doctor/permissions/permissions_linux.go
Normal file
62
doctor/permissions/permissions_linux.go
Normal file
@ -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
|
||||||
|
}
|
17
doctor/permissions/permissions_other.go
Normal file
17
doctor/permissions/permissions_other.go
Normal file
@ -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
|
||||||
|
}
|
12
doctor/permissions/permissions_test.go
Normal file
12
doctor/permissions/permissions_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@
|
|||||||
"tailscale.com/client/tailscale/apitype"
|
"tailscale.com/client/tailscale/apitype"
|
||||||
"tailscale.com/control/controlclient"
|
"tailscale.com/control/controlclient"
|
||||||
"tailscale.com/doctor"
|
"tailscale.com/doctor"
|
||||||
|
"tailscale.com/doctor/permissions"
|
||||||
"tailscale.com/doctor/routetable"
|
"tailscale.com/doctor/routetable"
|
||||||
"tailscale.com/envknob"
|
"tailscale.com/envknob"
|
||||||
"tailscale.com/health"
|
"tailscale.com/health"
|
||||||
@ -4698,7 +4699,10 @@ func (b *LocalBackend) Doctor(ctx context.Context, logf logger.Logf) {
|
|||||||
logf = logger.SlowLoggerWithClock(ctx, logf, 20*time.Millisecond, 60, time.Now)
|
logf = logger.SlowLoggerWithClock(ctx, logf, 20*time.Millisecond, 60, time.Now)
|
||||||
|
|
||||||
var checks []doctor.Check
|
var checks []doctor.Check
|
||||||
checks = append(checks, routetable.Check{})
|
checks = append(checks,
|
||||||
|
permissions.Check{},
|
||||||
|
routetable.Check{},
|
||||||
|
)
|
||||||
|
|
||||||
// Print a log message if any of the global DNS resolvers are Tailscale
|
// Print a log message if any of the global DNS resolvers are Tailscale
|
||||||
// IPs; this can interfere with our ability to connect to the Tailscale
|
// IPs; this can interfere with our ability to connect to the Tailscale
|
||||||
|
Loading…
Reference in New Issue
Block a user