User-Agent: [memory consumed=42M]
The second example has consumed significantly less memory, however, it is
still far more than should have been. There is also the issue that it
would require very few simultaneous attacks to achieve the same results as
in the first example.
In an attempt to correct the problem altogether ulimit was invoked to
restrict the maximum size of it's data segment instead of trying to hack
Apache's source. Using the shell script command [ulimit -d 2048] prevented
the 40M buffers that were previously occurring, however, instead of taking
up 2M the process took up 10M. This was not the expected result.
Next was to hack Apache to make sure it was not resetting the limits
internally and it did report the correct limit. After adding to the kernel
in /usr/src/linux/mm/mmap.c where it checks the memory limit the kernel
reported that the processes were ok.
Now it is necessary to run some test code to see just what was happening
with the memory allocation. The following is the first test which was run:
#include<stdio.h>
#include<sys/resource.h>
main(int argc,char **argv)
{
unsigned long int total,size;
char *p;
size=65536;
total=0;
for(;;)
{
getchar();
if (!(p=malloc(size)))
{
perror("malloc failed");
for(;;)
;
}
memset(p,0,size);
{
struct rlimit rlim;
getrlimit(RLIMIT_DATA,&rlim);
total=total+size;
fprintf(stderr,"BMA: rlim: %d\n",rlim.rlim_cur);
fprintf(stderr,"BMA: rlim: %lu %lu\n",total,size);
}
}
}
The result here was that just allocating 64k buffers the ulimit invocation
works just fine. The next test is where the problem lies. Using the
following:
#include<stdio.h>
#include<sys/resource.h>
main(int argc,char **argv)
{
unsigned long int total,size;
char *p;
size=65536;
total=0;
for(;;)
{
getchar();
if (!(p=malloc(size)))
{
perror("malloc failed");
for(;;)
;
}
memset(p,0,size);
{
struct rlimit rlim;
getrlimit(RLIMIT_DATA,&rlim);
total=total+size;
fprintf(stderr,"BMA: rlim: %d\n",rlim.rlim_cur);
fprintf(stderr,"BMA: rlim: %lu %lu\n",total,size);
size=size+65536;
}
}
}
results in allocating the increasingly larger blocks which indicates the
ulimit invocation has failed. This represents the same results as the
originally reported Apache dos attack.
>From these tests I can only conclude that if you use malloc to allocate
buffers larger than 128k the problem will occur consistently. Even if
ulimit is set to 100 bytes an 8M segment is allocated somewhere. Generally
speaking, most code does not do this, however, this appears to be a case
where Apache does. Either there is a significant flaw in my thinking on
this or a flaw in the way linux is allocating memory. If it's the former,
well, apologies in advance. If it is the latter, I believe it must be
addressed since it creates a vulnerability that represents a serious bug.
The tests were run on both libc5.3.12 and glibc2.0.5 using a linux 2.0.35
kernel. I ran strace on the Apache sever and noticed that it was running
the brk system call to increase the data segment. It was also running
mmap. Is that where the memory is going? I assume that malloc is making
these calls because Apache did not have any mmaps that were in the segment
of code that I was testing.
I wasn't sure whether this would be more appropriate if posted to bugtraq,
linux-kernel or linux- admin so I picked two out of the three.
Thanks,
Brian Ackerman
Computer Resource Center Inc.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html