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

Bug#544145: 32bit binaries on x86_64/Xen segfaults in syscall-vdso



Hi folks

I upgraded one of my 32bit chroots on a x86-64 machine runing under Xen
lately. All binaries started to segfault. Some extensive checks later
show the vdso as the culprit. Later I found <gpe0vg$j67$1@ger.gmane.org>
with the same problem. The full story can be found in the Debian bug
544145[1].

It happens with Linux 2.6.30 and 2.6.31-rc8 on Xen 3.2 and 3.4.

For the tests I set the vdso to compat mode to have it loaded on a fixed
location.

The following program is a minimal test case for the vdso in compat
mode, it can be compiled against dietlibc to minimize other effects.

| int main() {
|   unsigned int resultvar;
|   asm volatile (
|     "movl %1, %%eax\n\t"
|     "call 0xffffe420\n\t"
|     : "=a" (resultvar) : "i" (0) : "memory", "cc");
| }
| (gdb) run
| Starting program: /test 
| 
| Program received signal SIGSEGV, Segmentation fault.
| 0xffffe42f in ?? ()
| (gdb) bt
| #0  0xffffe42f in ?? ()
| #1  0xf7eb17a5 in __libc_start_main (main=0x8048394 <main>, argc=1, ubp_av=0xffffd884, init=0x80483d0 <__libc_csu_init>, 
|     fini=0x80483c0 <__libc_csu_fini>, rtld_fini=0xf7fee6e0 <_dl_fini>, stack_end=0xffffd87c) at libc-start.c:222
| #2  0x08048301 in _start () at ../sysdeps/i386/elf/start.S:119
| (gdb) disassemble 0xffffe420 0xffffe430
| Dump of assembler code from 0xffffe420 to 0xffffe430:
| 0xffffe420:     push   %ebp
| 0xffffe421:     mov    %ecx,%ebp
| 0xffffe423:     syscall 
| 0xffffe425:     mov    $0x2b,%ecx
| 0xffffe42a:     mov    %ecx,%ss
| 0xffffe42c:     mov    %ebp,%ecx
| 0xffffe42e:     pop    %ebp
| 0xffffe42f:     ret    
| End of assembler dump.

It segfaults on the ret opcode, in some variants also directly after the
ret. If I single-step over the syscall opcode it works. The register
contents slightly differ in this case.

Break on last opcode, state at the last opcode:
| (gdb) b *0xffffe42f
| Breakpoint 7 at 0xffffe42f
| (gdb) run
| Starting program: /test
| 
| Breakpoint 7, 0xffffe42f in ?? ()
| (gdb) info registers
| eax            0xfffffffc       -4
| ecx            0xffffd800       -10240
| edx            0xffffd820       -10208
| ebx            0xf7fd7ff4       -134381580
| esp            0xffffd7d0       0xffffd7d0
| ebp            0xffffd7e8       0xffffd7e8
| esi            0x80483d0        134513616
| edi            0x80482e0        134513376
| eip            0xffffe42f       0xffffe42f
| eflags         0x282    [ SF IF ]
| cs             0xe033   57395
| ss             0x2b     43
| ds             0x2b     43
| es             0x2b     43
| fs             0x0      0
| gs             0x63     99

Break on first opcode, state at the last opcode:
| (gdb) b *0xffffe420
| Breakpoint 8 at 0xffffe420
| (gdb) run
| Starting program: /test
| 
| Breakpoint 8, 0xffffe420 in ?? ()
| (gdb) stepi
| 0xffffe421 in ?? ()
[...]
| 0xffffe42f in ?? ()
| (gdb) info registers
| eax            0xfffffffc       -4
| ecx            0xffffd800       -10240
| edx            0xffffd820       -10208
| ebx            0xf7fd7ff4       -134381580
| esp            0xffffd7cc       0xffffd7cc
| ebp            0xffffd7e8       0xffffd7e8
| esi            0x80483d0        134513616
| edi            0x80482e0        134513376
| eip            0xffffe42f       0xffffe42f
| eflags         0x282    [ SF IF ]
| cs             0x23     35
| ss             0x2b     43
| ds             0x2b     43
| es             0x2b     43
| fs             0x0      0
| gs             0x63     99

The stack pointer and code segment are different in this two cases.

I think I found the problem. In the normal codeflow, sysret is used to
return as expected. In the compat codeflow, iret is used.

Bastian

[1]: http://bugs.debian.org/544145
-- 
Wait!  You have not been prepared!
		-- Mr. Atoz, "Tomorrow is Yesterday", stardate 3113.2

Attachment: signature.asc
Description: Digital signature


Reply to: