https://bugs.winehq.org/show_bug.cgi?id=25600
Michael Müller michael@fds-team.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |michael@fds-team.de
--- Comment #13 from Michael Müller michael@fds-team.de --- Hi,
today I spent some time to figure out why Skype causes a segmentation fault on some systems. The root of this issue is not an invalid memory access but instead Skype tries to execute a syscall using SYSENTER (I am on an intel system).
The problem is now that the linux kernel does not understand the syscall and returns with an error. The way how the return address is specified for such a syscall differs between windows and linux - and instead of going back to the program code of Skype, the kernel returns to the __kernel_vsyscall function inside of glibc. The next problem is that the Linux kernel changed the stack pointer during the syscall, but did not reset it back to the one specified by Skype, since this also works different between Windows and Linux. The stack pointer is now invalid and the __kernel_vsyscall function tries to pop a value from the stack causing a segmentation fault.
This segmentation fault is now handled by Wine. To do this wine calls the function setup_exception_record() and checks the stack pointer. The invalid stack is now detected, but the code only prints a warning and continues anyway:
---- snip ---- if (stack - 1 > stack || /* check for overflow in subtraction */ (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack || (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase) { WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n", GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); } ---- snip ----
Wine is now going to deference the invalid pointer:
---- snip ---- stack->ret_addr = (void *)0xdeadbabe; ---- snip ----
This results in a second segmentation fault inside the signal handler for the original segmentation fault causing the kernel to kill the process.
However, we can not really fix this problem since it is impossible for us to detect whether this is a regular linux syscall or a windows syscall. Moreover some of the information which would be necessary to emulate such a syscall are destroyed by the linux kernel. Setting the windows version to windows 2000 forces Skype to use interrupts instead, which would be much easier to emulate.
For those who are interested in which syscall Skype tries to execute, I decoded the necessary information. The syscall number is 0xad which is NtQuerySystemInformation on Windows XP and the parameters are: 0xb, 0x5ac0, 0x7c8, 0x2e5e848. The value 0xb specifies the information class SystemModuleInformation. So what Skype is trying to execute using syscalls / interrupts is: NtQuerySystemInformation(SystemModuleInformation, 0x5ac0, 0x7c8, 0x2e5e848); The Linux kernel btw. interprets the same syscall as sys_rt_sigreturn.
As I already mentioned above, there is not much we can do about this since we can not catch such wrong syscalls before they reach the linux kernel and this is most probably WON'T FIX - at least the code path for > Win2000, interrupt emulation is easy compared to that.
Regards, Michael