Commit 1e78c993 authored by Alexandre Julliard's avatar Alexandre Julliard

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

parent f2c54dba
......@@ -1809,6 +1809,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
*/
static pid_t exec_loader( LPCWSTR cmd_line, unsigned int flags, int socketfd,
......@@ -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,
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;
}
......
......@@ -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() );
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 );
}
......
......@@ -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 */
......@@ -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 */
{
......
......@@ -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 */
......
......@@ -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 );
......
......@@ -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:
......
......@@ -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 */
......
......@@ -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 },
......
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