From 4a328e08aca20a46ecbee634ffba873e0ab29b28 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Thu, 20 Sep 2018 13:06:12 +0200
Subject: [PATCH] server: Allow specifying the security descriptor for a new
 thread.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
---
 dlls/kernel32/thread.c         |  2 +-
 dlls/ntdll/thread.c            | 20 +++++++++++++++++---
 include/wine/server_protocol.h |  5 ++---
 include/winternl.h             |  2 +-
 server/process.c               |  2 +-
 server/protocol.def            |  2 +-
 server/request.h               |  7 +++----
 server/thread.c                | 19 ++++++++++++++++---
 server/thread.h                |  3 ++-
 server/trace.c                 |  2 +-
 10 files changed, 45 insertions(+), 19 deletions(-)

diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c
index a86ad3443a4..e6b99aed62c 100644
--- a/dlls/kernel32/thread.c
+++ b/dlls/kernel32/thread.c
@@ -97,7 +97,7 @@ HANDLE WINAPI CreateRemoteThreadEx( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SI
     if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
     else stack_commit = stack;
 
-    status = RtlCreateUserThread( hProcess, NULL, TRUE,
+    status = RtlCreateUserThread( hProcess, sa ? sa->lpSecurityDescriptor : NULL, TRUE,
                                   NULL, stack_reserve, stack_commit,
                                   (PRTL_THREAD_START_ROUTINE)start, param, &handle, &client_id );
     if (status == STATUS_SUCCESS)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index f8b9ce1bdb8..7fa087defe5 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -544,7 +544,7 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle_ptr, ACCESS_MASK access, OBJECT
 /***********************************************************************
  *              RtlCreateUserThread   (NTDLL.@)
  */
-NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr,
+NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
                                      BOOLEAN suspended, PVOID stack_addr,
                                      SIZE_T stack_reserve, SIZE_T stack_commit,
                                      PRTL_THREAD_START_ROUTINE start, void *param,
@@ -561,6 +561,8 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
     int request_pipe[2];
     NTSTATUS status;
     SIZE_T extra_stack = PTHREAD_STACK_MIN;
+    data_size_t len = 0;
+    struct object_attributes *objattr = NULL;
 
     if (process != NtCurrentProcess())
     {
@@ -587,15 +589,26 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
         return result.create_thread.status;
     }
 
-    if (server_pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
+    if (descr)
+    {
+        OBJECT_ATTRIBUTES thread_attr;
+        InitializeObjectAttributes( &thread_attr, NULL, 0, NULL, descr );
+        if ((status = alloc_object_attributes( &thread_attr, &objattr, &len ))) return status;
+    }
+
+    if (server_pipe( request_pipe ) == -1)
+    {
+        RtlFreeHeap( GetProcessHeap(), 0, objattr );
+        return STATUS_TOO_MANY_OPENED_FILES;
+    }
     wine_server_send_fd( request_pipe[0] );
 
     SERVER_START_REQ( new_thread )
     {
         req->access     = THREAD_ALL_ACCESS;
-        req->attributes = 0;  /* FIXME */
         req->suspend    = suspended;
         req->request_fd = request_pipe[0];
+        wine_server_add_data( req, objattr, len );
         if (!(status = wine_server_call( req )))
         {
             handle = wine_server_ptr_handle( reply->handle );
@@ -605,6 +618,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
     }
     SERVER_END_REQ;
 
+    RtlFreeHeap( GetProcessHeap(), 0, objattr );
     if (status)
     {
         close( request_pipe[1] );
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 24eb95be26d..d31a1d48419 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -767,10 +767,9 @@ struct new_thread_request
 {
     struct request_header __header;
     unsigned int access;
-    unsigned int attributes;
     int          suspend;
     int          request_fd;
-    char __pad_28[4];
+    /* VARARG(objattr,object_attributes); */
 };
 struct new_thread_reply
 {
@@ -6535,6 +6534,6 @@ union generic_reply
     struct terminate_job_reply terminate_job_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 560
+#define SERVER_PROTOCOL_VERSION 561
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winternl.h b/include/winternl.h
index dca8ff32dc2..c718d4c64a3 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -2608,7 +2608,7 @@ NTSYSAPI NTSTATUS  WINAPI RtlCreateTimer(PHANDLE, HANDLE, RTL_WAITORTIMERCALLBAC
 NTSYSAPI BOOLEAN   WINAPI RtlCreateUnicodeString(PUNICODE_STRING,LPCWSTR);
 NTSYSAPI BOOLEAN   WINAPI RtlCreateUnicodeStringFromAsciiz(PUNICODE_STRING,LPCSTR);
 NTSYSAPI NTSTATUS  WINAPI RtlCreateUserProcess(UNICODE_STRING*,ULONG,RTL_USER_PROCESS_PARAMETERS*,SECURITY_DESCRIPTOR*,SECURITY_DESCRIPTOR*,HANDLE,BOOLEAN,HANDLE,HANDLE,RTL_USER_PROCESS_INFORMATION*);
-NTSYSAPI NTSTATUS  WINAPI RtlCreateUserThread(HANDLE,const SECURITY_DESCRIPTOR*,BOOLEAN,PVOID,SIZE_T,SIZE_T,PRTL_THREAD_START_ROUTINE,void*,HANDLE*,CLIENT_ID*);
+NTSYSAPI NTSTATUS  WINAPI RtlCreateUserThread(HANDLE,SECURITY_DESCRIPTOR*,BOOLEAN,PVOID,SIZE_T,SIZE_T,PRTL_THREAD_START_ROUTINE,void*,HANDLE*,CLIENT_ID*);
 NTSYSAPI void      WINAPI RtlDeactivateActivationContext(DWORD,ULONG_PTR);
 NTSYSAPI PVOID     WINAPI RtlDecodePointer(PVOID);
 NTSYSAPI NTSTATUS  WINAPI RtlDecompressBuffer(USHORT,PUCHAR,ULONG,PUCHAR,ULONG,PULONG);
diff --git a/server/process.c b/server/process.c
index f8739d00b64..8b808de388f 100644
--- a/server/process.c
+++ b/server/process.c
@@ -590,7 +590,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
         goto error;
     }
     close( request_pipe[1] );
-    if (!(thread = create_thread( request_pipe[0], process ))) goto error;
+    if (!(thread = create_thread( request_pipe[0], process, NULL ))) goto error;
 
     set_fd_events( process->msg_fd, POLLIN );  /* start listening to events */
     release_object( process );
diff --git a/server/protocol.def b/server/protocol.def
index 8bff5d8d482..46669d6c8fe 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -769,9 +769,9 @@ struct rawinput_device
 /* Create a new thread from the context of the parent */
 @REQ(new_thread)
     unsigned int access;       /* wanted access rights */
-    unsigned int attributes;   /* object attributes */
     int          suspend;      /* new thread should be suspended on creation */
     int          request_fd;   /* fd for request pipe */
+    VARARG(objattr,object_attributes); /* object attributes */
 @REPLY
     thread_id_t  tid;          /* thread id */
     obj_handle_t handle;       /* thread handle (in the current process) */
diff --git a/server/request.h b/server/request.h
index 6005d1f8f54..ff2da53e4ee 100644
--- a/server/request.h
+++ b/server/request.h
@@ -753,10 +753,9 @@ C_ASSERT( FIELD_OFFSET(struct get_new_process_info_reply, success) == 8 );
 C_ASSERT( FIELD_OFFSET(struct get_new_process_info_reply, exit_code) == 12 );
 C_ASSERT( sizeof(struct get_new_process_info_reply) == 16 );
 C_ASSERT( FIELD_OFFSET(struct new_thread_request, access) == 12 );
-C_ASSERT( FIELD_OFFSET(struct new_thread_request, attributes) == 16 );
-C_ASSERT( FIELD_OFFSET(struct new_thread_request, suspend) == 20 );
-C_ASSERT( FIELD_OFFSET(struct new_thread_request, request_fd) == 24 );
-C_ASSERT( sizeof(struct new_thread_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct new_thread_request, suspend) == 16 );
+C_ASSERT( FIELD_OFFSET(struct new_thread_request, request_fd) == 20 );
+C_ASSERT( sizeof(struct new_thread_request) == 24 );
 C_ASSERT( FIELD_OFFSET(struct new_thread_reply, tid) == 8 );
 C_ASSERT( FIELD_OFFSET(struct new_thread_reply, handle) == 12 );
 C_ASSERT( sizeof(struct new_thread_reply) == 16 );
diff --git a/server/thread.c b/server/thread.c
index 2cf5054738a..9ee846df937 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -218,7 +218,7 @@ static inline int is_valid_address( client_ptr_t addr )
 }
 
 /* create a new thread */
-struct thread *create_thread( int fd, struct process *process )
+struct thread *create_thread( int fd, struct process *process, const struct security_descriptor *sd )
 {
     struct thread *thread;
 
@@ -244,6 +244,15 @@ struct thread *create_thread( int fd, struct process *process )
 
     list_add_head( &thread_list, &thread->entry );
 
+    if (sd && !set_sd_defaults_from_token( &thread->obj, sd,
+                                           OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+                                           DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
+                                           process->token ))
+    {
+        close( fd );
+        release_object( thread );
+        return NULL;
+    }
     if (!(thread->id = alloc_ptid( thread )))
     {
         close( fd );
@@ -1244,6 +1253,9 @@ unsigned int get_supported_cpu_mask(void)
 DECL_HANDLER(new_thread)
 {
     struct thread *thread;
+    struct unicode_str name;
+    const struct security_descriptor *sd;
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
     int request_fd = thread_get_inflight_fd( current, req->request_fd );
 
     if (request_fd == -1 || fcntl( request_fd, F_SETFL, O_NONBLOCK ) == -1)
@@ -1253,12 +1265,13 @@ DECL_HANDLER(new_thread)
         return;
     }
 
-    if ((thread = create_thread( request_fd, current->process )))
+    if ((thread = create_thread( request_fd, current->process, sd )))
     {
         thread->system_regs = current->system_regs;
         if (req->suspend) thread->suspend++;
         reply->tid = get_thread_id( thread );
-        if ((reply->handle = alloc_handle( current->process, thread, req->access, req->attributes )))
+        if ((reply->handle = alloc_handle_no_access_check( current->process, thread,
+                                                           req->access, objattr->attributes )))
         {
             /* thread object will be released when the thread gets killed */
             return;
diff --git a/server/thread.h b/server/thread.h
index 3cb7cb6cf15..e4332df4abd 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -102,7 +102,8 @@ extern struct thread *current;
 
 /* thread functions */
 
-extern struct thread *create_thread( int fd, struct process *process );
+extern struct thread *create_thread( int fd, struct process *process,
+                                     const struct security_descriptor *sd );
 extern struct thread *get_thread_from_id( thread_id_t id );
 extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access );
 extern struct thread *get_thread_from_tid( int tid );
diff --git a/server/trace.c b/server/trace.c
index 1a28cac13e5..3054a18d6a4 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1262,9 +1262,9 @@ static void dump_get_new_process_info_reply( const struct get_new_process_info_r
 static void dump_new_thread_request( const struct new_thread_request *req )
 {
     fprintf( stderr, " access=%08x", req->access );
-    fprintf( stderr, ", attributes=%08x", req->attributes );
     fprintf( stderr, ", suspend=%d", req->suspend );
     fprintf( stderr, ", request_fd=%d", req->request_fd );
+    dump_varargs_object_attributes( ", objattr=", cur_size );
 }
 
 static void dump_new_thread_reply( const struct new_thread_reply *req )
-- 
GitLab