Subject: kern/26839: ipfilter with IPv6 can dereference a NULL pointer
To: None <>
From: None <>
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
>Originator:     Pavel Cahyna
>Release:        2.0_BETA
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
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) {
# ifdef MENTAT
# 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);


Yes, please.