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

Bug#233996: libc6: non-debug binaries do odd things to the stack



Package: libc6
Version: 2.3.2.ds1-11
Severity: important
Tags: security

The non-debug libc6 binaries do strange things to the stack.  I haven't
figured out the specifics to this bug, but I have found two ways to
reliably reproduce the problem.

Method 1:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	printf("aborting...\n");

	abort();
}
		
Resulting stack trace on abort():
#0  0xffffe410 in __kernel_vsyscall ()
#1  0x4005acf3 in raise () from /lib/tls/i686/cmov/libc.so.6
#2  0x4016706c in ?? () from /lib/tls/i686/cmov/libc.so.6

Resulting (expected) stack trace with libc6-dbg:
#0  0x40041571 in kill () from /usr/lib/debug/libc.so.6
#1  0x40041315 in *__GI_raise (sig=6)
    at ../linuxthreads/sysdeps/unix/sysv/linux/raise.c:32
#2  0x40042838 in *__GI_abort () at ../sysdeps/generic/abort.c:88
#3  0x080483ae in main (argc=1, argv=0xbffff4b4) at test1.c:8


One other place I encountered the problem was while trying to walk the
stack in an LD_PRELOADed library that wrapped around gettimeofday().  I
used __builtin_frame_address (a gcc internal) to walk backwards through
the stack (the function is supposed to return 0 when the top of the stack
is reached.)  The results end with some characters of the program name
(which is stored after the stack) with a non-debug libc.

Method 2:
#include <time.h>
#include <stdio.h>
#include <sys/time.h>

#define STACKFRAME(x) \
	printf("%d: %p\n", x, __builtin_frame_address(x));	\
	fflush(stdout);						\
	if (__builtin_frame_address(x) == NULL)			\
		return 0;

int gettimeofday(struct timeval *tv, struct timezone *tz)
{
	if (tv != NULL) {
		tv->tv_sec = 946684800;
		tv->tv_usec = 0;
	}

	STACKFRAME(0) STACKFRAME(1) STACKFRAME(2) STACKFRAME(3)
	STACKFRAME(4) STACKFRAME(5) STACKFRAME(6) STACKFRAME(7)
	STACKFRAME(8) STACKFRAME(9) STACKFRAME(10) STACKFRAME(11)
	STACKFRAME(12) STACKFRAME(13) STACKFRAME(14) STACKFRAME(15)
	
	printf("16: [more...]\n");

	return 0;
}

Compile this code as a .so, and LD_PRELOAD it before running a program
that uses gettimeofday() (e.g. LD_PRELOAD=./test-gettimeofday.so top)

Resulting output:
0: 0xbfffeef8
1: 0xbfffef68
2: 0xbfffef88
3: 0xbffff0c8
4: 0xbffff358
5: 0xbffff428
6: 0xbffff4b4
7: 0xbffff615
8: 0x706f74
   ^^^^^^^^ 'top^@' in little endian.
[program crashes at this point]

Resulting (expected) output with libc6-dbg:
0: 0xbfffeef8
1: 0xbfffef68
2: 0xbfffef88
3: 0xbffff0c8
4: 0xbffff358
5: 0xbffff428
6: 0xbffff448
7: (nil)


Unfortunately, I haven't found any other ways to reproduce this with
a short test program.

The libsafe package is affected by this bug, because it relies on a
valid stack in order to determine whether or not a variable is stack or
heap, and the size of that variable should it reside on the stack.
Since libsafe always fails to determine that a variable is on the stack
(and presumes it's on the heap, instead), libsafe is rendered completely
ineffective, which is why I marked this bug with the 'security' tag.

Versions of relevant packages:
ii  gcc            3.3.2-2        The GNU C compiler
ii  libsafe        2.0-16-6       Protection against buffer overflow vulnerabi


-- System Information:
Debian Release: testing/unstable
  APT prefers unstable
  APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: i386 (i686)
Kernel: Linux 2.6.3
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8

Versions of packages libc6 depends on:
ii  libdb1-compat                 2.1.3-7    The Berkeley database routines [gl

-- no debconf information




Reply to: