From 32af08ecad3fe435ee646791e345526b5bcb7795 Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Mon, 18 Nov 2019 21:59:47 +0000 Subject: [PATCH] icmpv6: Fix mbuf change in mld After r354748 mld_input() can change the mbuf. The new pointer is never returned to icmp6_input() and when passed to icmp6_rip6_input() the mbuf may no longer valid leading to a panic. Pass a pointer to the mbuf to mld_input() so we can return an updated version in the non-error case. Add a test sending an MLD packet case which will trigger this bug. Pointyhat to: bz Reported by: gallatin, thj MFC After: 2 weeks X-MFC with: r354748 Sponsored by: Netflix --- sys/netinet6/icmp6.c | 2 +- sys/netinet6/mld6.c | 5 ++- sys/netinet6/mld6_var.h | 2 +- tests/sys/netinet6/Makefile | 3 ++ tests/sys/netinet6/mld.py | 76 +++++++++++++++++++++++++++++++ tests/sys/netinet6/mld.sh | 89 +++++++++++++++++++++++++++++++++++++ 6 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 tests/sys/netinet6/mld.py create mode 100755 tests/sys/netinet6/mld.sh diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 9a75233eb076..92624bf43042 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -604,7 +604,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) */ if ((ip6->ip6_hlim != 1) || (m->m_flags & M_RTALERT_MLD) == 0) goto freeit; - if (mld_input(m, off, icmp6len) != 0) { + if (mld_input(&m, off, icmp6len) != 0) { *mp = NULL; return (IPPROTO_DONE); } diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index d3ca2334a96f..fdfe989c74e3 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -1249,13 +1249,15 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6, * Return IPPROTO_DONE if we freed m. Otherwise, return 0. */ int -mld_input(struct mbuf *m, int off, int icmp6len) +mld_input(struct mbuf **mp, int off, int icmp6len) { struct ifnet *ifp; struct ip6_hdr *ip6; + struct mbuf *m; struct mld_hdr *mld; int mldlen; + m = *mp; CTR3(KTR_MLD, "%s: called w/mbuf (%p,%d)", __func__, m, off); ifp = m->m_pkthdr.rcvif; @@ -1278,6 +1280,7 @@ mld_input(struct mbuf *m, int off, int icmp6len) ICMP6STAT_INC(icp6s_badlen); return (IPPROTO_DONE); } + *mp = m; ip6 = mtod(m, struct ip6_hdr *); mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off); diff --git a/sys/netinet6/mld6_var.h b/sys/netinet6/mld6_var.h index 8dc2ffa4cd7c..0aedde275f1b 100644 --- a/sys/netinet6/mld6_var.h +++ b/sys/netinet6/mld6_var.h @@ -167,7 +167,7 @@ struct mld_ifsoftc * void mld_domifdetach(struct ifnet *); void mld_fasttimo(void); void mld_ifdetach(struct ifnet *, struct in6_multi_head *); -int mld_input(struct mbuf *, int, int); +int mld_input(struct mbuf **, int, int); void mld_slowtimo(void); #ifdef SYSCTL_DECL diff --git a/tests/sys/netinet6/Makefile b/tests/sys/netinet6/Makefile index dd4e7b90123b..bdedc404a16e 100644 --- a/tests/sys/netinet6/Makefile +++ b/tests/sys/netinet6/Makefile @@ -7,12 +7,15 @@ FILESDIR= ${TESTSDIR} ATF_TESTS_SH= \ exthdr \ + mld \ scapyi386 ${PACKAGE}FILES+= exthdr.py +${PACKAGE}FILES+= mld.py ${PACKAGE}FILES+= scapyi386.py ${PACKAGE}FILESMODE_exthdr.py= 0555 +${PACKAGE}FILESMODE_mld.py= 0555 ${PACKAGE}FILESMODE_scapyi386.py=0555 TESTS_SUBDIRS+= frag6 diff --git a/tests/sys/netinet6/mld.py b/tests/sys/netinet6/mld.py new file mode 100644 index 000000000000..b1fcf2f8e50a --- /dev/null +++ b/tests/sys/netinet6/mld.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +#- +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2019 Netflix, Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +import argparse +import scapy.all as sp +import socket +import sys +import binascii + +def main(): + parser = argparse.ArgumentParser("scapyi386.py", + description="IPv6 Ethernet Dest MAC test") + parser.add_argument('--sendif', nargs=1, + required=True, + help='The interface through which the packet will be sent') + parser.add_argument('--recvif', nargs=1, + required=True, + help='The interface on which to check for the packet') + parser.add_argument('--src', nargs=1, + required=True, + help='The source IP address') + parser.add_argument('--to', nargs=1, + required=True, + help='The destination IP address') + parser.add_argument('--debug', + required=False, action='store_true', + help='Enable test debugging') + parser.add_argument('--mldraw01', + required=False, action='store_true', + help='Multicast Listener Query Raw01') + + args = parser.parse_args() + + pkt = None + if args.mldraw01: + pkt = sp.Ether() / \ + sp.IPv6(dst="ff02::1", hlim=1, nh=0) / \ + sp.IPv6ExtHdrHopByHop(options = sp.RouterAlert(value=0)) / \ + sp.ICMPv6MLQuery() + if pkt is None: + sys.exit(1) + if args.debug: + pkt.display() + sp.sendp(pkt, iface=args.sendif[0], verbose=False) + + sys.exit(0) + +if __name__ == '__main__': + main() diff --git a/tests/sys/netinet6/mld.sh b/tests/sys/netinet6/mld.sh new file mode 100755 index 000000000000..034d5945ae20 --- /dev/null +++ b/tests/sys/netinet6/mld.sh @@ -0,0 +1,89 @@ +# $FreeBSD$ +#- +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2019 Netflix, Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +. $(atf_get_srcdir)/../common/vnet.subr + +atf_test_case "mldraw01" "cleanup" +mldraw01_head() { + + atf_set descr 'Test for correct Ethernet Destination MAC address' + atf_set require.user root + atf_set require.progs scapy +} + +mldraw01_body() { + + ids=65533 + id=`printf "%x" ${ids}` + if [ $$ -gt 65535 ]; then + xl=`printf "%x" $(($$ - 65535))` + yl="1" + else + xl=`printf "%x" $$` + yl="" + fi + + vnet_init + + ip6a="2001:db8:6666:0000:${yl}:${id}:1:${xl}" + ip6b="2001:db8:6666:0000:${yl}:${id}:2:${xl}" + + epair=$(vnet_mkepair) + ifconfig ${epair}a up + ifconfig ${epair}a inet6 ${ip6a}/64 + + jname="v6t-${id}-${yl}-${xl}" + vnet_mkjail ${jname} ${epair}b + jexec ${jname} ifconfig ${epair}b up + jexec ${jname} ifconfig ${epair}b inet6 ${ip6b}/64 + + # Let IPv6 ND do its thing. + #ping6 -q -c 1 ff02::1%${epair}a + #ping6 -q -c 1 ${ip6b} + sleep 3 + + pyname=$(atf_get ident) + + atf_check -s exit:0 $(atf_get_srcdir)/mld.py \ + --sendif ${epair}a --recvif ${epair}a \ + --src ${ip6a} --to ${ip6b} \ + --${pyname} +} + +mldraw01_cleanup() { + + vnet_cleanup +} + +atf_init_test_cases() +{ + + atf_add_test_case "mldraw01" +} + +# end