Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 5 May 1996 21:28:42 -0500 (CDT)
From:      Alex Nash <alex@zen.nash.org>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/1175: sys/netinet/ip_fw.c race conditions
Message-ID:  <199605060228.VAA04410@zen.nash.org>
Resent-Message-ID: <199605060241.TAA00262@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         1175
>Category:       kern
>Synopsis:       faulty/lacking spl() usage in sys/netinet/ip_fw.c
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun May  5 19:40:01 PDT 1996
>Last-Modified:
>Originator:     Alex Nash
>Organization:
>Release:        FreeBSD 2.1-STABLE i386
>Environment:

options IPFIREWALL enabled

>Description:

Several locations in sys/netinet/ip_fw.c are lacking or incorrectly
use spl() functions.

The supplied diffs fix or improve:

  1. IMPROVE: defer spl() until absolutely necessary.

  2. FIX: attempting to delete the default (deny) policy resulted
     in the priority level remaining at splnet().

  3. FIX: protect LIST_REMOVE during IP_FW_FLUSH against network
     interrupts.  [ Rationale: Since IP_FW_FLUSH is rarely used,
     the performance degredation of calling splnet() several times
     to allow network interrupts through is deemed acceptable. ]

  4. FIX: prevent network interrupts while clearing accounting
     information.  A network interrupt that occurs between clearing
     the packet counter and the byte counter could result in a
     zero byte count and a non-zero packet count.

>How-To-Repeat:

N/A

>Fix:
	
*** ip_fw.c	Mon Feb 26 09:30:29 1996
--- /usr/src/sys/netinet/ip_fw.c	Thu May  2 20:41:04 1996
***************
*** 444,465 ****
  	u_short nbr = 0;
  	int s;
  
- 	s = splnet();
- 
  	fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT);
  	ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT);
  	if (!fwc || !ftmp) {
  		dprintf(("ip_fw_ctl:  malloc said no\n"));
  		if (fwc)  free(fwc, M_IPFW);
  		if (ftmp) free(ftmp, M_IPFW);
- 		splx(s);
  		return (ENOSPC);
  	}
  	bcopy(frwl, ftmp, sizeof(struct ip_fw));
  	ftmp->fw_pcnt = 0L;
  	ftmp->fw_bcnt = 0L;
  	fwc->rule = ftmp;
  	
  	if (!chainptr->lh_first) {
  		LIST_INSERT_HEAD(chainptr, fwc, chain);
          } else if (ftmp->fw_number == (u_short)-1) {
--- 444,465 ----
  	u_short nbr = 0;
  	int s;
  
  	fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT);
  	ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT);
  	if (!fwc || !ftmp) {
  		dprintf(("ip_fw_ctl:  malloc said no\n"));
  		if (fwc)  free(fwc, M_IPFW);
  		if (ftmp) free(ftmp, M_IPFW);
  		return (ENOSPC);
  	}
+ 
  	bcopy(frwl, ftmp, sizeof(struct ip_fw));
  	ftmp->fw_pcnt = 0L;
  	ftmp->fw_bcnt = 0L;
  	fwc->rule = ftmp;
  	
+ 	s = splnet();
+ 
  	if (!chainptr->lh_first) {
  		LIST_INSERT_HEAD(chainptr, fwc, chain);
          } else if (ftmp->fw_number == (u_short)-1) {
***************
*** 502,519 ****
  	s = splnet();
  
  	fcp = chainptr->lh_first; 
! 	if (fcp->rule->fw_number == (u_short)-1)
! 		return (EINVAL);
! 
! 	for (; fcp; fcp = fcp->chain.le_next) {
! 		if (fcp->rule->fw_number == frwl->fw_number) {
! 			LIST_REMOVE(fcp, chain);
! 			splx(s);
! 			free(fcp->rule, M_IPFW);
! 			free(fcp, M_IPFW);
! 			return 0;
  		}
  	}
  	splx(s);
  	return (EINVAL);
  }
--- 502,519 ----
  	s = splnet();
  
  	fcp = chainptr->lh_first; 
! 	if (fcp->rule->fw_number != (u_short)-1) {
! 		for (; fcp; fcp = fcp->chain.le_next) {
! 			if (fcp->rule->fw_number == frwl->fw_number) {
! 				LIST_REMOVE(fcp, chain);
! 				splx(s);
! 				free(fcp->rule, M_IPFW);
! 				free(fcp, M_IPFW);
! 				return 0;
! 			}
  		}
  	}
+ 
  	splx(s);
  	return (EINVAL);
  }
***************
*** 590,596 ****
--- 590,598 ----
  		while (ip_fw_chain.lh_first != NULL && 
  		    ip_fw_chain.lh_first->rule->fw_number != (u_short)-1) {
  			struct ip_fw_chain *fcp = ip_fw_chain.lh_first;
+ 			int s = splnet();
  			LIST_REMOVE(ip_fw_chain.lh_first, chain);
+ 			splx(s);
  			free(fcp->rule, M_IPFW);
  			free(fcp, M_IPFW);
  		}
***************
*** 598,606 ****
--- 600,610 ----
  		return (0);
  	}
  	if (stage == IP_FW_ZERO) {
+ 		int s = splnet();
  		struct ip_fw_chain *fcp;
  		for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
  			fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
+ 		splx(s);
  		if (m) (void)m_free(m);
  		return (0);
  	}


>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199605060228.VAA04410>