From 8ec07b5f7fc31e5d86aa9db4f0c7fe5498d3f9fa Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 21 Sep 2025 08:08:41 -0700 Subject: [PATCH] ipn/ipnauth: don't crash on OpenBSD trying to log username of unknown peer We never implemented the peercred package on OpenBSD (and I just tried again and failed), but we've always documented that the creds pointer can be nil for operating systems where we can't map the unix socket back to its UID. On those platforms, we set the default unix socket permissions such that only the admin can open it anyway and we don't have a read-only vs read-write distinction. OpenBSD was always in that camp, where any access to Tailscale's unix socket meant full access. But during some refactoring, we broke OpenBSD in that we started assuming during one logging path (during login) that Creds was non-nil when looking up an ipnauth.Actor's username, which wasn't relevant (it was called from a function "maybeUsernameOf" anyway, which threw away errors). Verified on an OpenBSD VM. We don't have any OpenBSD integration tests yet. Fixes #17209 Updates #17221 Change-Id: I473c5903dfaa645694bcc75e7f5d484f3dd6044d Signed-off-by: Brad Fitzpatrick --- ipn/ipnauth/ipnauth.go | 2 +- ipn/ipnauth/ipnauth_notwindows.go | 7 ++++++- ipn/ipnserver/actor.go | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ipn/ipnauth/ipnauth.go b/ipn/ipnauth/ipnauth.go index e6560570c..513daf5b3 100644 --- a/ipn/ipnauth/ipnauth.go +++ b/ipn/ipnauth/ipnauth.go @@ -64,7 +64,7 @@ type ConnIdentity struct { // Fields used when NotWindows: isUnixSock bool // Conn is a *net.UnixConn - creds *peercred.Creds // or nil + creds *peercred.Creds // or nil if peercred.Get was not implemented on this OS // Used on Windows: // TODO(bradfitz): merge these into the peercreds package and diff --git a/ipn/ipnauth/ipnauth_notwindows.go b/ipn/ipnauth/ipnauth_notwindows.go index d9d11bd0a..f5dc07a8c 100644 --- a/ipn/ipnauth/ipnauth_notwindows.go +++ b/ipn/ipnauth/ipnauth_notwindows.go @@ -18,8 +18,13 @@ import ( func GetConnIdentity(_ logger.Logf, c net.Conn) (ci *ConnIdentity, err error) { ci = &ConnIdentity{conn: c, notWindows: true} _, ci.isUnixSock = c.(*net.UnixConn) - if ci.creds, _ = peercred.Get(c); ci.creds != nil { + if ci.creds, err = peercred.Get(c); ci.creds != nil { ci.pid, _ = ci.creds.PID() + } else if err == peercred.ErrNotImplemented { + // peercred.Get is not implemented on this OS (such as OpenBSD) + // Just leave creds as nil, as documented. + } else if err != nil { + return nil, err } return ci, nil } diff --git a/ipn/ipnserver/actor.go b/ipn/ipnserver/actor.go index 9d86d2c82..924417a33 100644 --- a/ipn/ipnserver/actor.go +++ b/ipn/ipnserver/actor.go @@ -145,7 +145,11 @@ func (a *actor) Username() (string, error) { defer tok.Close() return tok.Username() case "darwin", "linux", "illumos", "solaris", "openbsd": - uid, ok := a.ci.Creds().UserID() + creds := a.ci.Creds() + if creds == nil { + return "", errors.New("peer credentials not implemented on this OS") + } + uid, ok := creds.UserID() if !ok { return "", errors.New("missing user ID") }