mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-09 15:09:08 +02:00
OnNewPSKReady could be applied out of order: two exchanges for a peer can derive concurrently (one over signal, one over the data path), and the callbacks run outside the manager lock, so an older exchange's apply could land after a newer one and restore a stale WireGuard PSK, splitting the tunnel. Give each exchange a per-peer monotonic generation, assigned under the lock at creation so a later exchange always carries a higher one, and pass it to OnNewPSKReady. The host adapter records the newest generation applied per peer and drops any callback that is not newer, with the check-and-record atomic so the slow SetPresharedKey call stays off that lock. Found in cubic review on #7098 (client/internal/pqkem/callbacks.go:12).
32 lines
969 B
Go
32 lines
969 B
Go
package internal
|
|
|
|
import "testing"
|
|
|
|
// TestAppliedGenerations_DropsStale verifies the out-of-order guard: a generation is
|
|
// accepted only when it is strictly newer than the last one applied for that peer, so a
|
|
// reordered PSK callback cannot restore an older key over a newer one.
|
|
func TestAppliedGenerations_DropsStale(t *testing.T) {
|
|
a := newAppliedGenerations()
|
|
|
|
if !a.claim("peerA", 1) {
|
|
t.Fatal("first generation must be accepted")
|
|
}
|
|
if !a.claim("peerA", 2) {
|
|
t.Fatal("a newer generation must be accepted")
|
|
}
|
|
if a.claim("peerA", 2) {
|
|
t.Fatal("re-applying the same generation must be dropped")
|
|
}
|
|
if a.claim("peerA", 1) {
|
|
t.Fatal("an older generation arriving late must be dropped")
|
|
}
|
|
if !a.claim("peerA", 3) {
|
|
t.Fatal("a newer generation after a dropped stale one must still be accepted")
|
|
}
|
|
|
|
// Generations are tracked independently per peer.
|
|
if !a.claim("peerB", 1) {
|
|
t.Fatal("a different peer's first generation must be accepted")
|
|
}
|
|
}
|