diff --git a/README.md b/README.md index 6b55e167..808c72c3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ These patches fix the following Wine bugs: * Support for Junction Points ([Wine Bug #12401](http://bugs.winehq.org/show_bug.cgi?id=12401 "Support junction points, i.e. DeviceIoCtl(FSCTL_SET_REPARSE_POINT/FSCTL_GET_REPARSE_POINT)")) * GetSecurityInfo returns NULL DACL for process object ([Wine Bug #15980](http://bugs.winehq.org/show_bug.cgi?id=15980 "Rhapsody 2 crashes on startup (GetSecurityInfo returns NULL DACL for process object)")) * Workaround for TransactNamedPipe not being supported ([Wine Bug #17273](http://bugs.winehq.org/show_bug.cgi?id=17273 "Many apps and games need SetNamedPipeHandleState implementation (support for named pipe message mode)(FireFox+Flash, Win8/NET 4.x SDK/vcrun2012, WiX installers)")) +* Support for process ACLs ([Wine Bug #22006](http://bugs.winehq.org/show_bug.cgi?id=22006 "OpenProcess does not enforce ACL")) * Add implementation of WTSEnumerateProcessesW ([Wine Bug #29903](http://bugs.winehq.org/show_bug.cgi?id=29903 "Some Microsoft debuggers fail to enumerate processes due to wtsapi32.WTSEnumerateProcessesW() being a stub (Microsoft Visual Studio 2005, DbgCLR from .NET 2.0 SDK)")) * Support for stored file ACLs ([Wine Bug #31858](http://bugs.winehq.org/show_bug.cgi?id=31858 "Netflix on Firefox fails with Internet Connection Problem when loading bar is at 99%")) * Implement an Arial replacement font ([Wine Bug #32323](http://bugs.winehq.org/show_bug.cgi?id=32323 "Netflix (Silverlight 4.x) and several .NET Framework 3.x/4.0 WPF apps require either Arial or Verdana to be installed")) diff --git a/debian/changelog b/debian/changelog index 9129db50..e8ddf099 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,5 @@ -wine-compholio (1.7.22) UNRELEASED; urgency=low +wine-compholio (1.7.22) unstable; urgency=low + * Implement passing ACLs to CreateProcess. * Removed several patches (accepted upstream). * Added NT4 support to the process ACL tests. * Implement RegSetKeySecurity on top of NtSetSecurityObject. @@ -8,7 +9,7 @@ wine-compholio (1.7.22) UNRELEASED; urgency=low * Updated main extended attributes patch to include BSD support. * Return NULL-terminated list of arguments in CommandLineToArgvW. * Updated main extended attributes patch to include additional data checks. - -- Erich E. Hoover Tue, 08 Jul 2014 14:32:30 -0600 + -- Erich E. Hoover Fri, 11 Jul 2014 13:00:03 -0600 wine-compholio (1.7.21) unstable; urgency=low * Remove several patches (accepted upstream). diff --git a/patches/16-server-CreateProcess_ACLs/0001-server-A-new-function-set_sd_defaults_from_token-try.patch b/patches/16-server-CreateProcess_ACLs/0001-server-A-new-function-set_sd_defaults_from_token-try.patch new file mode 100644 index 00000000..93e29895 --- /dev/null +++ b/patches/16-server-CreateProcess_ACLs/0001-server-A-new-function-set_sd_defaults_from_token-try.patch @@ -0,0 +1,103 @@ +From 91fb6970f6b7f5a5c93d066c143e96398fba294e Mon Sep 17 00:00:00 2001 +From: Joris van der Wel +Date: Wed, 9 Jul 2014 00:58:10 +0200 +Subject: server: A new function "set_sd_defaults_from_token" (try 3) + +server: A new function "set_sd_defaults_from_token" that sets the + security descriptor along with a token that will be used to gather +defaults, instead of always using the primary token. + +Some objects take their defaults not from a primary token but from a +different one +(such as from the impersonation token or the process token). +This function can be used to create the various set_sd implementations +for the objects that need it. +As a bonus, a NULL token will skip setting any defaults, this is +useful for object implementations that would like to set their +defaults _only_ upon creation. +--- + server/object.c | 23 +++++++++++++++-------- + server/object.h | 2 ++ + 2 files changed, 17 insertions(+), 8 deletions(-) + +diff --git a/server/object.c b/server/object.c +index 11ef0ce..6389409 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -423,8 +423,8 @@ struct security_descriptor *default_get_sd( struct object *obj ) + return obj->sd; + } + +-int default_set_sd( struct object *obj, const struct security_descriptor *sd, +- unsigned int set_info ) ++int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd, ++ unsigned int set_info, struct token *token ) + { + struct security_descriptor new_sd, *new_sd_ptr; + int present; +@@ -446,9 +446,9 @@ int default_set_sd( struct object *obj, const struct security_descriptor *sd, + owner = sd_get_owner( obj->sd ); + new_sd.owner_len = obj->sd->owner_len; + } +- else ++ else if (token) + { +- owner = token_get_user( current->process->token ); ++ owner = token_get_user( token ); + new_sd.owner_len = security_sid_len( owner ); + } + +@@ -462,9 +462,9 @@ int default_set_sd( struct object *obj, const struct security_descriptor *sd, + group = sd_get_group( obj->sd ); + new_sd.group_len = obj->sd->group_len; + } +- else ++ else if (token) + { +- group = token_get_primary_group( current->process->token ); ++ group = token_get_primary_group( token ); + new_sd.group_len = security_sid_len( group ); + } + +@@ -494,9 +494,9 @@ int default_set_sd( struct object *obj, const struct security_descriptor *sd, + + if (obj->sd && present) + new_sd.dacl_len = obj->sd->dacl_len; +- else ++ else if (token) + { +- dacl = token_get_default_dacl( current->process->token ); ++ dacl = token_get_default_dacl( token ); + new_sd.dacl_len = dacl->AclSize; + } + } +@@ -521,6 +521,13 @@ int default_set_sd( struct object *obj, const struct security_descriptor *sd, + return 1; + } + ++/** Set the security descriptor using the current primary token for defaults. */ ++int default_set_sd( struct object *obj, const struct security_descriptor *sd, ++ unsigned int set_info ) ++{ ++ return set_sd_defaults_from_token( obj, sd, set_info, current->process->token ); ++} ++ + struct object *no_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ) + { +diff --git a/server/object.h b/server/object.h +index bb3ff21..7201ff9 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -139,6 +139,8 @@ extern struct fd *no_get_fd( struct object *obj ); + extern unsigned int no_map_access( struct object *obj, unsigned int access ); + extern struct security_descriptor *default_get_sd( struct object *obj ); + extern int default_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info ); ++extern int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd, ++ unsigned int set_info, struct token *token ); + extern struct object *no_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attributes ); + extern struct object *no_open_file( struct object *obj, unsigned int access, unsigned int sharing, + unsigned int options ); +-- +1.7.9.5 + diff --git a/patches/16-server-CreateProcess_ACLs/0002-server-Support-sending-process-and-thread-security-d.patch b/patches/16-server-CreateProcess_ACLs/0002-server-Support-sending-process-and-thread-security-d.patch new file mode 100644 index 00000000..c0c3ec4c --- /dev/null +++ b/patches/16-server-CreateProcess_ACLs/0002-server-Support-sending-process-and-thread-security-d.patch @@ -0,0 +1,176 @@ +From fe16cbc2062778bef273ac84eca992dcc45653e6 Mon Sep 17 00:00:00 2001 +From: Joris van der Wel +Date: Wed, 9 Jul 2014 00:58:47 +0200 +Subject: server: Support sending process and thread security descriptors for + the "new_process" request in the protocol. + +server: Support sending process and thread security descriptors for + the "new_process" request in the protocol. +--- + dlls/kernel32/process.c | 30 +++++++++++++++++------------- + server/process.c | 33 ++++++++++++++++++++------------- + server/protocol.def | 41 +++++++++++++++++++++++------------------ + 3 files changed, 60 insertions(+), 44 deletions(-) + +diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c +index 2566ac4..8bf1934 100644 +--- a/dlls/kernel32/process.c ++++ b/dlls/kernel32/process.c +@@ -2025,19 +2025,23 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + + SERVER_START_REQ( new_process ) + { +- req->inherit_all = inherit; +- req->create_flags = flags; +- req->socket_fd = socketfd[1]; +- req->exe_file = wine_server_obj_handle( hFile ); +- req->process_access = PROCESS_ALL_ACCESS; +- 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) ); ++ req->inherit_all = inherit; ++ req->create_flags = flags; ++ req->socket_fd = socketfd[1]; ++ req->exe_file = wine_server_obj_handle( hFile ); ++ req->process_access = PROCESS_ALL_ACCESS; ++ 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->process_sd_size = 0; ++ req->thread_sd_size = 0; ++ req->info_size = startup_info_size; ++ req->env_size = (env_end - env) * sizeof(WCHAR); ++ ++ wine_server_add_data( req, startup_info, req->info_size ); ++ wine_server_add_data( req, env , req->env_size ); ++ + if (!(status = wine_server_call( req ))) + { + info->dwProcessId = (DWORD)reply->pid; +diff --git a/server/process.c b/server/process.c +index 7b9a3b2..9942eb3 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -880,6 +880,9 @@ DECL_HANDLER(new_process) + struct process *process; + struct process *parent = current->process; + int socket_fd = thread_get_inflight_fd( current, req->socket_fd ); ++ const startup_info_t *req_info; ++ data_size_t req_info_size; ++ const WCHAR *req_env; + + if (socket_fd == -1) + { +@@ -903,6 +906,12 @@ DECL_HANDLER(new_process) + close( socket_fd ); + return; + } ++ ++ req_info = (const startup_info_t *) ++ ((char*)get_req_data() + req->process_sd_size + req->thread_sd_size); ++ ++ req_env = (const WCHAR *) ++ ((char*)get_req_data() + req->process_sd_size + req->thread_sd_size + req->info_size); + + if (!req->info_size) /* create an orphaned process */ + { +@@ -920,27 +929,25 @@ DECL_HANDLER(new_process) + !(info->exe_file = get_file_obj( current->process, req->exe_file, FILE_READ_DATA ))) + goto done; + +- info->data_size = get_req_data_size(); +- info->info_size = min( req->info_size, info->data_size ); +- + if (req->info_size < sizeof(*info->data)) + { + /* make sure we have a full startup_info_t structure */ +- data_size_t env_size = info->data_size - info->info_size; +- data_size_t info_size = min( req->info_size, FIELD_OFFSET( startup_info_t, curdir_len )); +- +- if (!(info->data = mem_alloc( sizeof(*info->data) + env_size ))) goto done; +- memcpy( info->data, get_req_data(), info_size ); +- memset( (char *)info->data + info_size, 0, sizeof(*info->data) - info_size ); +- memcpy( info->data + 1, (const char *)get_req_data() + req->info_size, env_size ); +- info->info_size = sizeof(startup_info_t); +- info->data_size = info->info_size + env_size; ++ info->info_size = sizeof(*info->data); ++ info->data_size = sizeof(*info->data) + req->env_size; ++ ++ req_info_size = min( req->info_size, FIELD_OFFSET( startup_info_t, curdir_len )); ++ if (!(info->data = mem_alloc( info->data_size ))) goto done; ++ memset( info->data, 0, info->data_size ); ++ memcpy( info->data, req_info, req_info_size ); ++ memcpy( info->data + 1, req_env, req->env_size ); + } + else + { + data_size_t pos = sizeof(*info->data); ++ info->info_size = req->info_size; ++ info->data_size = req->info_size + req->env_size; + +- if (!(info->data = memdup( get_req_data(), info->data_size ))) goto done; ++ if (!(info->data = memdup( req_info, info->data_size ))) goto done; + #define FIXUP_LEN(len) do { (len) = min( (len), info->info_size - pos ); pos += (len); } while(0) + FIXUP_LEN( info->data->curdir_len ); + FIXUP_LEN( info->data->dllpath_len ); +diff --git a/server/protocol.def b/server/protocol.def +index a8c1fb9..7b0b769 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -661,24 +661,29 @@ struct rawinput_device + + /* Create a new process from the context of the parent */ + @REQ(new_process) +- int inherit_all; /* inherit all handles from parent */ +- unsigned int create_flags; /* creation flags */ +- int socket_fd; /* file descriptor for process socket */ +- obj_handle_t exe_file; /* file handle for main exe */ +- unsigned int process_access; /* access rights for process object */ +- 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 */ +-@REPLY +- obj_handle_t info; /* new process info handle */ +- process_id_t pid; /* process id */ +- obj_handle_t phandle; /* process handle (in the current process) */ +- thread_id_t tid; /* thread id */ +- obj_handle_t thandle; /* thread handle (in the current process) */ ++ int inherit_all; /* inherit all handles from parent */ ++ unsigned int create_flags; /* creation flags */ ++ int socket_fd; /* file descriptor for process socket */ ++ obj_handle_t exe_file; /* file handle for main exe */ ++ unsigned int process_access; /* access rights for process object */ ++ 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 process_sd_size; /* size of the process security descriptor */ ++ data_size_t thread_sd_size; /* size of the thread security descriptor */ ++ data_size_t info_size; /* size of startup info */ ++ data_size_t env_size; /* size of the environment */ ++ VARARG(process_sd,security_descriptor,process_sd_size); /* security descriptor to set on the process */ ++ VARARG(thread_sd,security_descriptor,thread_sd_size); /* security descriptor to set on the thread */ ++ VARARG(info,startup_info,info_size); /* startup information */ ++ VARARG(env,unicode_str,env_size); /* environment for new process */ ++@REPLY ++ obj_handle_t info; /* new process info handle */ ++ process_id_t pid; /* process id */ ++ obj_handle_t phandle; /* process handle (in the current process) */ ++ thread_id_t tid; /* thread id */ ++ obj_handle_t thandle; /* thread handle (in the current process) */ + @END + + +-- +1.7.9.5 + diff --git a/patches/16-server-CreateProcess_ACLs/0003-server-implement-passing-a-process-security-descript.patch b/patches/16-server-CreateProcess_ACLs/0003-server-implement-passing-a-process-security-descript.patch new file mode 100644 index 00000000..6add19f4 --- /dev/null +++ b/patches/16-server-CreateProcess_ACLs/0003-server-implement-passing-a-process-security-descript.patch @@ -0,0 +1,242 @@ +From d565d8b72c9f57d5553f72dfd7d18e2e05033c0c Mon Sep 17 00:00:00 2001 +From: Joris van der Wel +Date: Wed, 9 Jul 2014 00:59:30 +0200 +Subject: server: implement passing a process security descriptor to + CreateProcess. + +server: implement passing a process security descriptor to CreateProcess. + +For now the function "NTDLL_create_struct_sd" has been duplicated in +kernel32. +This is needed because kernel32 makes the server call. kernel32 currently +makes the server call because NtCreateProcess(Ex) has not been implemented in +ntdll. When NtCreateProcessEx (and NtCreateThreadEx) gets implemented, the +server call will be made from within ntdll instead, and this extra function +in kernel32 will no longer be needed. +--- + dlls/advapi32/tests/security.c | 3 -- + dlls/kernel32/process.c | 85 +++++++++++++++++++++++++++++++++++++++- + server/process.c | 24 ++++++++++++ + 3 files changed, 108 insertions(+), 4 deletions(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index b44496a..b1b35aa 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -2696,7 +2696,6 @@ static void test_process_security_child(void) + ret = DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), + &handle1, PROCESS_ALL_ACCESS, TRUE, 0 ); + err = GetLastError(); +- todo_wine + ok(!ret && err == ERROR_ACCESS_DENIED, "duplicating handle should have failed " + "with STATUS_ACCESS_DENIED, instead of err:%d\n", err); + +@@ -2704,10 +2703,8 @@ static void test_process_security_child(void) + + /* These two should fail - they are denied by ACL */ + handle = OpenProcess( PROCESS_VM_READ, FALSE, GetCurrentProcessId() ); +- todo_wine + ok(handle == NULL, "OpenProcess(PROCESS_VM_READ) should have failed\n"); + handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() ); +- todo_wine + ok(handle == NULL, "OpenProcess(PROCESS_ALL_ACCESS) should have failed\n"); + + /* Documented privilege elevation */ +diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c +index 8bf1934..5f6c2e5 100644 +--- a/dlls/kernel32/process.c ++++ b/dlls/kernel32/process.c +@@ -1916,6 +1916,70 @@ static pid_t exec_loader( LPCWSTR cmd_line, unsigned int flags, int socketfd, + return pid; + } + ++/* creates a struct security_descriptor and contained information in one contiguous piece of memory */ ++static NTSTATUS create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_descriptor **server_sd, ++ data_size_t *server_sd_len) ++{ ++ unsigned int len; ++ PSID owner, group; ++ ACL *dacl, *sacl; ++ BOOLEAN owner_present, group_present, dacl_present, sacl_present; ++ BOOLEAN defaulted; ++ NTSTATUS status; ++ unsigned char *ptr; ++ ++ if (!nt_sd) ++ { ++ *server_sd = NULL; ++ *server_sd_len = 0; ++ return STATUS_SUCCESS; ++ } ++ ++ len = sizeof(struct security_descriptor); ++ ++ status = RtlGetOwnerSecurityDescriptor(nt_sd, &owner, &owner_present); ++ if (status != STATUS_SUCCESS) return status; ++ status = RtlGetGroupSecurityDescriptor(nt_sd, &group, &group_present); ++ if (status != STATUS_SUCCESS) return status; ++ status = RtlGetSaclSecurityDescriptor(nt_sd, &sacl_present, &sacl, &defaulted); ++ if (status != STATUS_SUCCESS) return status; ++ status = RtlGetDaclSecurityDescriptor(nt_sd, &dacl_present, &dacl, &defaulted); ++ if (status != STATUS_SUCCESS) return status; ++ ++ if (owner_present) ++ len += RtlLengthSid(owner); ++ if (group_present) ++ len += RtlLengthSid(group); ++ if (sacl_present && sacl) ++ len += sacl->AclSize; ++ if (dacl_present && dacl) ++ len += dacl->AclSize; ++ ++ /* fix alignment for the Unicode name that follows the structure */ ++ len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1); ++ *server_sd = RtlAllocateHeap(GetProcessHeap(), 0, len); ++ if (!*server_sd) return STATUS_NO_MEMORY; ++ ++ (*server_sd)->control = ((SECURITY_DESCRIPTOR *)nt_sd)->Control & ~SE_SELF_RELATIVE; ++ (*server_sd)->owner_len = owner_present ? RtlLengthSid(owner) : 0; ++ (*server_sd)->group_len = group_present ? RtlLengthSid(group) : 0; ++ (*server_sd)->sacl_len = (sacl_present && sacl) ? sacl->AclSize : 0; ++ (*server_sd)->dacl_len = (dacl_present && dacl) ? dacl->AclSize : 0; ++ ++ ptr = (unsigned char *)(*server_sd + 1); ++ memcpy(ptr, owner, (*server_sd)->owner_len); ++ ptr += (*server_sd)->owner_len; ++ memcpy(ptr, group, (*server_sd)->group_len); ++ ptr += (*server_sd)->group_len; ++ memcpy(ptr, sacl, (*server_sd)->sacl_len); ++ ptr += (*server_sd)->sacl_len; ++ memcpy(ptr, dacl, (*server_sd)->dacl_len); ++ ++ *server_sd_len = len; ++ ++ return STATUS_SUCCESS; ++} ++ + /*********************************************************************** + * create_process + * +@@ -1939,17 +2003,31 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + int socketfd[2], stdin_fd = -1, stdout_fd = -1; + pid_t pid; + int err, cpu; ++ struct security_descriptor *psd = NULL; ++ data_size_t psd_len = 0; + + if ((cpu = get_process_cpu( filename, binary_info )) == -1) + { + SetLastError( ERROR_BAD_EXE_FORMAT ); + return FALSE; ++ } ++ ++ if (psa && (psa->nLength >= sizeof(*psa)) && psa->lpSecurityDescriptor) ++ { ++ status = create_struct_sd( psa->lpSecurityDescriptor, &psd, &psd_len ); ++ if (status != STATUS_SUCCESS) ++ { ++ WARN("Invalid process security descriptor with status %x\n", status); ++ SetLastError( RtlNtStatusToDosError(status) ); ++ return FALSE; ++ } + } + + /* create the socket for the new process */ + + if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1) + { ++ RtlFreeHeap(GetProcessHeap(), 0, psd); + SetLastError( ERROR_TOO_MANY_OPEN_FILES ); + return FALSE; + } +@@ -1989,6 +2067,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + winedebug, binary_info, TRUE ); + } + close( socketfd[0] ); ++ RtlFreeHeap(GetProcessHeap(), 0, psd); + SetLastError( RtlNtStatusToDosError( status )); + return FALSE; + } +@@ -2001,6 +2080,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + RtlReleasePebLock(); + close( socketfd[0] ); + close( socketfd[1] ); ++ RtlFreeHeap(GetProcessHeap(), 0, psd); + return FALSE; + } + if (!env) env = NtCurrentTeb()->Peb->ProcessParameters->Environment; +@@ -2034,11 +2114,12 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + req->thread_access = THREAD_ALL_ACCESS; + req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0; + req->cpu = cpu; +- req->process_sd_size = 0; ++ req->process_sd_size = psd_len; + req->thread_sd_size = 0; + req->info_size = startup_info_size; + req->env_size = (env_end - env) * sizeof(WCHAR); + ++ wine_server_add_data( req, psd , req->process_sd_size ); + wine_server_add_data( req, startup_info, req->info_size ); + wine_server_add_data( req, env , req->env_size ); + +@@ -2053,6 +2134,8 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + } + SERVER_END_REQ; + ++ RtlFreeHeap(GetProcessHeap(), 0, psd); ++ + RtlReleasePebLock(); + if (status) + { +diff --git a/server/process.c b/server/process.c +index 9942eb3..1fba134 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -883,6 +883,7 @@ DECL_HANDLER(new_process) + const startup_info_t *req_info; + data_size_t req_info_size; + const WCHAR *req_env; ++ const struct security_descriptor *req_psd = NULL; + + if (socket_fd == -1) + { +@@ -907,6 +908,17 @@ DECL_HANDLER(new_process) + return; + } + ++ if (req->process_sd_size) ++ { ++ req_psd = get_req_data(); ++ ++ if (!sd_is_valid( req_psd, req->process_sd_size )) ++ { ++ set_error( STATUS_INVALID_SECURITY_DESCR ); ++ return; ++ } ++ } ++ + req_info = (const startup_info_t *) + ((char*)get_req_data() + req->process_sd_size + req->thread_sd_size); + +@@ -1011,6 +1023,18 @@ DECL_HANDLER(new_process) + reply->phandle = alloc_handle( parent, process, req->process_access, req->process_attr ); + reply->thandle = alloc_handle( parent, thread, req->thread_access, req->thread_attr ); + ++ /* note: alloc_handle might fail with access denied ++ * if the security descriptor is set before that call */ ++ ++ if (req_psd) ++ { ++ default_set_sd( &process->obj, ++ req_psd, ++ OWNER_SECURITY_INFORMATION| ++ GROUP_SECURITY_INFORMATION| ++ DACL_SECURITY_INFORMATION| ++ SACL_SECURITY_INFORMATION ); ++ } + done: + release_object( info ); + } +-- +1.7.9.5 + diff --git a/patches/16-server-CreateProcess_ACLs/0004-server-implement-passing-a-thread-security-descripto.patch b/patches/16-server-CreateProcess_ACLs/0004-server-implement-passing-a-thread-security-descripto.patch new file mode 100644 index 00000000..2c8db7f4 --- /dev/null +++ b/patches/16-server-CreateProcess_ACLs/0004-server-implement-passing-a-thread-security-descripto.patch @@ -0,0 +1,234 @@ +From e924e19cc72127f16b64bef300e394a7f641dba1 Mon Sep 17 00:00:00 2001 +From: Joris van der Wel +Date: Wed, 9 Jul 2014 01:00:02 +0200 +Subject: server: implement passing a thread security descriptor to + CreateProcess + +server: implement passing a thread security descriptor to CreateProcess +--- + dlls/advapi32/tests/security.c | 45 ++++++++++++++++++++++++++++++++++++---- + dlls/kernel32/process.c | 24 ++++++++++++++++++--- + server/process.c | 28 ++++++++++++++++++++++++- + 3 files changed, 89 insertions(+), 8 deletions(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index b1b35aa..aab63f3 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -2532,12 +2532,12 @@ static void test_process_security(void) + PTOKEN_OWNER owner; + PTOKEN_PRIMARY_GROUP group; + PSID AdminSid = NULL, UsersSid = NULL; +- PACL Acl = NULL; +- SECURITY_DESCRIPTOR *SecurityDescriptor = NULL; ++ PACL Acl = NULL, ThreadAcl = NULL; ++ SECURITY_DESCRIPTOR *SecurityDescriptor = NULL, *ThreadSecurityDescriptor = NULL; + char buffer[MAX_PATH]; + PROCESS_INFORMATION info; + STARTUPINFOA startup; +- SECURITY_ATTRIBUTES psa; ++ SECURITY_ATTRIBUTES psa, tsa; + HANDLE token, event; + DWORD size; + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = { SECURITY_WORLD_SID_AUTHORITY }; +@@ -2657,12 +2657,38 @@ static void test_process_security(void) + psa.nLength = sizeof(psa); + psa.lpSecurityDescriptor = SecurityDescriptor; + psa.bInheritHandle = TRUE; ++ ++ ++ ThreadSecurityDescriptor = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH); ++ res = InitializeSecurityDescriptor(ThreadSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); ++ ok(res, "InitializeSecurityDescriptor failed with error %d\n", GetLastError()); ++ ++ ThreadAcl = HeapAlloc(GetProcessHeap(), 0, 256); ++ res = InitializeAcl(ThreadAcl, 256, ACL_REVISION); ++ ok(res, "InitializeAcl failed with error %d\n", GetLastError()); ++ res = AddAccessDeniedAce(ThreadAcl, ACL_REVISION, THREAD_SET_THREAD_TOKEN, AdminSid); ++ ok(res, "AddAccessDeniedAce failed with error %d\n", GetLastError()); ++ res = AddAccessAllowedAce(ThreadAcl, ACL_REVISION, THREAD_ALL_ACCESS, AdminSid); ++ ok(res, "AddAccessAllowedAce failed with error %d\n", GetLastError()); ++ ++ res = SetSecurityDescriptorOwner(ThreadSecurityDescriptor, AdminSid, FALSE); ++ ok(res, "SetSecurityDescriptorOwner failed with error %d\n", GetLastError()); ++ res = SetSecurityDescriptorGroup(ThreadSecurityDescriptor, UsersSid, FALSE); ++ ok(res, "SetSecurityDescriptorGroup failed with error %d\n", GetLastError()); ++ res = SetSecurityDescriptorDacl(ThreadSecurityDescriptor, TRUE, ThreadAcl, FALSE); ++ ok(res, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError()); ++ ++ tsa.nLength = sizeof(tsa); ++ tsa.lpSecurityDescriptor = ThreadSecurityDescriptor; ++ tsa.bInheritHandle = TRUE; + + /* Doesn't matter what ACL say we should get full access for ourselves */ +- res = CreateProcessA( NULL, buffer, &psa, NULL, FALSE, 0, NULL, NULL, &startup, &info ); ++ res = CreateProcessA( NULL, buffer, &psa, &tsa, FALSE, 0, NULL, NULL, &startup, &info ); + ok(res, "CreateProcess with err:%d\n", GetLastError()); + TEST_GRANTED_ACCESS2( info.hProcess, PROCESS_ALL_ACCESS_NT4, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL ); ++ TEST_GRANTED_ACCESS2( info.hThread, THREAD_ALL_ACCESS_NT4, ++ STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL ); + winetest_wait_child_process( info.hProcess ); + + FreeSid(EveryoneSid); +@@ -2673,6 +2699,8 @@ static void test_process_security(void) + HeapFree(GetProcessHeap(), 0, owner); + HeapFree(GetProcessHeap(), 0, Acl); + HeapFree(GetProcessHeap(), 0, SecurityDescriptor); ++ HeapFree(GetProcessHeap(), 0, ThreadAcl); ++ HeapFree(GetProcessHeap(), 0, ThreadSecurityDescriptor); + } + + static void test_process_security_child(void) +@@ -2728,6 +2756,15 @@ static void test_process_security_child(void) + TEST_GRANTED_ACCESS( handle1, PROCESS_VM_READ ); + CloseHandle( handle1 ); + CloseHandle( handle ); ++ ++ ++ handle = OpenThread( THREAD_TERMINATE, FALSE, GetCurrentThreadId() ); ++ ok(handle != NULL, "OpenThread(THREAD_TERMINATE) with err:%d\n", GetLastError()); ++ TEST_GRANTED_ACCESS( handle, PROCESS_TERMINATE ); ++ CloseHandle( handle ); ++ ++ handle = OpenThread( THREAD_SET_THREAD_TOKEN, FALSE, GetCurrentThreadId() ); ++ ok(handle == NULL, "OpenThread(THREAD_SET_THREAD_TOKEN) should have failed\n"); + } + + static void test_impersonation_level(void) +diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c +index 5f6c2e5..a01e681 100644 +--- a/dlls/kernel32/process.c ++++ b/dlls/kernel32/process.c +@@ -2003,8 +2003,8 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + int socketfd[2], stdin_fd = -1, stdout_fd = -1; + pid_t pid; + int err, cpu; +- struct security_descriptor *psd = NULL; +- data_size_t psd_len = 0; ++ struct security_descriptor *psd = NULL, *tsd = NULL; ++ data_size_t psd_len = 0, tsd_len = 0; + + if ((cpu = get_process_cpu( filename, binary_info )) == -1) + { +@@ -2022,12 +2022,26 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + return FALSE; + } + } ++ ++ if (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->lpSecurityDescriptor) ++ { ++ status = create_struct_sd( tsa->lpSecurityDescriptor, &tsd, &tsd_len ); ++ ++ if (status != STATUS_SUCCESS) ++ { ++ RtlFreeHeap(GetProcessHeap(), 0, psd); ++ WARN("Invalid thread security descriptor with status %x\n", status); ++ SetLastError( RtlNtStatusToDosError(status) ); ++ return FALSE; ++ } ++ } + + /* create the socket for the new process */ + + if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1) + { + RtlFreeHeap(GetProcessHeap(), 0, psd); ++ RtlFreeHeap(GetProcessHeap(), 0, tsd); + SetLastError( ERROR_TOO_MANY_OPEN_FILES ); + return FALSE; + } +@@ -2068,6 +2082,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + } + close( socketfd[0] ); + RtlFreeHeap(GetProcessHeap(), 0, psd); ++ RtlFreeHeap(GetProcessHeap(), 0, tsd); + SetLastError( RtlNtStatusToDosError( status )); + return FALSE; + } +@@ -2081,6 +2096,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + close( socketfd[0] ); + close( socketfd[1] ); + RtlFreeHeap(GetProcessHeap(), 0, psd); ++ RtlFreeHeap(GetProcessHeap(), 0, tsd); + return FALSE; + } + if (!env) env = NtCurrentTeb()->Peb->ProcessParameters->Environment; +@@ -2115,11 +2131,12 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0; + req->cpu = cpu; + req->process_sd_size = psd_len; +- req->thread_sd_size = 0; ++ req->thread_sd_size = tsd_len; + req->info_size = startup_info_size; + req->env_size = (env_end - env) * sizeof(WCHAR); + + wine_server_add_data( req, psd , req->process_sd_size ); ++ wine_server_add_data( req, tsd , req->thread_sd_size ); + wine_server_add_data( req, startup_info, req->info_size ); + wine_server_add_data( req, env , req->env_size ); + +@@ -2135,6 +2152,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW + SERVER_END_REQ; + + RtlFreeHeap(GetProcessHeap(), 0, psd); ++ RtlFreeHeap(GetProcessHeap(), 0, tsd); + + RtlReleasePebLock(); + if (status) +diff --git a/server/process.c b/server/process.c +index 1fba134..f9a4611 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -883,7 +883,7 @@ DECL_HANDLER(new_process) + const startup_info_t *req_info; + data_size_t req_info_size; + const WCHAR *req_env; +- const struct security_descriptor *req_psd = NULL; ++ const struct security_descriptor *req_psd = NULL, *req_tsd = NULL; + + if (socket_fd == -1) + { +@@ -919,6 +919,18 @@ DECL_HANDLER(new_process) + } + } + ++ if (req->thread_sd_size) ++ { ++ req_tsd = (const struct security_descriptor *) ++ ((char*)get_req_data() + req->process_sd_size); ++ ++ if (!sd_is_valid( req_tsd, req->thread_sd_size )) ++ { ++ set_error( STATUS_INVALID_SECURITY_DESCR ); ++ return; ++ } ++ } ++ + req_info = (const startup_info_t *) + ((char*)get_req_data() + req->process_sd_size + req->thread_sd_size); + +@@ -1035,6 +1047,20 @@ DECL_HANDLER(new_process) + DACL_SECURITY_INFORMATION| + SACL_SECURITY_INFORMATION ); + } ++ ++ if (req_tsd) ++ { ++ /* In CreateProcess the thread defaults come from the process token, ++ * (this is not the case during CreateThread however) */ ++ set_sd_defaults_from_token( &thread->obj, ++ req_tsd, ++ OWNER_SECURITY_INFORMATION| ++ GROUP_SECURITY_INFORMATION| ++ DACL_SECURITY_INFORMATION| ++ SACL_SECURITY_INFORMATION, ++ process->token ); ++ } ++ + done: + release_object( info ); + } +-- +1.7.9.5 + diff --git a/patches/16-server-CreateProcess_ACLs/definition b/patches/16-server-CreateProcess_ACLs/definition new file mode 100644 index 00000000..967b970d --- /dev/null +++ b/patches/16-server-CreateProcess_ACLs/definition @@ -0,0 +1,11 @@ +Author: Joris van der Wel +Subject: Implement passing ACLs to CreateProcess. +Revision: 1 +Fixes: [22006] Support for process ACLs + +# Both patches modify server/process.c +Depends: 13-Misc_ACL + +# Both patches modify server/protocol.def +Depends: 09-TransmitFile + diff --git a/patches/Makefile b/patches/Makefile index a9c64d64..af520804 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -19,6 +19,7 @@ PATCHLIST := 00-Commandline.ok \ 13-Misc_ACL.ok \ 14-UrlCombineW.ok \ 15-wtsapi32.ok \ + 16-server-CreateProcess_ACLs.ok \ 97-Pipelight.ok \ 98-Miscellaneous.ok @@ -277,6 +278,23 @@ abort: echo "+ { \"15-wtsapi32\", \"Sebastian Lackner\", \"Partial implementation of WTSEnumerateProcessesW.\" },"; \ ) > 15-wtsapi32.ok +# Patchset 16-server-CreateProcess_ACLs +# | +# | Included patches: +# | * Implement passing ACLs to CreateProcess. [by Joris van der Wel] +# | +# | This patchset fixes the following Wine bugs: +# | * [#22006] OpenProcess does not enforce ACL +# | +16-server-CreateProcess_ACLs.ok: 09-TransmitFile.ok 13-Misc_ACL.ok + $(PATCH) < 16-server-CreateProcess_ACLs/0001-server-A-new-function-set_sd_defaults_from_token-try.patch + $(PATCH) < 16-server-CreateProcess_ACLs/0002-server-Support-sending-process-and-thread-security-d.patch + $(PATCH) < 16-server-CreateProcess_ACLs/0003-server-implement-passing-a-process-security-descript.patch + $(PATCH) < 16-server-CreateProcess_ACLs/0004-server-implement-passing-a-thread-security-descripto.patch + ( \ + echo "+ { \"16-server-CreateProcess_ACLs\", \"Joris van der Wel\", \"Implement passing ACLs to CreateProcess.\" },"; \ + ) > 16-server-CreateProcess_ACLs.ok + # Patchset 97-Pipelight # | # | Included patches: