netinet6: Don't return non-IPv6 enabled interfaces from in6_getlinkifnet()
There are scenarios where we can end up looking up an interface by its scope and turn up an interface that doesn't have IPv6 enabled on it. If that happens we could end up dereferencing a NULL pointer accessing ifp->if_afdata[AF_INET6]. Check for this. One such scenario is if a firewall rewrites a destination address to a link-local address, with an embedded scope for such an interface. Attach a test case which provokes this. PR: 288263 Reported by: Robert Morris <rtm@lcs.mit.edu> Reviewed by: zlei Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D51500
This commit is contained in:
+16
-1
@@ -505,8 +505,23 @@ in6_set_unicast_scopeid(struct in6_addr *in6, uint32_t scopeid)
|
||||
struct ifnet*
|
||||
in6_getlinkifnet(uint32_t zoneid)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
|
||||
return (ifnet_byindex((u_short)zoneid));
|
||||
ifp = ifnet_byindex((u_short)zoneid);
|
||||
|
||||
if (ifp == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* An interface might not be IPv6 capable. */
|
||||
if (ifp->if_afdata[AF_INET6] == NULL) {
|
||||
log(LOG_NOTICE,
|
||||
"%s: embedded scope points to an interface without "
|
||||
"IPv6: %s%%%d.\n", __func__,
|
||||
if_name(ifp), zoneid);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (ifp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
from atf_python.sys.net.vnet import VnetTestTemplate
|
||||
|
||||
class TestNAT64(VnetTestTemplate):
|
||||
REQUIRED_MODULES = [ "pf" ]
|
||||
REQUIRED_MODULES = [ "pf", "pflog" ]
|
||||
TOPOLOGY = {
|
||||
"vnet1": {"ifaces": ["if1"]},
|
||||
"vnet2": {"ifaces": ["if1", "if2"]},
|
||||
@@ -92,12 +92,15 @@ def vnet3_handler(self, vnet):
|
||||
def vnet2_handler(self, vnet):
|
||||
ifname = vnet.iface_alias_map["if1"].name
|
||||
|
||||
ToolsHelper.print_output("/sbin/sysctl net.inet6.ip6.forwarding=1")
|
||||
ToolsHelper.print_output("/sbin/route add default 192.0.2.2")
|
||||
ToolsHelper.print_output("/sbin/pfctl -e")
|
||||
ToolsHelper.pf_rules([
|
||||
"pass inet6 proto icmp6",
|
||||
"pass in on %s inet6 af-to inet from 192.0.2.1" % ifname])
|
||||
|
||||
vnet.pipe.send(socket.if_nametoindex("pflog0"))
|
||||
|
||||
@pytest.mark.require_user("root")
|
||||
@pytest.mark.require_progs(["scapy"])
|
||||
def test_tcp_rst(self):
|
||||
@@ -287,3 +290,39 @@ def test_bad_len(self):
|
||||
reply = sp.sr1(packet, timeout=3)
|
||||
# We don't expect a reply to a corrupted packet
|
||||
assert not reply
|
||||
|
||||
@pytest.mark.require_user("root")
|
||||
@pytest.mark.require_progs(["scapy"])
|
||||
def test_noip6(self):
|
||||
"""
|
||||
PR 288263: link-local target address in icmp6 ADVERT can cause NULL deref
|
||||
"""
|
||||
ifname = self.vnet.iface_alias_map["if1"].name
|
||||
gw_mac = self.vnet.iface_alias_map["if1"].epairb.ether
|
||||
scopeid = self.wait_object(self.vnet_map["vnet2"].pipe)
|
||||
ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1")
|
||||
|
||||
import scapy.all as sp
|
||||
|
||||
pkt = sp.Ether(dst=gw_mac) \
|
||||
/ sp.IPv6(dst="64:ff9b::203.0.113.2") \
|
||||
/ sp.ICMPv6ND_NA(tgt="FFA2:%x:2821:125F:1D27:B3B2:3F6F:C43C" % scopeid)
|
||||
pkt.show()
|
||||
sp.hexdump(pkt)
|
||||
s = DelayedSend(pkt, sendif=ifname)
|
||||
|
||||
packets = sp.sniff(iface=ifname, timeout=5)
|
||||
for r in packets:
|
||||
r.show()
|
||||
|
||||
# Try scope id that likely doesn't have an interface at all
|
||||
pkt = sp.Ether(dst=gw_mac) \
|
||||
/ sp.IPv6(dst="64:ff9b::203.0.113.2") \
|
||||
/ sp.ICMPv6ND_NA(tgt="FFA2:%x:2821:125F:1D27:B3B2:3F6F:C43C" % 255)
|
||||
pkt.show()
|
||||
sp.hexdump(pkt)
|
||||
s = DelayedSend(pkt, sendif=ifname)
|
||||
|
||||
packets = sp.sniff(iface=ifname, timeout=5)
|
||||
for r in packets:
|
||||
r.show()
|
||||
|
||||
Reference in New Issue
Block a user