On Tue, Oct 29, 2019 at 9:04 AM Martin Storsjo martin@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