On Tue, Oct 29, 2019 at 9:04 AM Martin Storsjo <martin(a)martin.st> wrote:
... Therefore, exception handling in executables with libunwind on i686 doesn't work when run with wine within docker.
I personally don't think this is a great rationale for changing the behavior of wine. It sounds like a rationale for docker to allow SYS_PTRACE. But I am not a wine maintainer, so my only real concern is that the correctness of NtReadVirtualMemory is not affected as it is used by anti-cheat and other programs.
... + server_enter_uninterrupted_section( &csVirtual, &sigset ); + if (virtual_check_buffer_for_read( addr, size )) + { + memcpy(buffer, addr, size); + status = STATUS_SUCCESS; + }
This does not have the same semantics as the original code. The original code used kernel system calls (e.g. pread) which will not cause a page fault. virtual_check_buffer_for_read explicitly reads each page to trigger a fault. At a minimum, this causes the behavior to diverge from Windows for guard pages. It may have other differences as well. A potential fix may be to implement something similar to virtual_uninterrupted_read_memory. Or use kernel system calls (e.g. read, write, pread, etc.) to access the memory, which will not cause a page fault. In any case, I think more testing is needed. Here is a sample program using VPROT_GUARD that triggers divergent behavior: #include <windows.h> #include <stdio.h> typedef NTSTATUS WINAPI (*pNtReadVirtualMemory)( HANDLE, const void *, void *, SIZE_T, SIZE_T *); int main() { char tmp[64]; char *p; HANDLE ntdll; NTSTATUS status; SIZE_T bytes_read; ntdll = GetModuleHandle("ntdll"); pNtReadVirtualMemory NtReadVirtualMemory = (pNtReadVirtualMemory)GetProcAddress(ntdll, "NtReadVirtualMemory"); p = (char *)VirtualAlloc(NULL, 0x10000, MEM_COMMIT | MEM_RESERVE, PAGE_GUARD | PAGE_READWRITE); printf("p = %p\n", p); status = NtReadVirtualMemory(GetCurrentProcess(), p, tmp, sizeof(tmp), &bytes_read); printf("status = %x\n", status); status = NtReadVirtualMemory(GetCurrentProcess(), p, tmp, sizeof(tmp), &bytes_read); printf("status = %x\n", status); return 0; } -Andrew