From 9baca2e8335119a55f4a040398c5aed43513c985 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 15 Feb 2021 20:50:20 -0800 Subject: [PATCH] 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 --- go.mod | 2 ++ ipn/ipnserver/conn_darwin.go | 56 ++++++++++++++++++++++++++++++++++ ipn/ipnserver/conn_no_ucred.go | 2 +- safesocket/unixsocket.go | 5 +-- 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 ipn/ipnserver/conn_darwin.go diff --git a/go.mod b/go.mod index c0266a0d0..214b6e1f7 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/ipn/ipnserver/conn_darwin.go b/ipn/ipnserver/conn_darwin.go new file mode 100644 index 000000000..594025fc1 --- /dev/null +++ b/ipn/ipnserver/conn_darwin.go @@ -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 +} diff --git a/ipn/ipnserver/conn_no_ucred.go b/ipn/ipnserver/conn_no_ucred.go index c50e4778d..e0899b5c6 100644 --- a/ipn/ipnserver/conn_no_ucred.go +++ b/ipn/ipnserver/conn_no_ucred.go @@ -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 diff --git a/safesocket/unixsocket.go b/safesocket/unixsocket.go index 8128bef57..8d8b6f176 100644 --- a/safesocket/unixsocket.go +++ b/safesocket/unixsocket.go @@ -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. //