diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 0bacd60b44a..d42d120d5f0 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -1808,6 +1808,25 @@ static BOOL terminate_main_thread(void) } #endif +/*********************************************************************** + * get_process_cpu + */ +static int get_process_cpu( const WCHAR *filename, const struct binary_info *binary_info ) +{ + switch (binary_info->arch) + { + case IMAGE_FILE_MACHINE_I386: return CPU_x86; + case IMAGE_FILE_MACHINE_AMD64: return CPU_x86_64; + case IMAGE_FILE_MACHINE_POWERPC: return CPU_POWERPC; + case IMAGE_FILE_MACHINE_ARM: + case IMAGE_FILE_MACHINE_THUMB: + case IMAGE_FILE_MACHINE_ARMNT: return CPU_ARM; + case IMAGE_FILE_MACHINE_ARM64: return CPU_ARM64; + } + ERR( "%s uses unsupported architecture (%04x)\n", debugstr_w(filename), binary_info->arch ); + return -1; +} + /*********************************************************************** * exec_loader */ @@ -1909,7 +1928,9 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW LPPROCESS_INFORMATION info, LPCSTR unixdir, const struct binary_info *binary_info, int exec_only ) { - BOOL ret, success = FALSE; + static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" }; + NTSTATUS status; + BOOL success = FALSE; HANDLE process_info; WCHAR *env_end; char *winedebug = NULL; @@ -1917,11 +1938,10 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW DWORD startup_info_size; int socketfd[2], stdin_fd = -1, stdout_fd = -1; pid_t pid; - int err; + int err, cpu; - if (!is_win64 && !is_wow64 && (binary_info->flags & BINARY_FLAG_64BIT)) + if ((cpu = get_process_cpu( filename, binary_info )) == -1) { - ERR( "starting 64-bit process %s not supported in 32-bit wineprefix\n", debugstr_w(filename) ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; } @@ -1950,14 +1970,26 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW req->create_flags = flags; req->socket_fd = socketfd[1]; req->exe_file = wine_server_obj_handle( hFile ); - ret = !wine_server_call_err( req ); + req->cpu = cpu; + status = wine_server_call( req ); } SERVER_END_REQ; - if (ret) exec_loader( cmd_line, flags, socketfd[0], stdin_fd, stdout_fd, unixdir, - winedebug, binary_info, TRUE ); - + switch (status) + { + case STATUS_INVALID_IMAGE_WIN_64: + ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_w(filename) ); + break; + case STATUS_INVALID_IMAGE_FORMAT: + ERR( "%s not supported on this installation (%s binary)\n", + debugstr_w(filename), cpu_names[cpu] ); + break; + case STATUS_SUCCESS: + exec_loader( cmd_line, flags, socketfd[0], stdin_fd, stdout_fd, unixdir, + winedebug, binary_info, TRUE ); + } close( socketfd[0] ); + SetLastError( RtlNtStatusToDosError( status )); return FALSE; } @@ -2001,11 +2033,12 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW req->process_attr = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0; req->thread_access = THREAD_ALL_ACCESS; req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0; + req->cpu = cpu; req->info_size = startup_info_size; wine_server_add_data( req, startup_info, startup_info_size ); wine_server_add_data( req, env, (env_end - env) * sizeof(WCHAR) ); - if ((ret = !wine_server_call_err( req ))) + if (!(status = wine_server_call( req ))) { info->dwProcessId = (DWORD)reply->pid; info->dwThreadId = (DWORD)reply->tid; @@ -2017,11 +2050,22 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW SERVER_END_REQ; RtlReleasePebLock(); - if (!ret) + if (status) { + switch (status) + { + case STATUS_INVALID_IMAGE_WIN_64: + ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_w(filename) ); + break; + case STATUS_INVALID_IMAGE_FORMAT: + ERR( "%s not supported on this installation (%s binary)\n", + debugstr_w(filename), cpu_names[cpu] ); + break; + } close( socketfd[0] ); HeapFree( GetProcessHeap(), 0, startup_info ); HeapFree( GetProcessHeap(), 0, winedebug ); + SetLastError( RtlNtStatusToDosError( status )); return FALSE; } diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index f396dd5b379..59e8ea598b2 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -1428,6 +1428,7 @@ NTSTATUS server_init_process_done(void) */ size_t server_init_thread( void *entry_point ) { + static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" }; static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); const char *arch = getenv( "WINEARCH" ); int ret; @@ -1485,15 +1486,14 @@ size_t server_init_thread( void *entry_point ) wine_get_config_dir() ); } return info_size; - case STATUS_NOT_REGISTRY_FILE: + case STATUS_INVALID_IMAGE_WIN_64: fatal_error( "'%s' is a 32-bit installation, it cannot support 64-bit applications.\n", wine_get_config_dir() ); case STATUS_NOT_SUPPORTED: - if (is_win64) - fatal_error( "wineserver is 32-bit, it cannot support 64-bit applications.\n" ); - else - fatal_error( "'%s' is a 64-bit installation, it cannot be used with a 32-bit wineserver.\n", - wine_get_config_dir() ); + fatal_error( "'%s' is a 64-bit installation, it cannot be used with a 32-bit wineserver.\n", + wine_get_config_dir() ); + case STATUS_INVALID_IMAGE_FORMAT: + fatal_error( "wineserver doesn't support the %s architecture\n", cpu_names[client_cpu] ); default: server_protocol_error( "init_thread failed with status %x\n", ret ); } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index dc8380650c1..f936a882ec4 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -667,9 +667,11 @@ struct new_process_request unsigned int process_attr; unsigned int thread_access; unsigned int thread_attr; + cpu_type_t cpu; data_size_t info_size; /* VARARG(info,startup_info,info_size); */ /* VARARG(env,unicode_str); */ + char __pad_52[4]; }; struct new_process_reply { @@ -5846,6 +5848,6 @@ union generic_reply struct set_suspend_context_reply set_suspend_context_reply; }; -#define SERVER_PROTOCOL_VERSION 452 +#define SERVER_PROTOCOL_VERSION 453 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/process.c b/server/process.c index 58ca9a84875..8622fec8739 100644 --- a/server/process.c +++ b/server/process.c @@ -898,6 +898,11 @@ DECL_HANDLER(new_process) close( socket_fd ); return; } + if (!is_cpu_supported( req->cpu )) + { + close( socket_fd ); + return; + } if (!req->info_size) /* create an orphaned process */ { diff --git a/server/protocol.def b/server/protocol.def index 3c3b0b53e12..8c5f953511e 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -681,6 +681,7 @@ struct rawinput_device unsigned int process_attr; /* attributes for process object */ unsigned int thread_access; /* access rights for thread object */ unsigned int thread_attr; /* attributes for thread object */ + cpu_type_t cpu; /* CPU that the new process will use */ data_size_t info_size; /* size of startup info */ VARARG(info,startup_info,info_size); /* startup information */ VARARG(env,unicode_str); /* environment for new process */ diff --git a/server/request.h b/server/request.h index 74f5892119e..3730f7b5f7c 100644 --- a/server/request.h +++ b/server/request.h @@ -659,8 +659,9 @@ C_ASSERT( FIELD_OFFSET(struct new_process_request, process_access) == 28 ); C_ASSERT( FIELD_OFFSET(struct new_process_request, process_attr) == 32 ); C_ASSERT( FIELD_OFFSET(struct new_process_request, thread_access) == 36 ); C_ASSERT( FIELD_OFFSET(struct new_process_request, thread_attr) == 40 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 44 ); -C_ASSERT( sizeof(struct new_process_request) == 48 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 44 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 48 ); +C_ASSERT( sizeof(struct new_process_request) == 56 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, info) == 8 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, phandle) == 16 ); diff --git a/server/thread.c b/server/thread.c index 32985ac0e57..623a3b34747 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1189,6 +1189,21 @@ struct token *thread_get_impersonation_token( struct thread *thread ) return thread->process->token; } +/* check if a cpu type can be supported on this server */ +int is_cpu_supported( enum cpu_type cpu ) +{ + unsigned int prefix_cpu_mask = get_prefix_cpu_mask(); + + if (CPU_FLAG(cpu) && (supported_cpus & prefix_cpu_mask & CPU_FLAG(cpu))) return 1; + if (!(supported_cpus & prefix_cpu_mask)) + set_error( STATUS_NOT_SUPPORTED ); + else if (supported_cpus & CPU_FLAG(cpu)) + set_error( STATUS_INVALID_IMAGE_WIN_64 ); /* server supports it but not the prefix */ + else + set_error( STATUS_INVALID_IMAGE_FORMAT ); + return 0; +} + /* create a new thread */ DECL_HANDLER(new_thread) { @@ -1218,7 +1233,6 @@ DECL_HANDLER(new_thread) /* initialize a new thread */ DECL_HANDLER(init_thread) { - unsigned int prefix_cpu_mask = get_prefix_cpu_mask(); struct process *process = current->process; int wait_fd, reply_fd; @@ -1257,14 +1271,7 @@ DECL_HANDLER(init_thread) if (!process->peb) /* first thread, initialize the process too */ { - if (!CPU_FLAG(req->cpu) || !(supported_cpus & prefix_cpu_mask & CPU_FLAG(req->cpu))) - { - if (!(supported_cpus & CPU_64BIT_MASK)) - set_error( STATUS_NOT_SUPPORTED ); - else - set_error( STATUS_NOT_REGISTRY_FILE ); /* server supports it but not the prefix */ - return; - } + if (!is_cpu_supported( req->cpu )) return; process->unix_pid = current->unix_pid; process->peb = req->entry; process->cpu = req->cpu; @@ -1293,7 +1300,7 @@ DECL_HANDLER(init_thread) reply->tid = get_thread_id( current ); reply->version = SERVER_PROTOCOL_VERSION; reply->server_start = server_start_time; - reply->all_cpus = supported_cpus & prefix_cpu_mask; + reply->all_cpus = supported_cpus & get_prefix_cpu_mask(); return; error: diff --git a/server/thread.h b/server/thread.h index eddfd304ace..996d95bd8c0 100644 --- a/server/thread.h +++ b/server/thread.h @@ -125,6 +125,7 @@ extern int thread_get_inflight_fd( struct thread *thread, int client ); extern struct thread_snapshot *thread_snap( int *count ); extern struct token *thread_get_impersonation_token( struct thread *thread ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); +extern int is_cpu_supported( enum cpu_type cpu ); /* ptrace functions */ diff --git a/server/trace.c b/server/trace.c index 2171a2578c4..7fe5c4fb701 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1106,6 +1106,7 @@ static void dump_new_process_request( const struct new_process_request *req ) fprintf( stderr, ", process_attr=%08x", req->process_attr ); fprintf( stderr, ", thread_access=%08x", req->thread_access ); fprintf( stderr, ", thread_attr=%08x", req->thread_attr ); + dump_cpu_type( ", cpu=", &req->cpu ); fprintf( stderr, ", info_size=%u", req->info_size ); dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) ); dump_varargs_unicode_str( ", env=", cur_size ); @@ -4909,6 +4910,11 @@ static const struct { "INVALID_DEVICE_REQUEST", STATUS_INVALID_DEVICE_REQUEST }, { "INVALID_FILE_FOR_SECTION", STATUS_INVALID_FILE_FOR_SECTION }, { "INVALID_HANDLE", STATUS_INVALID_HANDLE }, + { "INVALID_IMAGE_FORMAT", STATUS_INVALID_IMAGE_FORMAT }, + { "INVALID_IMAGE_NE_FORMAT", STATUS_INVALID_IMAGE_NE_FORMAT }, + { "INVALID_IMAGE_NOT_MZ", STATUS_INVALID_IMAGE_NOT_MZ }, + { "INVALID_IMAGE_PROTECT", STATUS_INVALID_IMAGE_PROTECT }, + { "INVALID_IMAGE_WIN_64", STATUS_INVALID_IMAGE_WIN_64 }, { "INVALID_PARAMETER", STATUS_INVALID_PARAMETER }, { "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR }, { "IO_TIMEOUT", STATUS_IO_TIMEOUT },