Commit 02e2fa77 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Implementation of inter-process NtMapViewOfSection and NtUnmapViewOfSection.

parent 8025f79c
...@@ -403,7 +403,66 @@ static void test_MapViewOfFile(void) ...@@ -403,7 +403,66 @@ static void test_MapViewOfFile(void)
GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
CloseHandle( file ); CloseHandle( file );
DeleteFileA( testfile );
}
static DWORD (WINAPI *pNtMapViewOfSection)( HANDLE handle, HANDLE process, PVOID *addr_ptr,
ULONG zero_bits, SIZE_T commit_size,
const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr,
ULONG inherit, ULONG alloc_type, ULONG protect );
static DWORD (WINAPI *pNtUnmapViewOfSection)( HANDLE process, PVOID addr );
static void test_NtMapViewOfSection(void)
{
HANDLE hProcess;
static const char testfile[] = "testfile.xxx";
static const char data[] = "test data for NtMapViewOfSection";
char buffer[sizeof(data)];
HANDLE file, mapping;
void *ptr;
BOOL ret;
DWORD status, written;
SIZE_T size, result;
LARGE_INTEGER offset;
pNtMapViewOfSection = (void *)GetProcAddress( GetModuleHandle("ntdll.dll"), "NtMapViewOfSection" );
pNtUnmapViewOfSection = (void *)GetProcAddress( GetModuleHandle("ntdll.dll"), "NtUnmapViewOfSection" );
if (!pNtMapViewOfSection || !pNtUnmapViewOfSection)
{
skip( "NtMapViewOfSection not found\n" );
return;
}
file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
WriteFile( file, data, sizeof(data), &written, NULL );
SetFilePointer( file, 4096, NULL, FILE_BEGIN );
SetEndOfFile( file );
/* read/write mapping */
mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
ok( mapping != 0, "CreateFileMapping failed\n" );
hProcess = create_target_process("sleep");
ok(hProcess != NULL, "Can't start process\n");
ptr = NULL;
size = 0;
offset.QuadPart = 0;
status = pNtMapViewOfSection( mapping, hProcess, &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
ok( !status, "NtMapViewOfSection failed status %x\n", status );
ret = ReadProcessMemory( hProcess, ptr, buffer, sizeof(buffer), &result );
ok( ret, "ReadProcessMemory failed\n" );
ok( result == sizeof(buffer), "ReadProcessMemory didn't read all data (%lx)\n", result );
ok( !memcmp( buffer, data, sizeof(buffer) ), "Wrong data read\n" );
status = pNtUnmapViewOfSection( hProcess, ptr );
ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
CloseHandle( mapping );
CloseHandle( file ); CloseHandle( file );
DeleteFileA( testfile ); DeleteFileA( testfile );
} }
...@@ -439,4 +498,5 @@ START_TEST(virtual) ...@@ -439,4 +498,5 @@ START_TEST(virtual)
test_VirtualAllocEx(); test_VirtualAllocEx();
test_VirtualAlloc(); test_VirtualAlloc();
test_MapViewOfFile(); test_MapViewOfFile();
test_NtMapViewOfSection();
} }
...@@ -780,6 +780,26 @@ static BOOL call_apcs( BOOL alertable ) ...@@ -780,6 +780,26 @@ static BOOL call_apcs( BOOL alertable )
&result.virtual_unlock.addr, &result.virtual_unlock.addr,
&result.virtual_unlock.size, 0 ); &result.virtual_unlock.size, 0 );
break; break;
case APC_MAP_VIEW:
{
LARGE_INTEGER offset;
result.type = call.type;
result.map_view.addr = call.map_view.addr;
result.map_view.size = call.map_view.size;
offset.u.LowPart = call.map_view.offset_low;
offset.u.HighPart = call.map_view.offset_high;
result.map_view.status = NtMapViewOfSection( call.map_view.handle, NtCurrentProcess(),
&result.map_view.addr, call.map_view.zero_bits,
0, &offset, &result.map_view.size, ViewShare,
call.map_view.alloc_type, call.map_view.prot );
NtClose( call.map_view.handle );
break;
}
case APC_UNMAP_VIEW:
result.type = call.type;
result.unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(),
call.unmap_view.addr );
break;
case APC_CREATE_THREAD: case APC_CREATE_THREAD:
{ {
CLIENT_ID id; CLIENT_ID id;
......
...@@ -1960,17 +1960,36 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p ...@@ -1960,17 +1960,36 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
TRACE("handle=%p process=%p addr=%p off=%x%08x size=%lx access=%x\n", TRACE("handle=%p process=%p addr=%p off=%x%08x size=%lx access=%x\n",
handle, process, *addr_ptr, offset.u.HighPart, offset.u.LowPart, size, protect ); handle, process, *addr_ptr, offset.u.HighPart, offset.u.LowPart, size, protect );
if (!is_current_process( process ))
{
ERR("Unsupported on other process\n");
return STATUS_ACCESS_DENIED;
}
/* Check parameters */ /* Check parameters */
if ((offset.u.LowPart & mask) || (*addr_ptr && ((UINT_PTR)*addr_ptr & mask))) if ((offset.u.LowPart & mask) || (*addr_ptr && ((UINT_PTR)*addr_ptr & mask)))
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
call.map_view.type = APC_MAP_VIEW;
call.map_view.handle = handle;
call.map_view.addr = *addr_ptr;
call.map_view.size = *size_ptr;
call.map_view.offset_low = offset.u.LowPart;
call.map_view.offset_high = offset.u.HighPart;
call.map_view.zero_bits = zero_bits;
call.map_view.alloc_type = alloc_type;
call.map_view.prot = protect;
res = NTDLL_queue_process_apc( process, &call, &result );
if (res != STATUS_SUCCESS) return res;
if (result.map_view.status == STATUS_SUCCESS)
{
*addr_ptr = result.map_view.addr;
*size_ptr = result.map_view.size;
}
return result.map_view.status;
}
SERVER_START_REQ( get_mapping_info ) SERVER_START_REQ( get_mapping_info )
{ {
req->handle = handle; req->handle = handle;
...@@ -2107,11 +2126,18 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) ...@@ -2107,11 +2126,18 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
sigset_t sigset; sigset_t sigset;
void *base = ROUND_ADDR( addr, page_mask ); void *base = ROUND_ADDR( addr, page_mask );
if (!is_current_process( process )) if (process != NtCurrentProcess())
{ {
ERR("Unsupported on other process\n"); apc_call_t call;
return STATUS_ACCESS_DENIED; apc_result_t result;
call.unmap_view.type = APC_UNMAP_VIEW;
call.unmap_view.addr = addr;
status = NTDLL_queue_process_apc( process, &call, &result );
if (status == STATUS_SUCCESS) status = result.unmap_view.status;
return status;
} }
server_enter_uninterrupted_section( &csVirtual, &sigset ); server_enter_uninterrupted_section( &csVirtual, &sigset );
if ((view = VIRTUAL_FindView( base )) && (base == view->base)) if ((view = VIRTUAL_FindView( base )) && (base == view->base))
{ {
......
...@@ -222,6 +222,8 @@ enum apc_type ...@@ -222,6 +222,8 @@ enum apc_type
APC_VIRTUAL_FLUSH, APC_VIRTUAL_FLUSH,
APC_VIRTUAL_LOCK, APC_VIRTUAL_LOCK,
APC_VIRTUAL_UNLOCK, APC_VIRTUAL_UNLOCK,
APC_MAP_VIEW,
APC_UNMAP_VIEW,
APC_CREATE_THREAD APC_CREATE_THREAD
}; };
...@@ -298,6 +300,23 @@ typedef union ...@@ -298,6 +300,23 @@ typedef union
struct struct
{ {
enum apc_type type; enum apc_type type;
obj_handle_t handle;
void *addr;
unsigned long size;
unsigned int offset_low;
unsigned int offset_high;
unsigned int zero_bits;
unsigned int alloc_type;
unsigned int prot;
} map_view;
struct
{
enum apc_type type;
void *addr;
} unmap_view;
struct
{
enum apc_type type;
void (__stdcall *func)(void*); void (__stdcall *func)(void*);
void *arg; void *arg;
unsigned long reserve; unsigned long reserve;
...@@ -368,6 +387,18 @@ typedef union ...@@ -368,6 +387,18 @@ typedef union
{ {
enum apc_type type; enum apc_type type;
unsigned int status; unsigned int status;
void *addr;
unsigned long size;
} map_view;
struct
{
enum apc_type type;
unsigned int status;
} unmap_view;
struct
{
enum apc_type type;
unsigned int status;
thread_id_t tid; thread_id_t tid;
obj_handle_t handle; obj_handle_t handle;
} create_thread; } create_thread;
...@@ -4593,6 +4624,6 @@ union generic_reply ...@@ -4593,6 +4624,6 @@ union generic_reply
struct query_symlink_reply query_symlink_reply; struct query_symlink_reply query_symlink_reply;
}; };
#define SERVER_PROTOCOL_VERSION 272 #define SERVER_PROTOCOL_VERSION 273
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -238,6 +238,8 @@ enum apc_type ...@@ -238,6 +238,8 @@ enum apc_type
APC_VIRTUAL_FLUSH, APC_VIRTUAL_FLUSH,
APC_VIRTUAL_LOCK, APC_VIRTUAL_LOCK,
APC_VIRTUAL_UNLOCK, APC_VIRTUAL_UNLOCK,
APC_MAP_VIEW,
APC_UNMAP_VIEW,
APC_CREATE_THREAD APC_CREATE_THREAD
}; };
...@@ -313,6 +315,23 @@ typedef union ...@@ -313,6 +315,23 @@ typedef union
} virtual_unlock; } virtual_unlock;
struct struct
{ {
enum apc_type type; /* APC_MAP_VIEW */
obj_handle_t handle; /* mapping handle */
void *addr; /* requested address */
unsigned long size; /* allocation size */
unsigned int offset_low;/* file offset */
unsigned int offset_high;
unsigned int zero_bits; /* allocation alignment */
unsigned int alloc_type;/* allocation type */
unsigned int prot; /* memory protection flags */
} map_view;
struct
{
enum apc_type type; /* APC_UNMAP_VIEW */
void *addr; /* view address */
} unmap_view;
struct
{
enum apc_type type; /* APC_CREATE_THREAD */ enum apc_type type; /* APC_CREATE_THREAD */
void (__stdcall *func)(void*); /* start function */ void (__stdcall *func)(void*); /* start function */
void *arg; /* argument for start function */ void *arg; /* argument for start function */
...@@ -382,6 +401,18 @@ typedef union ...@@ -382,6 +401,18 @@ typedef union
} virtual_unlock; } virtual_unlock;
struct struct
{ {
enum apc_type type; /* APC_MAP_VIEW */
unsigned int status; /* status returned by call */
void *addr; /* resulting address */
unsigned long size; /* resulting size */
} map_view;
struct
{
enum apc_type type; /* APC_MAP_VIEW */
unsigned int status; /* status returned by call */
} unmap_view;
struct
{
enum apc_type type; /* APC_CREATE_THREAD */ enum apc_type type; /* APC_CREATE_THREAD */
unsigned int status; /* status returned by call */ unsigned int status; /* status returned by call */
thread_id_t tid; /* thread id */ thread_id_t tid; /* thread id */
......
...@@ -1164,11 +1164,27 @@ DECL_HANDLER(queue_apc) ...@@ -1164,11 +1164,27 @@ DECL_HANDLER(queue_apc)
case APC_VIRTUAL_FLUSH: case APC_VIRTUAL_FLUSH:
case APC_VIRTUAL_LOCK: case APC_VIRTUAL_LOCK:
case APC_VIRTUAL_UNLOCK: case APC_VIRTUAL_UNLOCK:
case APC_UNMAP_VIEW:
process = get_process_from_handle( req->process, PROCESS_VM_OPERATION ); process = get_process_from_handle( req->process, PROCESS_VM_OPERATION );
break; break;
case APC_VIRTUAL_QUERY: case APC_VIRTUAL_QUERY:
process = get_process_from_handle( req->process, PROCESS_QUERY_INFORMATION ); process = get_process_from_handle( req->process, PROCESS_QUERY_INFORMATION );
break; break;
case APC_MAP_VIEW:
process = get_process_from_handle( req->process, PROCESS_VM_OPERATION );
if (process)
{
/* duplicate the handle into the target process */
obj_handle_t handle = duplicate_handle( current->process, apc->call.map_view.handle,
process, 0, 0, DUP_HANDLE_SAME_ACCESS );
if (handle) apc->call.map_view.handle = handle;
else
{
release_object( process );
process = NULL;
}
}
break;
case APC_CREATE_THREAD: case APC_CREATE_THREAD:
process = get_process_from_handle( req->process, PROCESS_CREATE_THREAD ); process = get_process_from_handle( req->process, PROCESS_CREATE_THREAD );
break; break;
......
...@@ -150,6 +150,15 @@ static void dump_apc_call( const apc_call_t *call ) ...@@ -150,6 +150,15 @@ static void dump_apc_call( const apc_call_t *call )
fprintf( stderr, "APC_VIRTUAL_UNLOCK,addr=%p,size=%lu", fprintf( stderr, "APC_VIRTUAL_UNLOCK,addr=%p,size=%lu",
call->virtual_unlock.addr, call->virtual_unlock.size ); call->virtual_unlock.addr, call->virtual_unlock.size );
break; break;
case APC_MAP_VIEW:
fprintf( stderr, "APC_MAP_VIEW,handle=%p,addr=%p,size=%lu,offset=%x%08x,zero_bits=%u,alloc_type=%x,prot=%x",
call->map_view.handle, call->map_view.addr, call->map_view.size,
call->map_view.offset_high, call->map_view.offset_low, call->map_view.zero_bits,
call->map_view.alloc_type, call->map_view.prot );
break;
case APC_UNMAP_VIEW:
fprintf( stderr, "APC_UNMAP_VIEW,addr=%p", call->unmap_view.addr );
break;
case APC_CREATE_THREAD: case APC_CREATE_THREAD:
fprintf( stderr, "APC_CREATE_THREAD,func=%p,arg=%p,reserve=%lx,commit=%lx,suspend=%u", fprintf( stderr, "APC_CREATE_THREAD,func=%p,arg=%p,reserve=%lx,commit=%lx,suspend=%u",
call->create_thread.func, call->create_thread.arg, call->create_thread.func, call->create_thread.arg,
...@@ -209,6 +218,15 @@ static void dump_apc_result( const apc_result_t *result ) ...@@ -209,6 +218,15 @@ static void dump_apc_result( const apc_result_t *result )
get_status_name( result->virtual_unlock.status ), get_status_name( result->virtual_unlock.status ),
result->virtual_unlock.addr, result->virtual_unlock.size ); result->virtual_unlock.addr, result->virtual_unlock.size );
break; break;
case APC_MAP_VIEW:
fprintf( stderr, "APC_MAP_VIEW,status=%s,addr=%p,size=%lu",
get_status_name( result->map_view.status ),
result->map_view.addr, result->map_view.size );
break;
case APC_UNMAP_VIEW:
fprintf( stderr, "APC_UNMAP_VIEW,status=%s",
get_status_name( result->unmap_view.status ) );
break;
case APC_CREATE_THREAD: case APC_CREATE_THREAD:
fprintf( stderr, "APC_CREATE_THREAD,status=%s,tid=%04x,handle=%p", fprintf( stderr, "APC_CREATE_THREAD,status=%s,tid=%04x,handle=%p",
get_status_name( result->create_thread.status ), get_status_name( result->create_thread.status ),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment