Subject: kern/26839: ipfilter with IPv6 can dereference a NULL pointer
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <pavel.cahyna@st.mff.cuni.cz>
List: netbsd-bugs
Date: 09/03/2004 09:47:02
>Number:         26839
>Category:       kern
>Synopsis:       ipfilter with IPv6 can dereference a NULL pointer
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Sep 03 09:48:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Pavel Cahyna
>Release:        2.0_BETA
>Organization:
>Environment:
NetBSD pcap 2.0_BETA NetBSD 2.0_BETA (PCAP_TPC - zalozeno na GENERIC-$Revision: 1.4 $, pridan patch na regulaci vykonu, zkompilovano s WI_DEBUG) #13: Sun Aug 29 17:41:57 CEST 2004  pavel@pc:/home/pavel/kompilace/jadra/compile/PCAP_TPC i386
>Description:
The function fr_coalesce assumes that the fin->fin_mp and fin->fin_m pointers will be non-NULL:

int fr_coalesce(fin)
fr_info_t *fin;
{
#if !defined(__sgi) && defined(_KERNEL)
	if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
		ATOMIC_INCL(fr_badcoalesces[fin->fin_out]);
# ifdef MENTAT
		FREE_MB_T(*fin->fin_mp);
# endif
		*fin->fin_mp = NULL;
...

But frpr_ipv6hdr, which calls fr_coalesce at several places, is called from fr_makefrip, which is called from fr_checkicmp6matchingstate, as in this backtrace:

#9  0xc012c8f2 in frpr_ipv6hdr (fin=0xc0a89b00)
    at /usr/src/sys/netinet/fil.c:464
#10 0xc0128b8d in fr_makefrip (hlen=0, ip=0x0, fin=0xc0a89b00)
    at /usr/src/sys/netinet/fil.c:1330
#11 0xc013f329 in fr_checkicmp6matchingstate (fin=0xc0a89cb0)
    at /usr/src/sys/netinet/ip_state.c:3347
#12 0xc013e2dc in fr_stlookup (fin=0xc0a89cb0, tcp=0xc290c048, ifqp=0xc0a89c78)
    at /usr/src/sys/netinet/ip_state.c:2154
#13 0xc013e73f in fr_checkstate (fin=0xc0a89cb0, passp=0x0)
    at /usr/src/sys/netinet/ip_state.c:2378
#14 0xc0129839 in fr_check (ip=0xc0a89cac, hlen=40, ifp=0x0, out=0, 
    mp=0xc0a89db8) at /usr/src/sys/netinet/fil.c:2350
#15 0xc012d95b in fr_check_wrapper6 (arg=0x0, mp=0x0, ifp=0xc0b8f034, dir=1)
    at /usr/src/sys/netinet/ip_fil_netbsd.c:183
#16 0xc03c0067 in pfil_run_hooks (ph=0x0, mp=0xc0a89e50, ifp=0xc0b8f034, dir=1)
    at /usr/src/sys/net/pfil.c:69
#17 0xc014ccaa in ip6_input (m=0xc0d1bd00)
    at /usr/src/sys/netinet6/ip6_input.c:317
#18 0xc014c24d in ip6intr () at /usr/src/sys/netinet6/ip6_input.c:212
#19 0xc0102ac9 in Xsoftnet ()

The problem is that fr_checkicmp6matchingstate sets those fields to NULL in the fin structure that is passed down:

	ofin.fin_m = NULL;	/* if dereferenced, panic XXX */
	ofin.fin_mp = NULL;	/* if dereferenced, panic XXX */

	/*
	 * We make a fin entry to be able to feed it to
	 * matchsrcdst. Note that not all fields are necessary
	 * but this is the cleanest way. Note further we fill
	 * in fin_mp such that if someone uses it we'll get
	 * a kernel panic. fr_matchsrcdst does not use this.
	 *
	 * watch out here, as ip is in host order and oip6 in network
	 * order. Any change we make must be undone afterwards.
	 */
...
(void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin);


>How-To-Repeat:

>Fix:
Yes, please.
>Release-Note:
>Audit-Trail:
>Unformatted: