[PATCH] ntdll: Add a shortcut to NtReadVirtualMemory for the local process
Andrew Wesie
awesie at gmail.com
Tue Oct 29 15:42:15 CDT 2019
On Tue, Oct 29, 2019 at 9:04 AM Martin Storsjo <martin at 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
More information about the wine-devel
mailing list