[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#6215) liblber problems

Full_Name: Hallvard B Furuseth
Submission from: (NULL) (
Submitted by: hallvard

Given these declarations:
    #include <lber.h>
    #define LBER_EXBUFSIZ 4060 /* from liblber/io.c */
    static char data[8000];
    struct berval bv;
    BerElement *ber;

Buffer overrun i ber_flatten(,,0):
    ber = der_alloc();
    ber_printf(ber, "o", data, LBER_EXBUFSIZ - 4);
    ber_flatten2(ber, &bv, 0);
ber_flatten2(,,0) \0-terminates the Ber buffer, but does not grow it first
at need.  Simplest fix is to allocate an extra byte in ber_realloc(), and
reduce LBER_EXBUFSIZ by 1 to compensate.  I don't know how kosher it is to
write into the ber buffer in the first place though.

Coredump - write through NULL pointer:
    ber_flatten2(der_alloc(), &bv, 0);
A fresh Ber has no buffers yet, the buffer pointers are NULL.
\0-terminating a NULL pointer doesn't work too well.  Don't know if
it should be called a bug though, since ber_flatten2() doesn't work
right on an incomplete Ber element either (due to seqorset stuff).

The NULL pointers in a fresh ber also mean ber_write, ber_len()
& co do pointer arithmetic on NULL pointers, which is not valid.
Oh well, it seems to work on most machines.

Buffer overrun in ber_write():
    ber = der_alloc();
    ber_printf(ber, "{");
    ber_write(ber, data, 6000, 0);

ber_write() needs buffer space and calls ber_realloc(ber, 6000).
However "{" has moved ber->ber_sos->sos_ptr (the write destination)
6 bytes beyond ber->ber_end, so 6006 bytes are actually needed.
ber_realloc() does not know that, and allocates 6000 bytes.

It cannot happen with ber_write() called from liblber:  Next liblber
write after "{" will be just a few bytes with the next element's tag.
ber_realloc() always allocates 4060 bytes or more - moving sos_ptr
beyond ber_end again.

This can only happen if a caller outside liblber generates a complete
"tag, length, contents" element >= 4060 bytes and ber_write()s it in one
operation.  There are ber_write()s in libldap and slapd/connection.c,
but haven't checked if any are at risk.

Don't know where to fix it:
- in ber_realloc(), most techinically correct.
- in ber_write() - simpler since it already knows about sos_ptr.
- in ber_start_seqorset() - always alloc a buffer, never point
  beyond allocated data.  Cleanest but most space-costly.