story about lost %ebx (stack corruption in inet_aton ?)
Yuriy Tsibizov
Yuriy.Tsibizov at gfk.com
Mon Dec 17 22:35:10 PST 2007
(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.
More information about the freebsd-current
mailing list