On 2009/08/27 18:02, Manoj Srivastava <[email protected]> wrote:
> >  [...]
> >  brk(0x3233000)                          = 0x3233000
> >  mmap(NULL, 18446744073703178240, PROT_READ|PROT_WRITE, 
> > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
> >  mmap(NULL, 18446744073703313408, PROT_READ|PROT_WRITE, 
> > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
> >  mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, 
> > -1, 0) = 0x7fdfda316000
> 
>         So, seems like a  memory issue to me.
> 
> >  munmap(0x7fdfda316000, 30318592)        = 0
> >  munmap(0x7fdfe0000000, 36790272)        = 0
> >  mprotect(0x7fdfdc000000, 135168, PROT_READ|PROT_WRITE) = 0
> >  mmap(NULL, 18446744073703178240, PROT_READ|PROT_WRITE, 
> > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
> >  write(2, "libsepol.sepol_module_package_rea"..., 
> > 36libsepol.sepol_module_package_read: ) = 36
> >
> > This looks like a buffer underflow (0xffffffffff9ec000) or an
> > uninitialized variable.
> 
>         Why do you think this is buffer underflow? (Also, I do not see
>  0xffffffffff9ec000 in the log fragment)

0xffffffffff9ec000 == 18446744073703178240 (the size of the first
large allocation).  It's also equal to -6373376.  This just looks like
an integer underflow, doesn't it?

>         Unless you can provide some evidence that his is not a local
>  hardware or configuration error, or if I can reproduce this, I would
>  have to treat this as an out of memory error.

What kind of configuration error could make semanage allocate this
huge amount of memory?

Here is a backtrace:

 Breakpoint 4, 0x00007f9bc4c05400 in mmap64 () from /lib/libc.so.6
 (gdb) p $rsi
 $25 = -6373376
 (gdb) bt
 #0  0x00007f9bc4c05400 in mmap64 () from /lib/libc.so.6
 #1  0x00007f9bc4baf6bb in _int_malloc () from /lib/libc.so.6
 #2  0x00007f9bc4bb0a78 in malloc () from /lib/libc.so.6
 #3  0x00007f9bc5301a8e in sepol_module_package_read (mod=0xb1d170, 
spf=0xb202e0, verbose=0) at module.c:533
 #4  0x00007f9bc4ea7838 in ?? () from /lib/libsemanage.so.1

More debugging info:

 (gdb) frame 3
 #3  0x00007f9bc5301a8e in sepol_module_package_read (mod=0xb1d170, 
spf=0xb202e0, verbose=0) at module.c:533
 533     module.c: No such file or directory.
         in module.c
 (gdb) p len
 $26 = 18446744073703176358
 (gdb) p i
 $27 = 3
 (gdb) p nsec
 $30 = 4
 (gdb) p offsets[i+1] 
 $28 = 8192
 (gdb) p offsets[i]
 $29 = 6383450

line 456:

 len = offsets[i + 1] - offsets[i];

Voila, integer underflow.  Good guess, isn'it it?  The function
module_package_read_offsets() reads the offsets from the input file,
but does not verify them.

 for (i = 0; i < nsec; i++) {
   // ...
   len = offsets[i + 1] - offsets[i];

That looks obviously wrong, but it in fact isn't - because
module_package_read_offsets() allocates nsec+1 items.  But the problem
is in module_package_read_offsets() itself:

 off = (size_t *) malloc((nsec + 1) * sizeof(size_t));
 // ...
 for (i = 0; i < nsec; i++) {
   off[i] = le32_to_cpu(buf[i]);
   if (i && off[i] < off[i - 1]) {
 // ...

That's nice so far - it verifies that the offsets are ascending.  BUT:

 off[nsec] = policy_file_length(file);

Here, the check is missing.

But why is the file length 8192?  My base.pp has 6383597 bytes
(compressed), not 8192.  Let's break in policy_file_length():

 (gdb) p prev_offset 
 $4 = 28
 (gdb) p end_offset 
 $5 = 8192
 (gdb) p fp->fp
 $6 = (FILE *) 0x1c42350
 (gdb) p fileno(fp->fp)
 $7 = -1

But why is the file descriptor negative?  sepol_module_package_read()
is called by semanage_load_module(), which bunzips the file, closes
it, reopens it with fmemopen().  fmemopen has no file descriptor,
that's why it's negative.  Is there another bug in glibc?

fmemopen_seek():

    case SEEK_END:
      np = c->maxpos - *p;

What is c->maxpos?  Let's look it up in fmemopen():

  c->size = len;
  c->maxpos = strlen (c->buffer);

WTF!

Bottom line is:

- libsepol misses proper input validation, which may lead to an
  integer underflow and a ridiculously huge allocation.

- in glibc, fmemopen_seek() works only with null-terminated strings.

Is that enough information?

Max



-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to