Messages in this thread | | | Date | Sun, 30 Aug 2009 20:16:37 +0200 | From | Bastian Blank <> | Subject | 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 [unhandled content-type:application/pgp-signature] | |