---

FreeBSD Ports Security Advisory: Remote denial-of-service in IP stack [REVISED]

Date: Tue, 11 Jul 2000 14:58:00 -0700
From: FreeBSD Security Advisories security-advisories@freebsd.org

To: BUGTRAQ@SECURITYFOCUS.COM
Subject: FreeBSD Ports Security Advisory:
FreeBSD-SA-00:23.ip-options [REVISED]

—–BEGIN PGP SIGNED MESSAGE—–


FreeBSD-SA-00:23                                           Security Advisory
                                                                FreeBSD, Inc.

Topic:          Remote denial-of-service in IP stack [REVISED]

Category:       core
Module:         kernel
Announced:      2000-06-19
Revised:        2000-07-11
Affects:        FreeBSD systems prior to the correction date
Credits:        NetBSD Security Advisory 2000-002, and
                Jun-ichiro itojun Hagino 
Corrected:      (Several bugs fixed, the date below is that of the most
                recent fix)
                2000-06-08 (3.4-STABLE)
                2000-06-08 (4.0-STABLE)
                2000-06-02 (5.0-CURRENT)
FreeBSD only:   NO

I. Background

II. Problem Description

There are several bugs in the processing of IP options in the
FreeBSD IP stack, which fail to correctly bounds-check arguments
and contain other coding errors leading to the possibility of data
corruption and a kernel panic upon reception of certain invalid IP
packets.

This set of bugs includes the instance of the vulnerability
described in NetBSD Security Advisory 2000-002 (see
ftp://ftp.NetBSD.ORG/pub/NetBSD/misc/security/advisories/NetBSD-SA2000-002.txt.asc
)
as well as other bugs with similar effect.

III. Impact

Remote users can cause a FreeBSD system to panic and reboot.

IV. Workaround

Incoming packets containing IP Options can be blocked at a
perimeter firewall or on the local system, using ipfw(8) (ipf(8) is
also capable of blocking packets with IP Options, but is not
described here).

The following ipfw rules are believed to prevent the
denial-of-service attack (replace the rule numbers ‘100’-‘103’ with
whichever rule numbers are appropriate for your local firewall, if
you are already using ipfw):

ipfw add 100 deny log ip from any to any ipopt rr
ipfw add 101 deny log ip from any to any ipopt ts
ipfw add 102 deny log ip from any to any ipopt ssrr
ipfw add 103 deny log ip from any to any ipopt lsrr

Note that there are legitimate uses for IP options, although
they are no believed to be in common use, and blocking them should
not cause any problems. Therefore the log entries generated by
these ipfw rules will not necessarily be evidence of an attempted
attack. Furthermore, the packets may be spoofed and have falsified
source addresses.

V. Solution

One of the following:

1) Upgrade your FreeBSD system to 3.4-STABLE, 4.0-STABLE or
5.0-CURRENT after the respective correction dates.

2) Apply the patch below and recompile your kernel.

Either save this advisory to a file, or download the patch and
detached PGP signature from the following locations, and verify the
signature using your PGP utility.


ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-00:23/ip_options.diff


ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-00:23/ip_options.diff.asc

# cd /usr/src/sys/netinet
# patch -p < /path/to/patch_or_advisory

[ Recompile your kernel as described in
http://www.freebsd.org/handbook/kernelconfig.html
and reboot the system ]

VI. Revision History

v1.0 2000-06-19 Initial release
v1.1 2000-07-11 Note workaround using ipfw.


    Index: ip_icmp.c
    ===================================================================
    RCS file: /ncvs/src/sys/netinet/ip_icmp.c,v
    retrieving revision 1.39
    diff -u -r1.39 ip_icmp.c
    --- ip_icmp.c       2000/01/28 06:13:09     1.39
    +++ ip_icmp.c       2000/06/08 15:26:39
    @@ -662,8 +662,11 @@
                            if (opt == IPOPT_NOP)
                                    len = 1;
                            else {
    +                               if (cnt < IPOPT_OLEN + sizeof(*cp))
    +                                       break;
                                    len = cp[IPOPT_OLEN];
    -                               if (len <= 0 || len > cnt)
    +                               if (len < IPOPT_OLEN + sizeof(*cp) ||
    +                                   len > cnt)
                                            break;
                            }
                            /*
    Index: ip_input.c
    ===================================================================
    RCS file: /ncvs/src/sys/netinet/ip_input.c,v
    retrieving revision 1.130
    diff -u -r1.130 ip_input.c
    --- ip_input.c      2000/02/23 20:11:57     1.130
    +++ ip_input.c      2000/06/08 15:25:46
    @@ -1067,8 +1067,12 @@
                if (opt == IPOPT_NOP)
                        optlen = 1;
                else {
    +                   if (cnt < IPOPT_OLEN + sizeof(*cp)) {
    +                           code = &cp[IPOPT_OLEN] - (u_char *)ip;
    +                           goto bad;
    +                   }
                        optlen = cp[IPOPT_OLEN];
    -                   if (optlen <= 0 || optlen > cnt) {
    +                   if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
                                code = &cp[IPOPT_OLEN] - (u_char *)ip;
                                goto bad;
                        }
    @@ -1174,6 +1178,10 @@
                        break;

                case IPOPT_RR:
    +                   if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
    +                           code = &cp[IPOPT_OFFSET] - (u_char *)ip;
    +                           goto bad;
    +                   }
                        if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
                                code = &cp[IPOPT_OFFSET] - (u_char *)ip;
                                goto bad;
    Index: ip_output.c
    ===================================================================
    RCS file: /ncvs/src/sys/netinet/ip_output.c,v
    retrieving revision 1.99
    diff -u -r1.99 ip_output.c
    --- ip_output.c     2000/03/09 14:57:15     1.99
    +++ ip_output.c     2000/06/08 15:27:08
    @@ -1302,8 +1302,10 @@
                if (opt == IPOPT_NOP)
                        optlen = 1;
                else {
    +                   if (cnt < IPOPT_OLEN + sizeof(*cp))
    +                           goto bad;
                        optlen = cp[IPOPT_OLEN];
    -                   if (optlen <= IPOPT_OLEN || optlen > cnt)
    +                   if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
                                goto bad;
                }
                switch (opt) {


-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBOWuYHFUuHi5z0oilAQEp+wP/bK5jRQXK/d3sQw9cph/usAbiYUD6Ux3l
MIo1R1ZPWnIE20Hx334hvr3u5AUnbtjkFg+86WZcpv5bgWjKS2VLyV4UjJIMMOQr
sSDXta5X4XRO0aXv1Td/Jlkoh2UcoayhKssYa3LLwgcYq++BBGrwbJM+ShUGmllS
qQ86FwHKdow=
=5Ksz
-----END PGP SIGNATURE-----

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends, & analysis