Synopsis: IP options denial of service
NetBSD versions: NetBSD 1.4.1 and before
Thanks to: Jason Thorpe, Bill Sommerfeld
Reported in NetBSD Security Advisory: SA2000-002


*** sys/netinet/ip.h.orig	1998/02/10 01:26:44	1.18
--- sys/netinet/ip.h	2000/05/05 03:06:42	1.18.8.1
***************
*** 68,74 ****
  	u_int8_t  ip_p;			/* protocol */
  	u_int16_t ip_sum;		/* checksum */
  	struct	  in_addr ip_src, ip_dst; /* source and dest address */
! };
  
  #define	IP_MAXPACKET	65535		/* maximum packet size */
  
--- 68,74 ----
  	u_int8_t  ip_p;			/* protocol */
  	u_int16_t ip_sum;		/* checksum */
  	struct	  in_addr ip_src, ip_dst; /* source and dest address */
! } __attribute__((__packed__));
  
  #define	IP_MAXPACKET	65535		/* maximum packet size */
  
***************
*** 142,149 ****
  		 struct	ipt_ta {
  			struct in_addr ipt_addr;
  			n_time ipt_time;
! 		 } ipt_ta[1];
! 	} ipt_timestamp;
  };
  
  /* flag bits for ipt_flg */
--- 142,149 ----
  		 struct	ipt_ta {
  			struct in_addr ipt_addr;
  			n_time ipt_time;
! 		 } ipt_ta[1] __attribute__((__packed__));
! 	} ipt_timestamp __attribute__((__packed__));
  };
  
  /* flag bits for ipt_flg */

*** sys/netinet/ip_input.c.orig	2000/02/12 18:10:24	1.82.2.4
--- sys/netinet/ip_input.c	2000/05/06 16:43:25	1.82.2.6
***************
*** 856,866 ****
  	struct mbuf *m;
  {
  	register struct ip *ip = mtod(m, struct ip *);
! 	register u_char *cp;
  	register struct ip_timestamp *ipt;
  	register struct in_ifaddr *ia;
  	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
! 	struct in_addr *sin, dst;
  	n_time ntime;
  
  	dst = ip->ip_dst;
--- 856,866 ----
  	struct mbuf *m;
  {
  	register struct ip *ip = mtod(m, struct ip *);
! 	register u_char *cp, *cp0;
  	register struct ip_timestamp *ipt;
  	register struct in_ifaddr *ia;
  	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
! 	struct in_addr dst;
  	n_time ntime;
  
  	dst = ip->ip_dst;
***************
*** 919,925 ****
  				break;
  			}
  			off--;			/* 0 origin */
! 			if (off > optlen - sizeof(struct in_addr)) {
  				/*
  				 * End of source route.  Should be for us.
  				 */
--- 919,925 ----
  				break;
  			}
  			off--;			/* 0 origin */
! 			if ((off + sizeof(struct in_addr)) > optlen) {
  				/*
  				 * End of source route.  Should be for us.
  				 */
***************
*** 961,967 ****
  			 * If no space remains, ignore.
  			 */
  			off--;			/* 0 origin */
! 			if (off > optlen - sizeof(struct in_addr))
  				break;
  			bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
  			    sizeof(ipaddr.sin_addr));
--- 961,967 ----
  			 * If no space remains, ignore.
  			 */
  			off--;			/* 0 origin */
! 			if ((off + sizeof(struct in_addr)) > optlen)
  				break;
  			bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
  			    sizeof(ipaddr.sin_addr));
***************
*** 990,996 ****
  					goto bad;
  				break;
  			}
! 			sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
  			switch (ipt->ipt_flg) {
  
  			case IPOPT_TS_TSONLY:
--- 990,996 ----
  					goto bad;
  				break;
  			}
! 			cp0 = (cp + ipt->ipt_ptr - 1);
  			switch (ipt->ipt_flg) {
  
  			case IPOPT_TS_TSONLY:
***************
*** 1005,1012 ****
  							    m->m_pkthdr.rcvif);
  				if (ia == 0)
  					continue;
! 				bcopy((caddr_t)&ia->ia_addr.sin_addr,
! 				    (caddr_t)sin, sizeof(struct in_addr));
  				ipt->ipt_ptr += sizeof(struct in_addr);
  				break;
  
--- 1005,1012 ----
  							    m->m_pkthdr.rcvif);
  				if (ia == 0)
  					continue;
! 				bcopy(&ia->ia_addr.sin_addr,
! 				    cp0, sizeof(struct in_addr));
  				ipt->ipt_ptr += sizeof(struct in_addr);
  				break;
  
***************
*** 1014,1020 ****
  				if (ipt->ipt_ptr - 1 + sizeof(n_time) +
  				    sizeof(struct in_addr) > ipt->ipt_len)
  					goto bad;
! 				bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
  				    sizeof(struct in_addr));
  				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
  					continue;
--- 1014,1020 ----
  				if (ipt->ipt_ptr - 1 + sizeof(n_time) +
  				    sizeof(struct in_addr) > ipt->ipt_len)
  					goto bad;
! 				bcopy(cp0, &ipaddr.sin_addr,
  				    sizeof(struct in_addr));
  				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
  					continue;
***************
*** 1025,1031 ****
  				goto bad;
  			}
  			ntime = iptime();
! 			bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
  			    sizeof(n_time));
  			ipt->ipt_ptr += sizeof(n_time);
  		}
--- 1025,1032 ----
  				goto bad;
  			}
  			ntime = iptime();
! 			cp0 = (u_char *) &ntime;	/* XXX GCC BUG */
! 			bcopy(cp0, (caddr_t)cp + ipt->ipt_ptr - 1,
  			    sizeof(n_time));
  			ipt->ipt_ptr += sizeof(n_time);
  		}