From 9fd2330a9686bed56cbc8a7731d219d18e5226b3 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 28 Apr 2020 11:28:29 +0200 Subject: [PATCH] ntdll: Add a helper to exec wineloader. Signed-off-by: Alexandre Julliard --- dlls/ntdll/ntdll_misc.h | 1 + dlls/ntdll/process.c | 137 ++++++---------------------------------- dlls/ntdll/server.c | 131 +++++++++++++++++++++++++++++++++++++- 3 files changed, 151 insertions(+), 118 deletions(-) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 2e26d189a1e..1c3088ae400 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -113,6 +113,7 @@ extern size_t dll_path_maxlen DECLSPEC_HIDDEN; extern timeout_t server_start_time DECLSPEC_HIDDEN; extern unsigned int server_cpus DECLSPEC_HIDDEN; extern BOOL is_wow64 DECLSPEC_HIDDEN; +extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN; extern void server_init_process(void) DECLSPEC_HIDDEN; extern void server_init_process_done(void) DECLSPEC_HIDDEN; extern size_t server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index d2a3421ac58..e59c255e327 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -51,7 +51,6 @@ #include "winternl.h" #include "ntdll_misc.h" #include "wine/exception.h" -#include "wine/library.h" #include "wine/server.h" #ifdef HAVE_MACH_MACH_H @@ -68,10 +67,6 @@ static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" }; -static inline BOOL is_64bit_arch( client_cpu_t cpu ) -{ - return (cpu == CPU_x86_64 || cpu == CPU_ARM64); -} /* * Process object @@ -995,51 +990,6 @@ static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *p } -/*********************************************************************** - * get_alternate_loader - * - * Get the name of the alternate (32 or 64 bit) Wine loader. - */ -static const char *get_alternate_loader( char **ret_env ) -{ - char *env; - const char *loader = NULL; - const char *loader_env = getenv( "WINELOADER" ); - - *ret_env = NULL; - - if (build_dir) loader = is_win64 ? "loader/wine" : "loader/wine64"; - - if (loader_env) - { - int len = strlen( loader_env ); - if (!is_win64) - { - if (!(env = RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len + 2 ))) return NULL; - strcpy( env, "WINELOADER=" ); - strcat( env, loader_env ); - strcat( env, "64" ); - } - else - { - if (!(env = RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len ))) return NULL; - strcpy( env, "WINELOADER=" ); - strcat( env, loader_env ); - len += sizeof("WINELOADER=") - 1; - if (!strcmp( env + len - 2, "64" )) env[len - 2] = 0; - } - if (!loader) - { - if ((loader = strrchr( env, '/' ))) loader++; - else loader = env; - } - *ret_env = env; - } - if (!loader) loader = is_win64 ? "wine" : "wine64"; - return loader; -} - - #ifdef __APPLE__ /*********************************************************************** * terminate_main_thread @@ -1117,15 +1067,10 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc { pid_t pid; int stdin_fd = -1, stdout_fd = -1; - char *wineloader = NULL; - const char *loader = NULL; char **argv; NTSTATUS status = STATUS_SUCCESS; - argv = build_argv( ¶ms->CommandLine, 1 ); - - if (!is_win64 ^ !is_64bit_arch( pe_info->cpu )) - loader = get_alternate_loader( &wineloader ); + argv = build_argv( ¶ms->CommandLine, 2 ); wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ); wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ); @@ -1134,10 +1079,6 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc { if (!(pid = fork())) /* grandchild */ { - char preloader_reserve[64], socket_env[64]; - ULONGLONG res_start = pe_info->base; - ULONGLONG res_end = pe_info->base + pe_info->map_size; - if (params->ConsoleFlags || params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ || (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE)) @@ -1150,20 +1091,10 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc if (stdin_fd != -1) close( stdin_fd ); if (stdout_fd != -1) close( stdout_fd ); - /* Reset signals that we previously set to SIG_IGN */ - signal( SIGPIPE, SIG_DFL ); - - sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd ); - sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x", - (ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end ); - - putenv( preloader_reserve ); - putenv( socket_env ); if (winedebug) putenv( winedebug ); - if (wineloader) putenv( wineloader ); if (unixdir) chdir( unixdir ); - if (argv) wine_exec_wine_binary( loader, argv, getenv("WINELOADER") ); + exec_wineloader( argv, socketfd, pe_info ); _exit(1); } @@ -1182,56 +1113,11 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc if (stdin_fd != -1) close( stdin_fd ); if (stdout_fd != -1) close( stdout_fd ); - RtlFreeHeap( GetProcessHeap(), 0, wineloader ); RtlFreeHeap( GetProcessHeap(), 0, argv ); return status; } -/*********************************************************************** - * exec_loader - */ -static NTSTATUS exec_loader( const UNICODE_STRING *cmdline, int socketfd, const pe_image_info_t *pe_info ) -{ - char *wineloader = NULL; - const char *loader = NULL; - char **argv; - char preloader_reserve[64], socket_env[64]; - ULONGLONG res_start = pe_info->base; - ULONGLONG res_end = pe_info->base + pe_info->map_size; - - if (!(argv = build_argv( cmdline, 1 ))) return STATUS_NO_MEMORY; - - if (!is_win64 ^ !is_64bit_arch( pe_info->cpu )) - loader = get_alternate_loader( &wineloader ); - - /* Reset signals that we previously set to SIG_IGN */ - signal( SIGPIPE, SIG_DFL ); - - sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd ); - sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x", - (ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end ); - - putenv( preloader_reserve ); - putenv( socket_env ); - if (wineloader) putenv( wineloader ); - - do - { - wine_exec_wine_binary( loader, argv, getenv("WINELOADER") ); - } -#ifdef __APPLE__ - while (errno == ENOTSUP && terminate_main_thread()); -#else - while (0); -#endif - - RtlFreeHeap( GetProcessHeap(), 0, wineloader ); - RtlFreeHeap( GetProcessHeap(), 0, argv ); - return STATUS_INVALID_IMAGE_FORMAT; -} - - /*************************************************************************** * is_builtin_path */ @@ -1636,7 +1522,24 @@ NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status ) } SERVER_END_REQ; - if (!status) status = exec_loader( &strW, socketfd[0], &pe_info ); + if (!status) + { + char **argv = build_argv( &strW, 2 ); + if (argv) + { + do + { + status = exec_wineloader( argv, socketfd[0], &pe_info ); + } +#ifdef __APPLE__ + while (errno == ENOTSUP && terminate_main_thread()); +#else + while (0); +#endif + RtlFreeHeap( GetProcessHeap(), 0, argv ); + } + else status = STATUS_NO_MEMORY; + } close( socketfd[0] ); return status; } diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index d793d314a68..edb91cf91a6 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -75,6 +75,13 @@ #ifdef HAVE_UNISTD_H # include #endif +#ifdef __APPLE__ +#include +#include +#ifndef _POSIX_SPAWN_DISABLE_ASLR +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#endif +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -113,6 +120,12 @@ static const enum cpu_type client_cpu = CPU_ARM64; #error Unsupported CPU #endif +#if defined(linux) || defined(__APPLE__) +static const BOOL use_preloader = TRUE; +#else +static const BOOL use_preloader = FALSE; +#endif + static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); const char *build_dir = NULL; @@ -122,6 +135,7 @@ const char **dll_paths = NULL; size_t dll_path_maxlen = 0; static const char *server_dir; static const char *bin_dir; +static const char *argv0; unsigned int server_cpus = 0; BOOL is_wow64 = FALSE; @@ -1218,6 +1232,119 @@ int server_pipe( int fd[2] ) } +/*********************************************************************** + * preloader_exec + */ +static void preloader_exec( char **argv ) +{ + if (use_preloader) + { + static const char *preloader = "wine-preloader"; + char *p; + + if (!(p = strrchr( argv[1], '/' ))) p = argv[1]; + else p++; + + if (strlen(p) > 2 && !strcmp( p + strlen(p) - 2, "64" )) preloader = "wine64-preloader"; + argv[0] = malloc( p - argv[1] + strlen(preloader) + 1 ); + memcpy( argv[0], argv[1], p - argv[1] ); + strcpy( argv[0] + (p - argv[1]), preloader ); + +#ifdef __APPLE__ + { + posix_spawnattr_t attr; + posix_spawnattr_init( &attr ); + posix_spawnattr_setflags( &attr, POSIX_SPAWN_SETEXEC | _POSIX_SPAWN_DISABLE_ASLR ); + posix_spawn( NULL, argv[0], NULL, &attr, argv, *_NSGetEnviron() ); + posix_spawnattr_destroy( &attr ); + } +#endif + execv( argv[0], argv ); + free( argv[0] ); + } + execv( argv[1], argv + 1 ); +} + + +/*********************************************************************** + * exec_wineloader + * + * argv[0] and argv[1] must be reserved for the preloader and loader respectively. + */ +NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) +{ + const int is_child_64bit = (pe_info->cpu == CPU_x86_64 || pe_info->cpu == CPU_ARM64); + const char *path, *loader = argv0; + const char *loader_env = getenv( "WINELOADER" ); + char *p, preloader_reserve[64], socket_env[64]; + ULONGLONG res_start = pe_info->base; + ULONGLONG res_end = pe_info->base + pe_info->map_size; + + if (!is_win64 ^ !is_child_64bit) + { + /* remap WINELOADER to the alternate 32/64-bit version if necessary */ + if (loader_env) + { + int len = strlen( loader_env ); + char *env = malloc( sizeof("WINELOADER=") + len + 2 ); + + if (!env) return STATUS_NO_MEMORY; + strcpy( env, "WINELOADER=" ); + strcat( env, loader_env ); + if (is_child_64bit) + { + strcat( env, "64" ); + } + else + { + len += sizeof("WINELOADER=") - 1; + if (!strcmp( env + len - 2, "64" )) env[len - 2] = 0; + } + loader = env; + putenv( env ); + } + else loader = is_child_64bit ? "wine64" : "wine"; + } + + signal( SIGPIPE, SIG_DFL ); + + sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd ); + sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x", + (ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end ); + + putenv( preloader_reserve ); + putenv( socket_env ); + + if (build_dir) + { + argv[1] = build_path( build_dir, is_child_64bit ? "loader/wine64" : "loader/wine" ); + preloader_exec( argv ); + return STATUS_INVALID_IMAGE_FORMAT; + } + + if ((p = strrchr( loader, '/' ))) loader = p + 1; + + argv[1] = build_path( bin_dir, loader ); + preloader_exec( argv ); + + argv[1] = getenv( "WINELOADER" ); + if (argv[1]) preloader_exec( argv ); + + if ((path = getenv( "PATH" ))) + { + for (p = strtok( strdup( path ), ":" ); p; p = strtok( NULL, ":" )) + { + argv[1] = build_path( p, loader ); + preloader_exec( argv ); + } + } + + argv[1] = build_path( BINDIR, loader ); + preloader_exec( argv ); + return STATUS_INVALID_IMAGE_FORMAT; +} + + /*********************************************************************** * exec_wineserver * @@ -1402,12 +1529,14 @@ void init_paths(void) dll_dir = realpath_dirname( info.dli_fname ); #endif + argv0 = strdup( __wine_main_argv[0] ); + #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) bin_dir = realpath_dirname( "/proc/self/exe" ); #elif defined (__FreeBSD__) || defined(__DragonFly__) bin_dir = realpath_dirname( "/proc/curproc/file" ); #else - bin_dir = realpath_dirname( __wine_main_argv[0] ); + bin_dir = realpath_dirname( argv0 ); #endif if (dll_dir) build_dir = remove_tail( dll_dir, "/dlls/ntdll" );