kernel32: Validate the architecture of newly created processes on the server side.
This commit is contained in:
parent
f2c54dba01
commit
1e78c99388
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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 },
|
||||||
|
|
Loading…
Reference in New Issue