[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Pine.NEB.4.61.0505060156210.19421@speedy.ludd.ltu.se>
Date: Fri May 6 15:01:51 2005
From: jlo at ludd.luth.se (Lars Olsson)
Subject: 64 bit qmail fun
On Fri, 6 May 2005, Georgi Guninski wrote:
> Georgi Guninski security advisory #74, 2005
>
> 64 bit qmail fun
>
> Systems affected:
> qmail on 64 bit platforms with a lot of virtual memory ( ~ >8GB)
>
> Date: 6 May 2005
[snip]
Hehe...darn, you beat me to it...I've been sitting on this for some
time now...
I noticed the problem with the heap-allocation wrapper alloc() in alloc.c
(also affects djbdns BTW although I haven't found a way to trigger for
it):
static aligned realspace[SPACE / ALIGNMENT];
#define space ((char *) realspace)
static unsigned int avail = SPACE; /* multiple of ALIGNMENT;
0<=avail<=SPACE */
/*@...l@...*@out@...har *alloc(n)
unsigned int n;
{
char *x;
n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */
^^^^^^^^^^^^^^^^^^^
if (n <= avail) { avail -= n; return space + avail; }
x = malloc(n);
if (!x) errno = error_nomem;
return x;
}
Notice the XXX? :)
If n > 0xfffffff0 the alignment adjustment will truncate n to 0
which means the pointer returned will be to the static realspace buffer.
This step does not require a 64-bit architecture!
However, the only way I've found so far to trigger the integer overflow is
via the stralloc_* routines used in a manner that grows the buffer one
byte at a time, for instance in qmail-smtpd.c commands() loop (function
pointer is placed after realspace on my test compilations BTW).
Hence 64-bit arch with lots of mem is necessary in this case. I don't
think it's possible to break out of the byte_copy routine though
unfortunately (or fortunately, depending on which side of the fence
you're on.)
There are usually checks for excessive lenghts before the other
alloc-routines that specifies length explicitly (and without copying),
especially in djbdns since DNS packets only are 2^16 bytes max (or some
such, I forget.)
It might well be that qmail and djbdns are immune to exploits, but it
is a good idea to patch alloc() in alloc.c anyway, for instance like:
if (n >= 0xfffffff0) {
errno = error_nomem;
return NULL;
}
(Crude and for more general operations should be rewritten to allow larger
allocations, but for qmail and djbns it should be good enough since
hopefulyl one doesn't need that much memory to run them efficiently...)
Don't have time to write more now...apologize if I screwed something up in
my extreme hurry...
Cheers,
Lars
Powered by blists - more mailing lists