kernel32: Validate the architecture of newly created processes on the server side.

This commit is contained in:
Alexandre Julliard 2013-11-22 12:32:48 +01:00
parent f2c54dba01
commit 1e78c99388
9 changed files with 96 additions and 29 deletions

View File

@ -1808,6 +1808,25 @@ static BOOL terminate_main_thread(void)
} }
#endif #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 * exec_loader
*/ */
@ -1909,7 +1928,9 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
LPPROCESS_INFORMATION info, LPCSTR unixdir, LPPROCESS_INFORMATION info, LPCSTR unixdir,
const struct binary_info *binary_info, int exec_only ) 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; HANDLE process_info;
WCHAR *env_end; WCHAR *env_end;
char *winedebug = NULL; char *winedebug = NULL;
@ -1917,11 +1938,10 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
DWORD startup_info_size; DWORD startup_info_size;
int socketfd[2], stdin_fd = -1, stdout_fd = -1; int socketfd[2], stdin_fd = -1, stdout_fd = -1;
pid_t pid; 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 ); SetLastError( ERROR_BAD_EXE_FORMAT );
return FALSE; return FALSE;
} }
@ -1950,14 +1970,26 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
req->create_flags = flags; req->create_flags = flags;
req->socket_fd = socketfd[1]; req->socket_fd = socketfd[1];
req->exe_file = wine_server_obj_handle( hFile ); 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; SERVER_END_REQ;
if (ret) exec_loader( cmd_line, flags, socketfd[0], stdin_fd, stdout_fd, unixdir, switch (status)
winedebug, binary_info, TRUE ); {
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] ); close( socketfd[0] );
SetLastError( RtlNtStatusToDosError( status ));
return FALSE; 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->process_attr = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0;
req->thread_access = THREAD_ALL_ACCESS; req->thread_access = THREAD_ALL_ACCESS;
req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0; req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0;
req->cpu = cpu;
req->info_size = startup_info_size; req->info_size = startup_info_size;
wine_server_add_data( req, startup_info, startup_info_size ); wine_server_add_data( req, startup_info, startup_info_size );
wine_server_add_data( req, env, (env_end - env) * sizeof(WCHAR) ); 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->dwProcessId = (DWORD)reply->pid;
info->dwThreadId = (DWORD)reply->tid; info->dwThreadId = (DWORD)reply->tid;
@ -2017,11 +2050,22 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
SERVER_END_REQ; SERVER_END_REQ;
RtlReleasePebLock(); 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] ); close( socketfd[0] );
HeapFree( GetProcessHeap(), 0, startup_info ); HeapFree( GetProcessHeap(), 0, startup_info );
HeapFree( GetProcessHeap(), 0, winedebug ); HeapFree( GetProcessHeap(), 0, winedebug );
SetLastError( RtlNtStatusToDosError( status ));
return FALSE; return FALSE;
} }

View File

@ -1428,6 +1428,7 @@ NTSTATUS server_init_process_done(void)
*/ */
size_t server_init_thread( void *entry_point ) 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)); static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
const char *arch = getenv( "WINEARCH" ); const char *arch = getenv( "WINEARCH" );
int ret; int ret;
@ -1485,15 +1486,14 @@ size_t server_init_thread( void *entry_point )
wine_get_config_dir() ); wine_get_config_dir() );
} }
return info_size; 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", fatal_error( "'%s' is a 32-bit installation, it cannot support 64-bit applications.\n",
wine_get_config_dir() ); wine_get_config_dir() );
case STATUS_NOT_SUPPORTED: case STATUS_NOT_SUPPORTED:
if (is_win64) fatal_error( "'%s' is a 64-bit installation, it cannot be used with a 32-bit wineserver.\n",
fatal_error( "wineserver is 32-bit, it cannot support 64-bit applications.\n" ); wine_get_config_dir() );
else case STATUS_INVALID_IMAGE_FORMAT:
fatal_error( "'%s' is a 64-bit installation, it cannot be used with a 32-bit wineserver.\n", fatal_error( "wineserver doesn't support the %s architecture\n", cpu_names[client_cpu] );
wine_get_config_dir() );
default: default:
server_protocol_error( "init_thread failed with status %x\n", ret ); server_protocol_error( "init_thread failed with status %x\n", ret );
} }

View File

@ -667,9 +667,11 @@ struct new_process_request
unsigned int process_attr; unsigned int process_attr;
unsigned int thread_access; unsigned int thread_access;
unsigned int thread_attr; unsigned int thread_attr;
cpu_type_t cpu;
data_size_t info_size; data_size_t info_size;
/* VARARG(info,startup_info,info_size); */ /* VARARG(info,startup_info,info_size); */
/* VARARG(env,unicode_str); */ /* VARARG(env,unicode_str); */
char __pad_52[4];
}; };
struct new_process_reply struct new_process_reply
{ {
@ -5846,6 +5848,6 @@ union generic_reply
struct set_suspend_context_reply set_suspend_context_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 */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -898,6 +898,11 @@ DECL_HANDLER(new_process)
close( socket_fd ); close( socket_fd );
return; return;
} }
if (!is_cpu_supported( req->cpu ))
{
close( socket_fd );
return;
}
if (!req->info_size) /* create an orphaned process */ if (!req->info_size) /* create an orphaned process */
{ {

View File

@ -681,6 +681,7 @@ struct rawinput_device
unsigned int process_attr; /* attributes for process object */ unsigned int process_attr; /* attributes for process object */
unsigned int thread_access; /* access rights for thread object */ unsigned int thread_access; /* access rights for thread object */
unsigned int thread_attr; /* attributes 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 */ data_size_t info_size; /* size of startup info */
VARARG(info,startup_info,info_size); /* startup information */ VARARG(info,startup_info,info_size); /* startup information */
VARARG(env,unicode_str); /* environment for new process */ VARARG(env,unicode_str); /* environment for new process */

View File

@ -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, process_attr) == 32 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, thread_access) == 36 ); 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, thread_attr) == 40 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 44 ); C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 44 );
C_ASSERT( sizeof(struct new_process_request) == 48 ); 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, info) == 8 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, phandle) == 16 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, phandle) == 16 );

View File

@ -1189,6 +1189,21 @@ struct token *thread_get_impersonation_token( struct thread *thread )
return thread->process->token; 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 */ /* create a new thread */
DECL_HANDLER(new_thread) DECL_HANDLER(new_thread)
{ {
@ -1218,7 +1233,6 @@ DECL_HANDLER(new_thread)
/* initialize a new thread */ /* initialize a new thread */
DECL_HANDLER(init_thread) DECL_HANDLER(init_thread)
{ {
unsigned int prefix_cpu_mask = get_prefix_cpu_mask();
struct process *process = current->process; struct process *process = current->process;
int wait_fd, reply_fd; int wait_fd, reply_fd;
@ -1257,14 +1271,7 @@ DECL_HANDLER(init_thread)
if (!process->peb) /* first thread, initialize the process too */ if (!process->peb) /* first thread, initialize the process too */
{ {
if (!CPU_FLAG(req->cpu) || !(supported_cpus & prefix_cpu_mask & CPU_FLAG(req->cpu))) if (!is_cpu_supported( req->cpu )) return;
{
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;
}
process->unix_pid = current->unix_pid; process->unix_pid = current->unix_pid;
process->peb = req->entry; process->peb = req->entry;
process->cpu = req->cpu; process->cpu = req->cpu;
@ -1293,7 +1300,7 @@ DECL_HANDLER(init_thread)
reply->tid = get_thread_id( current ); reply->tid = get_thread_id( current );
reply->version = SERVER_PROTOCOL_VERSION; reply->version = SERVER_PROTOCOL_VERSION;
reply->server_start = server_start_time; reply->server_start = server_start_time;
reply->all_cpus = supported_cpus & prefix_cpu_mask; reply->all_cpus = supported_cpus & get_prefix_cpu_mask();
return; return;
error: error:

View File

@ -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 thread_snapshot *thread_snap( int *count );
extern struct token *thread_get_impersonation_token( struct thread *thread ); extern struct token *thread_get_impersonation_token( struct thread *thread );
extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity );
extern int is_cpu_supported( enum cpu_type cpu );
/* ptrace functions */ /* ptrace functions */

View File

@ -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, ", process_attr=%08x", req->process_attr );
fprintf( stderr, ", thread_access=%08x", req->thread_access ); fprintf( stderr, ", thread_access=%08x", req->thread_access );
fprintf( stderr, ", thread_attr=%08x", req->thread_attr ); fprintf( stderr, ", thread_attr=%08x", req->thread_attr );
dump_cpu_type( ", cpu=", &req->cpu );
fprintf( stderr, ", info_size=%u", req->info_size ); fprintf( stderr, ", info_size=%u", req->info_size );
dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) ); dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) );
dump_varargs_unicode_str( ", env=", cur_size ); dump_varargs_unicode_str( ", env=", cur_size );
@ -4909,6 +4910,11 @@ static const struct
{ "INVALID_DEVICE_REQUEST", STATUS_INVALID_DEVICE_REQUEST }, { "INVALID_DEVICE_REQUEST", STATUS_INVALID_DEVICE_REQUEST },
{ "INVALID_FILE_FOR_SECTION", STATUS_INVALID_FILE_FOR_SECTION }, { "INVALID_FILE_FOR_SECTION", STATUS_INVALID_FILE_FOR_SECTION },
{ "INVALID_HANDLE", STATUS_INVALID_HANDLE }, { "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_PARAMETER", STATUS_INVALID_PARAMETER },
{ "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR }, { "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR },
{ "IO_TIMEOUT", STATUS_IO_TIMEOUT }, { "IO_TIMEOUT", STATUS_IO_TIMEOUT },