headscale/hscontrol/state
SAY-5 01e548e030 state: avoid nil deref in registration handlers when old user is missing
Mirror the guard from HandleNodeFromPreAuthKey in HandleNodeFromAuthPath.
Both functions log the old user's name in the "different user" branch
when an existing NodeStore entry under the same machine key belongs to
another user. UserView.Name dereferences the backing User pointer
unconditionally, so when the cached node was loaded with a non-nil
UserID but a nil User (Preload join missed the row, or upstream code
left the snapshot in that shape), the log call panics with a nil-pointer
dereference at hscontrol/types/types_view.go:97.

The panic is caught by the http2 server's runHandler for the noise
control plane, so the process keeps running but every retry produces a
new panic — production has observed bursts of ~1.9k panics per hour
during a tailscaled reconnect loop. The gRPC/OIDC entry has no equivalent
recover and would surface the panic to the caller.

Guard both call sites with oldUser.Valid() and fall back to an empty
old-user name when the pointer is nil. The "Creating new node for
different user" log line still includes the existing node ID, hostname,
machine key, and new user, so operator visibility is preserved.

Add reproduction tests for both handlers seeding the orphan shape
directly into NodeStore via PutNodeInStoreForTest.

Co-Authored-By: Kristoffer Dalby <kristoffer@dalby.cc>
2026-05-06 07:23:02 +01:00
..
auth_cache_test.go state: replace zcache with bounded LRU for auth cache 2026-04-10 14:09:57 +01:00
debug.go state: switch consumers to NodeStore primary routes 2026-04-29 18:08:39 +01:00
debug_test.go hscontrol/state: make NodeStore batch configuration tunable (#2886) 2025-11-28 16:38:29 +01:00
endpoint_test.go hscontrol/state: make NodeStore batch configuration tunable (#2886) 2025-11-28 16:38:29 +01:00
ephemeral_test.go all: upgrade to Go 1.26rc2 and modernize codebase 2026-02-08 12:35:23 +01:00
ha_health.go state: per-goroutine deadline in HA probe cycle 2026-04-30 12:52:05 +01:00
maprequest.go all: fix golangci-lint issues (#3064) 2026-02-06 21:45:32 +01:00
maprequest_test.go all: fix golangci-lint issues (#3064) 2026-02-06 21:45:32 +01:00
node_store.go state: preserve previous primary when all HA advertisers unhealthy 2026-04-29 18:08:39 +01:00
node_store_hostname_test.go state: auto-bump GivenName on collision and add SetGivenName 2026-04-18 15:12:21 +01:00
node_store_test.go state: compute primary routes inside NodeStore snapshot 2026-04-29 18:08:39 +01:00
ping.go state: drain pending pings on Close 2026-04-17 16:31:49 +01:00
ping_test.go state: drain pending pings on Close 2026-04-17 16:31:49 +01:00
primaries_property_test.go state: preserve previous primary when all HA advertisers unhealthy 2026-04-29 18:08:39 +01:00
primaries_test.go state: preserve previous primary when all HA advertisers unhealthy 2026-04-29 18:08:39 +01:00
ssh_check_test.go state, policy, noise: implement SSH check period auto-approval 2026-02-25 21:28:05 +01:00
state.go state: avoid nil deref in registration handlers when old user is missing 2026-05-06 07:23:02 +01:00
tags.go hscontrol: enforce that tagged nodes never have user_id 2026-02-20 21:51:00 +01:00
test_helpers.go hscontrol/state: make NodeStore batch configuration tunable (#2886) 2025-11-28 16:38:29 +01:00