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);
               }