rmind / npf

NPF: packet filter with stateful inspection, NAT, IP sets, etc.
Other
239 stars 42 forks source link

Broken allocation failure branches #129

Open riastradh opened 1 year ago

riastradh commented 1 year ago

Description

npf_conn_establish (invoked from the packet-processing path in softint context) has an error branch to handle memory allocation failure in thmap_put (via npf_conndb_insert), but the error branch calls thmap_del (via npf_conndb_remove), which relies on memory allocation to succeed (https://github.com/rmind/thmap/issues/11):

https://github.com/rmind/npf/blob/2efbe2828bc507896248598ffb1026653cbfed2c/src/kern/npf_conn.c#L477-L480

This error branch is essentially guaranteed to crash -- see, e.g.: https://gnats.netbsd.org/57208

Environment and configuration

Environment:

Configuration: N/A

Any additional information

pettai commented 1 year ago

Here's the configuration of the crashing system, FWIW

$wired_if = "bnx0"
$wired_v4 = inet4(bnx0)
$wired_v6 = inet6(bnx0)
$lab_if = inet4(bnx1)

table <blacklist> type hash file "/etc/npf_blacklist"
table <internal> type tree file "/etc/npf_internal"

$services_tcp = { domain, ssh, http, https }
$services_udp = { domain, ntp }

$internal_tcp = { 5666 }
$internal_udp = { bootps, syslog }

alg "icmp"

procedure "log" {
        # Note: npf_ext_log kernel module should be loaded, if not built-in.
        # Also, the interface created, e.g.: ifconfig npflog0 create
        log: npflog0
}

group "wired" on $wired_if {
        block in final from <blacklist>
        pass stateful in final family inet4 proto icmp to $wired_v4
        pass in final family inet6 proto ipv6-icmp to $wired_v6
        pass stateful in final family inet4 proto tcp to $wired_v4 port ssh apply "log"
        pass in final family inet6 proto tcp to $wired_v6 port ssh apply "log"
        pass in final family inet4 proto tcp from X.X.Y.Z to $wired_v4 port 782    # ConServer
        pass in final family inet4 proto tcp from X.X.Y.Z to $wired_v4 port 60000-65535    # ConServer
        pass stateful in final family inet4 proto tcp from <internal> to $wired_v4 port $internal_tcp
        pass stateful in final family inet4 proto udp from <internal> to $wired_v4 port $internal_tcp
        pass stateful in final family inet4 proto tcp to $wired_v4 port $services_tcp
        pass in final family inet6 proto tcp to $wired_v6 port $services_tcp
        pass stateful in final family inet4 proto udp to $wired_v4 port $services_udp
        pass in final family inet6 proto udp to $wired_v6 port $services_udp
        pass stateful in final family inet4 proto tcp to $wired_v4 port 49151-65535    # Passive FTP
        pass stateful in final family inet6 proto tcp to $wired_v6 port 49151-65535    # Passive FTP
        # pass stateful in final family inet4 proto udp to $wired_v4 port 33434-33600    # Traceroute
        # pass in final family inet6 proto udp to $wired_v6 port 33434-33600    # Traceroute

        # only SYN packets need to generate state
        pass stateful out final family inet6 proto tcp flags S/SA from $wired_v6
        pass stateful out final family inet4 proto tcp flags S/SA from $wired_v4
        # pass the other tcp packets without generating extra state
        pass out final family inet6 proto tcp from $wired_v6
        pass out final family inet4 proto tcp from $wired_v4

        # all other types of traffic, generate state per packet
        pass stateful out final family inet6 from $wired_v6
        pass stateful out final family inet4 from $wired_v4
}

group "lab" {
        pass final on $lab_if all
}

group default {
        pass final on lo0 all
        block all apply "log"
}