From 6672fc9d8532fbf893a7ea11820f7b0f77a58a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 1 Aug 2019 10:07:44 +0200 Subject: [PATCH] ntdll: Use custom internal zero_bits_64 parameter format. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The zero_bits parameter can be a pointer mask on Win64 and WoW64 and it was incorrectly truncated to 16bits in APCs. Testing shows that only the leading zeroes are used in the mask, so we can safely use the 64 based number of leading zeroes everywhere instead. Signed-off-by: RĂ©mi Bernon Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/ntdll/ntdll_misc.h | 4 +- dlls/ntdll/server.c | 4 +- dlls/ntdll/virtual.c | 80 ++++++++++++++++++++++------------ include/wine/server_protocol.h | 4 +- server/protocol.def | 28 ++++++------ server/trace.c | 8 ++-- 6 files changed, 77 insertions(+), 51 deletions(-) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 1950d8c1c7e..5ddce437cfb 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -163,9 +163,9 @@ extern NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_S UINT disposition ) DECLSPEC_HIDDEN; /* virtual memory */ -extern NTSTATUS virtual_alloc_aligned( PVOID *ret, ULONG zero_bits, SIZE_T *size_ptr, +extern NTSTATUS virtual_alloc_aligned( PVOID *ret, unsigned short zero_bits_64, SIZE_T *size_ptr, ULONG type, ULONG protect, ULONG alignment ) DECLSPEC_HIDDEN; -extern NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, SIZE_T commit_size, +extern NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size, const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type, ULONG protect, pe_image_info_t *image_info ) DECLSPEC_HIDDEN; extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 16e73d497c4..204370a1b77 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -431,7 +431,7 @@ BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) if ((ULONG_PTR)addr == call->virtual_alloc.addr && size == call->virtual_alloc.size) { result->virtual_alloc.status = virtual_alloc_aligned( &addr, - call->virtual_alloc.zero_bits, &size, + call->virtual_alloc.zero_bits_64, &size, call->virtual_alloc.op_type, call->virtual_alloc.prot, 0 ); @@ -538,7 +538,7 @@ BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) offset.QuadPart = call->map_view.offset; result->map_view.status = virtual_map_section( wine_server_ptr_handle(call->map_view.handle), &addr, - call->map_view.zero_bits, 0, + call->map_view.zero_bits_64, 0, &offset, &size, call->map_view.alloc_type, call->map_view.prot, &image_info ); diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 57536eb6295..d651a16ff37 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -418,6 +418,30 @@ static inline UINT_PTR get_mask( ULONG alignment ) } +/*********************************************************************** + * zero_bits_win_to_64 + * + * Convert from Windows hybrid 32bit-based / bitmask to 64bit-based format + */ +static inline unsigned short zero_bits_win_to_64( ULONG_PTR zero_bits ) +{ + unsigned short zero_bits_64; + + if (zero_bits == 0) return 0; + if (zero_bits < 32) return 32 + zero_bits; + zero_bits_64 = 63; +#ifdef _WIN64 + if (zero_bits >> 32) { zero_bits_64 -= 32; zero_bits >>= 32; } +#endif + if (zero_bits >> 16) { zero_bits_64 -= 16; zero_bits >>= 16; } + if (zero_bits >> 8) { zero_bits_64 -= 8; zero_bits >>= 8; } + if (zero_bits >> 4) { zero_bits_64 -= 4; zero_bits >>= 4; } + if (zero_bits >> 2) { zero_bits_64 -= 2; zero_bits >>= 2; } + if (zero_bits >> 1) { zero_bits_64 -= 1; } + return zero_bits_64; +} + + /*********************************************************************** * is_write_watch_range */ @@ -1083,7 +1107,7 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot ) * The csVirtual section must be held by caller. */ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, size_t alignment, - int top_down, unsigned int vprot, size_t zero_bits ) + int top_down, unsigned int vprot, unsigned short zero_bits_64 ) { void *ptr; NTSTATUS status; @@ -1102,7 +1126,7 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, size_t view_size = size + mask + 1; struct alloc_area alloc; - if (zero_bits) + if (zero_bits_64) FIXME("Unimplemented zero_bits parameter value\n"); alloc.size = size; @@ -1361,7 +1385,7 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable ) * * Map an executable (PE format) image into memory. */ -static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_down, SIZE_T zero_bits, +static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_down, unsigned short zero_bits_64, pe_image_info_t *image_info, int shared_fd, BOOL removable, PVOID *addr_ptr ) { IMAGE_DOS_HEADER *dos; @@ -1392,11 +1416,11 @@ static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_ if (base >= (char *)address_space_start) /* make sure the DOS area remains free */ status = map_view( &view, base, total_size, 0, top_down, SEC_IMAGE | SEC_FILE | - VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits ); + VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits_64 ); if (status != STATUS_SUCCESS) status = map_view( &view, NULL, total_size, 0, top_down, SEC_IMAGE | SEC_FILE | - VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits ); + VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits_64 ); if (status != STATUS_SUCCESS) goto error; @@ -1611,7 +1635,7 @@ static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_ * * Map a file section into memory. */ -NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, SIZE_T commit_size, +NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size, const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type, ULONG protect, pe_image_info_t *image_info ) { @@ -1673,14 +1697,14 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, S if ((res = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA, &shared_fd, &shared_needs_close, NULL, NULL ))) goto done; - res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits, image_info, + res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits_64, image_info, shared_fd, needs_close, addr_ptr ); if (shared_needs_close) close( shared_fd ); close_handle( shared_file ); } else { - res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits, image_info, + res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits_64, image_info, -1, needs_close, addr_ptr ); } if (needs_close) close( unix_handle ); @@ -1718,7 +1742,7 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, S get_vprot_flags( protect, &vprot, sec_flags & SEC_IMAGE ); vprot |= sec_flags; if (!(sec_flags & SEC_RESERVE)) vprot |= VPROT_COMMITTED; - res = map_view( &view, *addr_ptr, size, 0, alloc_type & MEM_TOP_DOWN, vprot, zero_bits ); + res = map_view( &view, *addr_ptr, size, 0, alloc_type & MEM_TOP_DOWN, vprot, zero_bits_64 ); if (res) { server_leave_uninterrupted_section( &csVirtual, &sigset ); @@ -2506,6 +2530,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z { SIZE_T size = *size_ptr; NTSTATUS status = STATUS_SUCCESS; + unsigned short zero_bits_64 = zero_bits_win_to_64( zero_bits ); TRACE("%p %p %08lx %x %08x\n", process, *ret, size, type, protect ); @@ -2520,12 +2545,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z memset( &call, 0, sizeof(call) ); - call.virtual_alloc.type = APC_VIRTUAL_ALLOC; - call.virtual_alloc.addr = wine_server_client_ptr( *ret ); - call.virtual_alloc.size = *size_ptr; - call.virtual_alloc.zero_bits = zero_bits; - call.virtual_alloc.op_type = type; - call.virtual_alloc.prot = protect; + call.virtual_alloc.type = APC_VIRTUAL_ALLOC; + call.virtual_alloc.addr = wine_server_client_ptr( *ret ); + call.virtual_alloc.size = *size_ptr; + call.virtual_alloc.zero_bits_64 = zero_bits_64; + call.virtual_alloc.op_type = type; + call.virtual_alloc.prot = protect; status = server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; @@ -2537,7 +2562,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z return result.virtual_alloc.status; } - return virtual_alloc_aligned( ret, zero_bits, size_ptr, type, protect, 0 ); + return virtual_alloc_aligned( ret, zero_bits_64, size_ptr, type, protect, 0 ); } @@ -2546,7 +2571,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z * * Same as NtAllocateVirtualMemory but with an alignment parameter */ -NTSTATUS virtual_alloc_aligned( PVOID *ret, ULONG zero_bits, SIZE_T *size_ptr, +NTSTATUS virtual_alloc_aligned( PVOID *ret, unsigned short zero_bits_64, SIZE_T *size_ptr, ULONG type, ULONG protect, ULONG alignment ) { void *base; @@ -2608,7 +2633,7 @@ NTSTATUS virtual_alloc_aligned( PVOID *ret, ULONG zero_bits, SIZE_T *size_ptr, if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION; else if (is_dos_memory) status = allocate_dos_memory( &view, vprot ); - else status = map_view( &view, base, size, alignment, type & MEM_TOP_DOWN, vprot, zero_bits ); + else status = map_view( &view, base, size, alignment, type & MEM_TOP_DOWN, vprot, zero_bits_64 ); if (status == STATUS_SUCCESS) base = view->base; } @@ -3140,6 +3165,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p SIZE_T mask = get_mask( 0 ); pe_image_info_t image_info; LARGE_INTEGER offset; + unsigned short zero_bits_64 = zero_bits_win_to_64( zero_bits ); offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; @@ -3178,14 +3204,14 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p memset( &call, 0, sizeof(call) ); - call.map_view.type = APC_MAP_VIEW; - call.map_view.handle = wine_server_obj_handle( handle ); - call.map_view.addr = wine_server_client_ptr( *addr_ptr ); - call.map_view.size = *size_ptr; - call.map_view.offset = offset.QuadPart; - call.map_view.zero_bits = zero_bits; - call.map_view.alloc_type = alloc_type; - call.map_view.prot = protect; + call.map_view.type = APC_MAP_VIEW; + call.map_view.handle = wine_server_obj_handle( handle ); + call.map_view.addr = wine_server_client_ptr( *addr_ptr ); + call.map_view.size = *size_ptr; + call.map_view.offset = offset.QuadPart; + call.map_view.zero_bits_64 = zero_bits_64; + call.map_view.alloc_type = alloc_type; + call.map_view.prot = protect; res = server_queue_process_apc( process, &call, &result ); if (res != STATUS_SUCCESS) return res; @@ -3197,7 +3223,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p return result.map_view.status; } - return virtual_map_section( handle, addr_ptr, zero_bits, commit_size, + return virtual_map_section( handle, addr_ptr, zero_bits_64, commit_size, offset_ptr, size_ptr, alloc_type, protect, &image_info ); } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 392c944d6d9..4f350472417 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -484,7 +484,7 @@ typedef union unsigned int op_type; client_ptr_t addr; mem_size_t size; - unsigned int zero_bits; + unsigned int zero_bits_64; unsigned int prot; } virtual_alloc; struct @@ -536,7 +536,7 @@ typedef union mem_size_t size; file_pos_t offset; unsigned int alloc_type; - unsigned short zero_bits; + unsigned short zero_bits_64; unsigned short prot; } map_view; struct diff --git a/server/protocol.def b/server/protocol.def index 8157199f2fa..6af0ae0cff8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -496,12 +496,12 @@ typedef union } async_io; struct { - enum apc_type type; /* APC_VIRTUAL_ALLOC */ - unsigned int op_type; /* type of operation */ - client_ptr_t addr; /* requested address */ - mem_size_t size; /* allocation size */ - unsigned int zero_bits; /* allocation alignment */ - unsigned int prot; /* memory protection flags */ + enum apc_type type; /* APC_VIRTUAL_ALLOC */ + unsigned int op_type; /* type of operation */ + client_ptr_t addr; /* requested address */ + mem_size_t size; /* allocation size */ + unsigned int zero_bits_64; /* number of zero high bits */ + unsigned int prot; /* memory protection flags */ } virtual_alloc; struct { @@ -546,14 +546,14 @@ typedef union } virtual_unlock; struct { - enum apc_type type; /* APC_MAP_VIEW */ - obj_handle_t handle; /* mapping handle */ - client_ptr_t addr; /* requested address */ - mem_size_t size; /* allocation size */ - file_pos_t offset; /* file offset */ - unsigned int alloc_type;/* allocation type */ - unsigned short zero_bits; /* allocation alignment */ - unsigned short prot; /* memory protection flags */ + enum apc_type type; /* APC_MAP_VIEW */ + obj_handle_t handle; /* mapping handle */ + client_ptr_t addr; /* requested address */ + mem_size_t size; /* allocation size */ + file_pos_t offset; /* file offset */ + unsigned int alloc_type; /* allocation type */ + unsigned short zero_bits_64; /* number of zero high bits */ + unsigned short prot; /* memory protection flags */ } map_view; struct { diff --git a/server/trace.c b/server/trace.c index 0df649ea295..615542cff52 100644 --- a/server/trace.c +++ b/server/trace.c @@ -171,8 +171,8 @@ static void dump_apc_call( const char *prefix, const apc_call_t *call ) case APC_VIRTUAL_ALLOC: dump_uint64( "APC_VIRTUAL_ALLOC,addr==", &call->virtual_alloc.addr ); dump_uint64( ",size=", &call->virtual_alloc.size ); - fprintf( stderr, ",zero_bits=%u,op_type=%x,prot=%x", - call->virtual_alloc.zero_bits, call->virtual_alloc.op_type, + fprintf( stderr, ",zero_bits_64=%u,op_type=%x,prot=%x", + call->virtual_alloc.zero_bits_64, call->virtual_alloc.op_type, call->virtual_alloc.prot ); break; case APC_VIRTUAL_FREE: @@ -205,8 +205,8 @@ static void dump_apc_call( const char *prefix, const apc_call_t *call ) dump_uint64( ",addr=", &call->map_view.addr ); dump_uint64( ",size=", &call->map_view.size ); dump_uint64( ",offset=", &call->map_view.offset ); - fprintf( stderr, ",zero_bits=%u,alloc_type=%x,prot=%x", - call->map_view.zero_bits, call->map_view.alloc_type, call->map_view.prot ); + fprintf( stderr, ",zero_bits_64=%u,alloc_type=%x,prot=%x", + call->map_view.zero_bits_64, call->map_view.alloc_type, call->map_view.prot ); break; case APC_UNMAP_VIEW: dump_uint64( "APC_UNMAP_VIEW,addr=", &call->unmap_view.addr );