story about lost %ebx (stack corruption in inet_aton ?)

From: Yuriy Tsibizov <Yuriy.Tsibizov_at_gfk.com>
Date: Tue, 18 Dec 2007 09:35:51 +0300
(this is an update to 'story about lost %ebx (gcc bug?)' mail that seems
to wait for moderato approval)

My first impression was that there is a bug in gcc compiler on 7-BETA
and 8-CURRENT (i386 only, and only if optimization is enabled), but it
seems to be incorrect. Most probably source is stack corruption in
inet_aton()

How to reproduce:
1) Get i386 version of 7-BETA or 8-CURRENT (amd64 does not expose this
bug)
2) make shure you build with default options (empty /etc/make.conf)
3) /sbin/route add 172.17.1.0.0/12 10.0.0.1 (yes, network address is
incorrect)
4) get core dump

core dump shows that in route.c q==NULL in last assignment of this code
block:
 --------
	q = strchr(s,'/');
	if (q && which == RTA_DST) {
		*q = '\0';
		if ((val = inet_network(s)) != INADDR_NONE) {
			inet_makenetandmask(
				val, &su->sin, strtoul(q+1, 0, 0));
			return (0);
		}
		*q = '/';
	}
 --------
with relevant asm output:
 --asm--- (-O1)
        movl    $47, 4(%esp)    #,
        movl    12(%ebp), %edx  # s,
        movl    %edx, (%esp)    #,
        call    strchr  #
        movl    %eax, %ebx      #, q.583
## %ebx is q.583

        testl   %eax, %eax      # q.583
        setne   %al     #, tmp160
        cmpl    $1, 8(%ebp)     #, which
        sete    -73(%ebp)       #, D.6325
        testb   %al, -73(%ebp)  # tmp160, D.6325
        je      .L419   #,
        movb    $0, (%ebx)      #,* q.583
        movl    12(%ebp), %eax  # s,
        movl    %eax, (%esp)    #,
        call    __inet_network  # 
## %ebx here should be == 0, because nothing change it below
        movl    %eax, %esi      #, D.6327
        cmpl    $-1, %eax       #, D.6327
        je      .L421   #,
        leal    1(%ebx), %eax   #, D.6328
        movl    $0, 8(%esp)     #,
        movl    $0, 4(%esp)     #,
        movl    %eax, (%esp)    # D.6328,
        call    strtoul #
        movl    %eax, 8(%esp)   # D.6329,
        movl    %edi, 4(%esp)   # su,
        movl    %esi, (%esp)    # D.6327,
        call    inet_makenetandmask     #
        movl    $0, %eax        #, D.6280 
        jmp     .L385   #
.L421:
## null pointer reference here
        movb    $47, (%ebx)     #,* q.583
.L419:  
 -- asm---


My findings so far:
for route.c (and 'broken' libc) :
1) code generated by gcc 4.2.1 for this part of route.c is correct for
-O0 and -O1. You can make it with CFLAGS=-save-temps -fverbose-asm and
check yourself.
2) if route is built with -O0 it will work well in any case. (will not
use %ebx)
3) if route is built with -O1 -fno-tree-lrs it will work well (it will
not use %ebx to keep q)
4) if -ftree-lrs is enabled with -O1 (or -O2) it will fail (because it
will use %ebx that seems to be == 0 after call to inet_network(s)).

for libc:
1) if libc is built with -O0 any optimization on route.c will work well
(it will not push/pop %ebx in __inet_network in libc)
2) if libc is built with -O1 -fno-tree-lrs route will coredump
(-fno-tree-lrs is only a workaround for route.c)
3) -O1 and -O2 libc will give you coredump

I checked inet_network.s asm output and can't find any obvious compiler
errors there.

The only reason for this (as I see now) is a stack corruption in
inet_aton that leads to old %ebx (pushed into stack) being replaced with
0x0 and then popped on return from inet_network.

Yuriy.
Received on Tue Dec 18 2007 - 05:35:10 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:24 UTC