From 1ea968016f1eaa9fada60a328e6f310fa0d5d7e3 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 15 Jan 2007 22:30:04 +0100 Subject: [PATCH] ntdll: Implementation of inter-process VirtualProtectEx. --- dlls/kernel32/tests/virtual.c | 16 ++++++---------- dlls/ntdll/sync.c | 10 ++++++++++ dlls/ntdll/virtual.c | 21 ++++++++++++++++++--- include/wine/server_protocol.h | 20 ++++++++++++++++++-- server/protocol.def | 18 +++++++++++++++++- server/thread.c | 1 + server/trace.c | 11 +++++++++++ 7 files changed, 81 insertions(+), 16 deletions(-) diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c index 3c64a068a2a..d19818c87aa 100644 --- a/dlls/kernel32/tests/virtual.c +++ b/dlls/kernel32/tests/virtual.c @@ -118,7 +118,7 @@ static void test_VirtualAllocEx(void) SetLastError(0xdeadbeef); ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot), "VirtualProtectEx should fail on a not committed memory\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ || + ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ || GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */ "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); @@ -141,21 +141,17 @@ static void test_VirtualAllocEx(void) SetLastError(0xdeadbeef); ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot), "VirtualProtectEx should fail on a not committed memory\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ || + ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ || GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */ "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); old_prot = 0; - todo_wine ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READONLY, - &old_prot), "VirtualProtectEx failed\n"); - todo_wine ok(old_prot == PAGE_NOACCESS, - "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot); + ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtectEx failed\n"); + ok(old_prot == PAGE_NOACCESS, "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot); old_prot = 0; - todo_wine ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READWRITE, - &old_prot), "VirtualProtectEx failed\n"); - todo_wine ok(old_prot == PAGE_READONLY, - "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot); + ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtectEx failed\n"); + ok(old_prot == PAGE_READONLY, "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot); ok(!VirtualFreeEx(hProcess, addr1, 0x10000, 0), "VirtualFreeEx should fail with type 0\n"); diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index e0eb2d4645b..8cfd1e5f83a 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -746,6 +746,16 @@ static BOOL call_apcs( BOOL alertable ) } break; } + case APC_VIRTUAL_PROTECT: + result.type = call.type; + result.virtual_protect.addr = call.virtual_protect.addr; + result.virtual_protect.size = call.virtual_protect.size; + result.virtual_protect.status = NtProtectVirtualMemory( NtCurrentProcess(), + &result.virtual_protect.addr, + &result.virtual_protect.size, + call.virtual_protect.prot, + &result.virtual_protect.prot ); + break; default: server_protocol_error( "get_apc_request: bad type %d\n", call.type ); break; diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 0407a213078..57cbb20941a 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -1597,10 +1597,25 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T TRACE("%p %p %08lx %08x\n", process, addr, size, new_prot ); - if (!is_current_process( process )) + if (process != NtCurrentProcess()) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; + apc_call_t call; + apc_result_t result; + + call.virtual_protect.type = APC_VIRTUAL_PROTECT; + call.virtual_protect.addr = addr; + call.virtual_protect.size = size; + call.virtual_protect.prot = new_prot; + status = NTDLL_queue_process_apc( process, &call, &result ); + if (status != STATUS_SUCCESS) return status; + + if (result.virtual_protect.status == STATUS_SUCCESS) + { + *addr_ptr = result.virtual_protect.addr; + *size_ptr = result.virtual_protect.size; + if (old_prot) *old_prot = result.virtual_protect.prot; + } + return result.virtual_protect.status; } /* Fix the parameters */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 60715ff0d5c..890dabd294f 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -217,7 +217,8 @@ enum apc_type APC_ASYNC_IO, APC_VIRTUAL_ALLOC, APC_VIRTUAL_FREE, - APC_VIRTUAL_QUERY + APC_VIRTUAL_QUERY, + APC_VIRTUAL_PROTECT }; typedef union @@ -265,6 +266,13 @@ typedef union enum apc_type type; const void *addr; } virtual_query; + struct + { + enum apc_type type; + void *addr; + unsigned long size; + unsigned int prot; + } virtual_protect; } apc_call_t; typedef union @@ -296,6 +304,14 @@ typedef union unsigned int alloc_prot; unsigned int alloc_type; } virtual_query; + struct + { + enum apc_type type; + unsigned int status; + void *addr; + unsigned long size; + unsigned int prot; + } virtual_protect; } apc_result_t; @@ -4517,6 +4533,6 @@ union generic_reply struct query_symlink_reply query_symlink_reply; }; -#define SERVER_PROTOCOL_VERSION 267 +#define SERVER_PROTOCOL_VERSION 268 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index b24e27546f0..8c40e106952 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -233,7 +233,8 @@ enum apc_type APC_ASYNC_IO, APC_VIRTUAL_ALLOC, APC_VIRTUAL_FREE, - APC_VIRTUAL_QUERY + APC_VIRTUAL_QUERY, + APC_VIRTUAL_PROTECT }; typedef union @@ -281,6 +282,13 @@ typedef union enum apc_type type; /* APC_VIRTUAL_QUERY */ const void *addr; /* requested address */ } virtual_query; + struct + { + enum apc_type type; /* APC_VIRTUAL_PROTECT */ + void *addr; /* requested address */ + unsigned long size; /* requested address */ + unsigned int prot; /* new protection flags */ + } virtual_protect; } apc_call_t; typedef union @@ -312,6 +320,14 @@ typedef union unsigned int alloc_prot;/* resulting allocation protection */ unsigned int alloc_type;/* resulting region allocation type */ } virtual_query; + struct + { + enum apc_type type; /* APC_VIRTUAL_PROTECT */ + unsigned int status; /* status returned by call */ + void *addr; /* resulting address */ + unsigned long size; /* resulting size */ + unsigned int prot; /* old protection flags */ + } virtual_protect; } apc_result_t; /****************************************************************/ diff --git a/server/thread.c b/server/thread.c index 62bd559f596..35484a41b74 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1157,6 +1157,7 @@ DECL_HANDLER(queue_apc) case APC_VIRTUAL_ALLOC: case APC_VIRTUAL_FREE: case APC_VIRTUAL_QUERY: + case APC_VIRTUAL_PROTECT: access = (apc->call.type == APC_VIRTUAL_QUERY) ? PROCESS_QUERY_INFORMATION : PROCESS_VM_OPERATION; if ((process = get_process_from_handle( req->process, access ))) { diff --git a/server/trace.c b/server/trace.c index 2b9ee8caf84..b878c0278ef 100644 --- a/server/trace.c +++ b/server/trace.c @@ -133,6 +133,11 @@ static void dump_apc_call( const apc_call_t *call ) case APC_VIRTUAL_QUERY: fprintf( stderr, "APC_VIRTUAL_QUERY,addr=%p", call->virtual_query.addr ); break; + case APC_VIRTUAL_PROTECT: + fprintf( stderr, "APC_VIRTUAL_PROTECT,addr=%p,size=%lu,prot=%x", + call->virtual_protect.addr, call->virtual_protect.size, + call->virtual_protect.prot ); + break; default: fprintf( stderr, "type=%u", call->type ); break; @@ -165,6 +170,12 @@ static void dump_apc_result( const apc_result_t *result ) result->virtual_query.prot, result->virtual_query.alloc_prot, result->virtual_query.alloc_type ); break; + case APC_VIRTUAL_PROTECT: + fprintf( stderr, "APC_VIRTUAL_PROTECT,status=%s,addr=%p,size=%lu,prot=%x", + get_status_name( result->virtual_protect.status ), + result->virtual_protect.addr, result->virtual_protect.size, + result->virtual_protect.prot ); + break; default: fprintf( stderr, "type=%u", result->type ); break;