util/linuxfw: fix nil deref in nftables chain check
Fix a panic in getOrCreateChain when the kernel lacks nftables support (CONFIG_NF_TABLES). When the nftables netlink connection fails, chain objects returned by getChainFromTable can have nil Hooknum and Priority fields. Dereferencing these caused tailscaled to SIGSEGV during router configuration, which manifested as tailscaled silently crashing ~13 seconds after "tailscale up" on arm64 gokrazy (whose kernel.arm64 build doesn't include nftables). Updates #13038 Change-Id: I14433616da5ed57895cad37038921fb4f79c3534 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
a0a8fae856
commit
943b426038
@@ -453,8 +453,13 @@ func getOrCreateChain(c *nftables.Conn, cinfo chainInfo) (*nftables.Chain, error
|
||||
// type/hook/priority, but for "conventional chains" assume they're what
|
||||
// we expect (in case iptables-nft/ufw make minor behavior changes in
|
||||
// the future).
|
||||
if isTSChain(chain.Name) && (chain.Type != cinfo.chainType || *chain.Hooknum != *cinfo.chainHook || *chain.Priority != *cinfo.chainPriority) {
|
||||
return nil, fmt.Errorf("chain %s already exists with different type/hook/priority", cinfo.name)
|
||||
if isTSChain(chain.Name) {
|
||||
if chain.Hooknum == nil || chain.Priority == nil {
|
||||
return nil, errors.New("nftables chain has nil hooknum or priority; kernel may lack nftables support (CONFIG_NF_TABLES)")
|
||||
}
|
||||
if chain.Type != cinfo.chainType || *chain.Hooknum != *cinfo.chainHook || *chain.Priority != *cinfo.chainPriority {
|
||||
return nil, fmt.Errorf("chain %s already exists with different type/hook/priority", cinfo.name)
|
||||
}
|
||||
}
|
||||
return chain, nil
|
||||
}
|
||||
|
||||
@@ -1309,3 +1309,39 @@ func TestMakeConnmarkSaveExprs(t *testing.T) {
|
||||
t.Fatalf("Flush() failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetOrCreateChainNilHooknum verifies that getOrCreateChain returns a clear
|
||||
// error when a ts- chain exists but has nil Hooknum/Priority, which happens when
|
||||
// the kernel lacks nftables support (CONFIG_NF_TABLES).
|
||||
func TestGetOrCreateChainNilHooknum(t *testing.T) {
|
||||
conn := newSysConn(t)
|
||||
|
||||
table := conn.AddTable(&nftables.Table{
|
||||
Family: nftables.TableFamilyIPv4,
|
||||
Name: "ts-filter-test",
|
||||
})
|
||||
// Add a ts- chain without hooknum/priority (regular chain), simulating
|
||||
// the broken state returned by a kernel without nftables support.
|
||||
conn.AddChain(&nftables.Chain{
|
||||
Name: "ts-input",
|
||||
Table: table,
|
||||
})
|
||||
if err := conn.Flush(); err != nil {
|
||||
t.Fatalf("Flush() failed: %v", err)
|
||||
}
|
||||
|
||||
// Now try getOrCreateChain expecting a base chain with hooknum/priority.
|
||||
_, err := getOrCreateChain(conn, chainInfo{
|
||||
table: table,
|
||||
name: "ts-input",
|
||||
chainType: nftables.ChainTypeFilter,
|
||||
chainHook: nftables.ChainHookInput,
|
||||
chainPriority: nftables.ChainPriorityFilter,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for chain with nil hooknum/priority, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "nil hooknum") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user