ipn,magicsock: deny peer capabilities to unsigned peers (#20561)
Unsigned peers aren't covered by tailnet lock, so they must never hold peer capabilities even if the packet filter grants them. This change extends the check for unsigned-peers to ensure full coverage in capabilities. Fixes tailscale/corp#45116 Change-Id: I918af24f0b9855e55921cbdad109cc68e745e125 Signed-off-by: Mike Jensen <mikej@tailscale.com>
This commit is contained in:
@@ -406,6 +406,12 @@ func upgradeNode(n *tailcfg.Node) {
|
||||
if n.AllowedIPs == nil {
|
||||
n.AllowedIPs = slices.Clone(n.Addresses)
|
||||
}
|
||||
// Unsigned peers aren't covered by tailnet lock, so a (possibly malicious)
|
||||
// control server must not grant them network access via advertised routes.
|
||||
// Strip any AllowedIPs beyond their own addresses.
|
||||
if n.UnsignedPeerAPIOnly && !slices.Equal(n.AllowedIPs, n.Addresses) {
|
||||
n.AllowedIPs = slices.Clone(n.Addresses)
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *mapSession) tryHandleIncrementally(res *tailcfg.MapResponse) bool {
|
||||
|
||||
@@ -1547,6 +1547,24 @@ func TestUpgradeNode(t *testing.T) {
|
||||
in: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{}},
|
||||
want: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{}},
|
||||
},
|
||||
{
|
||||
// An unsigned peer is not covered by tailnet lock and must not carry advertised routes
|
||||
name: "unsigned-peer-strips-extra-allowed-ips",
|
||||
in: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{a1, a2, a3, a4}, UnsignedPeerAPIOnly: true},
|
||||
want: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{a1, a2}, UnsignedPeerAPIOnly: true},
|
||||
},
|
||||
{
|
||||
// An unsigned peer whose AllowedIPs already equal its Addresses is left untouched
|
||||
name: "unsigned-peer-allowed-ips-equal-addresses",
|
||||
in: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{a1, a2}, UnsignedPeerAPIOnly: true},
|
||||
want: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{a1, a2}, UnsignedPeerAPIOnly: true},
|
||||
},
|
||||
{
|
||||
// A signed peer keeps its advertised routes: the strip only applies to unsigned peers
|
||||
name: "signed-peer-keeps-extra-allowed-ips",
|
||||
in: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{a1, a2, a3, a4}},
|
||||
want: &tailcfg.Node{Addresses: []netip.Prefix{a1, a2}, AllowedIPs: []netip.Prefix{a1, a2, a3, a4}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user