[prev in list] [next in list] [prev in thread] [next in thread] 

List:       ipfilter
Subject:    Patch for pfil 2.1.5 Solaris 10 Panic
From:       John Wehle <john () feith ! com>
Date:       2005-02-22 0:33:32
Message-ID: 200502220033.j1M0XWcR002841 () jwlab ! FEITH ! COM
[Download RAW message or body]

IP Filter bug report form.
--------------------------
IP Filter Version: 4.1.5
Operating System Version: Solaris 10 x86
Configuration: LKM

Description of problem:

Using IP Filter with an IP in IP tunnel protected by transport mode
IPSEC panics under Solaris 10 x86.  It possible that the same panic
may be triggered by other things.

How to repeat:

Install IP Filter, create /etc/hostname.ip.tun0 containing:

  feith-bb-vpn feith-asp-vpn netmask 0xfffffffc \
    tsrc feith-bb tdst prepnet-rt mtu 1440 up

Also configure /etc/inet/ipsecinit.conf, /etc/inet/ike/config,
and /etc/inet/secret/ike.preshared so that transport mode IPSEC
protects the tunnel.  Setup ipf.conf so it simply passes all
(the actual rules don't appear to affect the problem).

Attempt to connect to the system through the tunnel and watch it
panic.  The enclosed * lightly tested * patch to SunOS/pfildrv.c
fixes the problem.

*** SunOS/pfildrv.c.ORIGINAL	Sat May  8 13:25:55 2004
--- SunOS/pfildrv.c	Mon Feb 21 19:07:18 2005
*************** int pfil_precheck(queue_t *q, mblk_t **m
*** 431,437 ****
  {
  	register struct ip *ip;
  	size_t hlen, len, off, mlen, iphlen, plen;
! 	int err, out, sap, realigned = 0;
  	packet_filter_hook_t *pfh;
  	qpktinfo_t qpkt, *qpi;
  	struct pfil_head *ph;
--- 431,437 ----
  {
  	register struct ip *ip;
  	size_t hlen, len, off, mlen, iphlen, plen;
! 	int err, out, sap;
  	packet_filter_hook_t *pfh;
  	qpktinfo_t qpkt, *qpi;
  	struct pfil_head *ph;
*************** int pfil_precheck(queue_t *q, mblk_t **m
*** 466,472 ****
  	 */
  	out = (flags & PFIL_OUT) ? 1 : 0;
  	off = (out) ? qpi->qpi_hl : 0;
! tryagain:
  	ip = NULL;
  	m = NULL;
  
--- 466,472 ----
  	 */
  	out = (flags & PFIL_OUT) ? 1 : 0;
  	off = (out) ? qpi->qpi_hl : 0;
! 
  	ip = NULL;
  	m = NULL;
  
*************** tryagain:
*** 541,574 ****
  
  	}
  
- 	/*
- 	 * If there is more than one copy of this message traversing the
- 	 * STREAMS stack (ie packet is being used for snoop data) then make a
- 	 * copy of it for our use so we become the sole owner of the new
- 	 * message and do a freemsg() on the one passed in as we're no longer
- 	 * using it or passing it up.
- 	 */
- 	if ((pfil_delayed_copy == 0) && (m->b_datap->db_ref > 1)) {
- 		mblk_t *new;
- 
- forced_copy:
- 		new = copymsg(m);
- 		if (new == NULL) {
- 			atomic_add_long(&qif->qf_copyfail, 1);
- 			return -3;
- 		}
- 		atomic_add_long(&qif->qf_copy, 1);
- 
- 		if (mt != m)
- 			mt->b_cont = new;
- 		else {
- 			*mp = new;
- 			mt = new;
- 		}
- 		freemsg(m);
- 		m = new;
- 	}
- 
  	ip = (struct ip *)(m->b_rptr + off);
  
  	/*
--- 541,546 ----
*************** forced_copy:
*** 590,595 ****
--- 562,661 ----
  	if (mlen == 0)
  		mlen = mt->b_wptr - mt->b_rptr;
  
+ 	len = m->b_wptr - m->b_rptr - off;
+ #ifdef PFILDEBUG
+ 	/*LINTED: E_CONSTANT_CONDITION*/
+ 	PRINT(10,(CE_CONT,
+ 		  "!IP Filter[%s]: out %d len %ld/%ld sap %d ip %p b_rptr %p off %ld m \
%p/%d/%ld/%p mt %p/%d/%ld/%p\n", + 		  qif->qf_name, out, len, mlen, sap,
+ 		  (void *)ip, (void *)m->b_rptr, off, 
+ 		  (void *)m, MTYPE(m), MLEN(m), (void *)m->b_cont,
+ 		  (void *)mt, MTYPE(mt), MLEN(mt), (void *)mt->b_cont));
+ #endif
+ 
+ 	/*
+ 	 * If there is more than one copy of this message traversing the
+ 	 * STREAMS stack (ie the packet is being used for snoop data), the
+ 	 * IP header isn't on a 32bit aligned address, or the IP header
+ 	 * isn't contain within a single block, then make a copy which
+ 	 * meets our requirements and do a freemsg on the one passed in
+ 	 * since we're no longer using it or passing it up.
+ 	 */
+ 	
+ 	if ((pfil_delayed_copy == 0 && m->b_datap->db_ref > 1)
+ 	    || ((u_int)ip & 0x3) || len < sizeof(*ip)
+ 	    || (sap != ETHERTYPE_IP
+ #if SOLARIS2 >= 8
+ 		&& sap != IP6_DL_SAP
+ #endif
+ 	        )) {
+ 		mblk_t *b;
+ 		mblk_t *nm;
+ 		mblk_t *nmt;
+ 		mblk_t *previous_nm;
+ 	
+ forced_copy:
+ 		nmt = NULL;
+ 		previous_nm = NULL;
+ 	
+ 		/*
+ 		 * Duplicate the message block descriptors up to (and
+ 		 * including if the offset is non-zero) the block where
+ 		 * IP begins.
+ 		 */
+ 		for (b = mt; b != m || off; b = b->b_cont) {
+ 			nm = dupb(b);
+ 			if (nm == NULL) {
+ 				atomic_add_long(&qif->qf_copyfail, 1);
+ 				if (nmt)
+ 					freemsg(nmt);
+ 				return -3;
+ 			}
+ 		
+ 			if (nmt)
+ 				linkb(previous_nm, nm);
+ 			else
+ 				nmt = nm;
+ 			previous_nm = nm;
+ 		
+ 			/*
+ 			 * Set the length so the block only contains what
+ 			 * appears before IP.
+ 			 */
+ 			if (b == m) {
+ 				nm->b_wptr = nm->b_rptr + off;
+ 				break;
+ 			}
+ 		}
+ 		
+ 		m->b_rptr += off;
+ 		len = msgdsize(m);
+ 		nm = msgpullup(m,  len);
+ 		m->b_rptr -= off;
+ 		
+ 		if (nm == NULL) {
+ 			atomic_add_long(&qif->qf_copyfail, 1);
+ 			if (nmt)
+ 				freemsg(nmt);
+ 			return -3;
+ 		}
+ 		
+ 		if (nmt)
+ 			linkb(previous_nm, nm);
+ 		else
+ 			nmt = nm;
+ 		
+ 		freemsg(mt);
+ 		
+ 		*mp = nmt;
+ 		mt = nmt;
+ 		m = nm;
+ 	
+ 		off = 0;
+ 	
+ 		ip = (struct ip *)m->b_rptr;
+ 	}
+ 
  	if (sap == ETHERTYPE_IP) {
  		u_short tlen;
  
*************** forced_copy:
*** 625,728 ****
  	else {
  		hlen = 0;
  		sap = -1;
- 	}
- 
- 	len = m->b_wptr - m->b_rptr - off;
- #ifdef PFILDEBUG
- 	/*LINTED: E_CONSTANT_CONDITION*/
- 	PRINT(10,(CE_CONT,
- 		  "!IP Filter[%s]: out %d len %ld/%ld sap %d ip %p b_rptr %p off %ld m \
                %p/%d/%ld/%p mt %p/%d/%ld/%p\n",
- 		  qif->qf_name, out, len, mlen, sap,
- 		  (void *)ip, (void *)m->b_rptr, off, 
- 		  (void *)m, MTYPE(m), MLEN(m), (void *)m->b_cont,
- 		  (void *)mt, MTYPE(mt), MLEN(mt), (void *)mt->b_cont));
- #endif
- 
- 	/*
- 	 * Ok, the IP header isn't on a 32bit aligned address so fix this.
- 	 */
- 	if (((u_int)ip & 0x3) || (len < sizeof(*ip)) || (sap == -1)) {
- 		mblk_t *m2, *m1;
- 		int off2;
- 
- 		if (m->b_datap->db_ref > 1)
- 			goto forced_copy;
- 		/*
- 		 * If we have already tried to realign the IP header and we
- 		 * are back here, then the attempt has failed, so stop now
- 		 * rather than try again (could keep on retrying with no
- 		 * benefit.)
- 		 */
- 		if (realigned) {
- 			atomic_add_long(&qif->qf_drop, 1);
- 			return EINVAL;
- 		}
- 		realigned = 1;
- 
- 		len = msgdsize(m);
- 		if (len < sizeof(*ip)) {
- 			atomic_add_long(&qif->qf_bad, 1);
- 			return EINVAL;
- 		}
- 
- 		/*
- 		 * XXX - Now I understand how pullupmsg() & STREAMS messages
- 		 * work better, this can possibly be junked in favour of using
- 		 * pullupmsg() which will preserve all the dblk bits correctly,
- 		 * as is done in fr_pullup in the ipf code.
- 		 */
- 
- 		/*
- 		 * Junk using pullupmsg()
- 		 */
- 		off2 = (u_int)ip & 0x3;
- 		if (off2)
- 			off2 = 4 - off2;
- 
- 		m2 = allocb(len + off2, BPRI_HI);
- 		if (m2 == NULL) {
- 			atomic_add_long(&qif->qf_drop, 1);
- 			return ENOBUFS;
- 		}
- 
- 		MTYPE(m2) = M_DATA;
- 		if (m->b_rptr != (u_char *)ip)
- 			m2->b_rptr += off2;
- 		m2->b_wptr = m2->b_rptr + len;
- 		m1 = m;
- 		s = (u_char *)m->b_rptr;
- 		for (bp = m2->b_rptr; m1 && (bp < m2->b_wptr); bp += len) {
- 			len = MIN(m1->b_wptr - s, m2->b_wptr - bp);
- 			bcopy(s, bp, len);
- 			m1 = m1->b_cont;
- 			if (m1 != NULL)
- 				s = m1->b_rptr;
- 		}
- 
- 		if ((mt != m) && (mt->b_cont == m) && (off == 0)) {
- 			/*
- 			 * check if the buffer we're changing is chained in-
- 			 * between other buffers and unlink/relink as required.
- 			 */
- 			(void) unlinkb(mt);	/* should return 'm' */
- 			m1 = unlinkb(m);
- 			if (m1 != NULL)
- 				linkb(m2, m1);
- 			freemsg(m);
- 			linkb(mt, m2);
- 		} else {
- 			if (m == mt) {
- 				m1 = unlinkb(mt);
- 				if (m1)
- 					linkb(m2, m1);
- 			}
- 			freemsg(mt);
- 			*mp = m2;
- 			mt = m2;
- 		}
- 
- 		off = 0;
- 		goto tryagain;
  	}
  
  	if (((sap == 0) && (ip->ip_v != IPVERSION))
--- 691,696 ----
-- John
-------------------------------------------------------------------------
> Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
> John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic