safesocket, ipn/ipnserver: look up peer creds on Darwin

And open up socket permissions like Linux, now that we know who connections are from.

WIP DO NOT SUBMIT

Updates #1347
Fixes #1348
This commit is contained in:
Brad Fitzpatrick 2021-02-15 20:50:20 -08:00
parent 4ec01323c1
commit 9baca2e833
4 changed files with 62 additions and 3 deletions

2
go.mod
View File

@ -42,3 +42,5 @@ require (
inet.af/netaddr v0.0.0-20210105212526-648fbc18a69d
rsc.io/goversion v1.2.0
)
replace golang.org/x/sys => /Users/bradfitz/src/golang.org/x/sys

View File

@ -0,0 +1,56 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin,!redo
package ipnserver
import (
"net"
"golang.org/x/sys/unix"
"tailscale.com/types/logger"
)
const (
xLOCAL_PEERCRED = 0x1
xLOCAL_PEEREPID = 0x3
xLOCAL_PEEREUUID = 0x5
xLOCAL_PEERPID = 0x2
xLOCAL_PEERUUID = 0x4
)
func isReadonlyConn(c net.Conn, logf logger.Logf) (ro bool) {
ro = true // conservative default for naked returns below
uc, ok := c.(*net.UnixConn)
if !ok {
logf("unexpected connection type %T", c)
return
}
raw, err := uc.SyscallConn()
if err != nil {
logf("SyscallConn: %v", err)
return
}
var cred unix.Xucred
cerr := raw.Control(func(fd uintptr) {
err = unix.GetsockoptXucred(int(fd), unix.SOL_LOCAL, unix.LOCAL_PEERCRED, &cred)
})
if cerr != nil {
logf("raw.Control: %v", err)
return
}
if err != nil {
logf("raw.GetsockoptXucred: %v", err)
return
}
logf("XXX got creds %+v", cred)
if cred.Uid == 0 {
// root is not read-only.
return false
}
logf("non-root connection from %v (read-only)", cred.Uid)
return true
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !linux
// +build !linux,!darwin darwin,redo
package ipnserver

View File

@ -103,8 +103,9 @@ func tailscaledRunningUnderLaunchd() bool {
// socketPermissionsForOS returns the permissions to use for the
// tailscaled.sock.
func socketPermissionsForOS() os.FileMode {
if runtime.GOOS == "linux" {
// On Linux, the ipn/ipnserver package looks at the Unix peer creds
switch runtime.GOOS {
case "linux", "darwin":
// On Linux and Farwin, the ipn/ipnserver package looks at the Unix peer creds
// and only permits read-only actions from non-root users, so we want
// this opened up wider.
//