[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Full-disclosure] 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 */


/*@null@*//*@out@*/char *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 _______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/