From d0bea3d70207587f183bcad0e40cfeba8668c6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Wed, 23 Sep 2020 23:44:55 -0500 Subject: [PATCH] server: Implement support for creating a process with a specified token. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/advapi32/tests/security.c | 24 +++++++++++------------- dlls/ntdll/unix/process.c | 2 +- include/wine/server_protocol.h | 4 +++- server/process.c | 17 +++++++++++++---- server/process.h | 2 +- server/protocol.def | 1 + server/request.c | 2 +- server/request.h | 21 +++++++++++---------- server/security.h | 1 + server/token.c | 5 +++++ server/trace.c | 3 ++- 11 files changed, 50 insertions(+), 32 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index bd8cc5f061b..c9318bef928 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -7732,16 +7732,16 @@ static void test_duplicate_handle_access_child(void) SetLastError(0xdeadbeef); event2 = OpenEventA(EVENT_MODIFY_STATE, FALSE, "test_dup"); - todo_wine ok(!event2, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + ok(!event2, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); ret = DuplicateHandle(process, event, process, &event2, EVENT_MODIFY_STATE, FALSE, 0); - ok(ret, "got error %u\n", GetLastError()); + todo_wine ok(ret, "got error %u\n", GetLastError()); SetLastError(0xdeadbeef); ret = DuplicateHandle(process, event, GetCurrentProcess(), &event2, EVENT_MODIFY_STATE, FALSE, 0); - todo_wine ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); ret = DuplicateHandle(process, (HANDLE)(ULONG_PTR)_atoi64(myARGV[5]), GetCurrentProcess(), &token, 0, FALSE, DUPLICATE_SAME_ACCESS); @@ -7823,17 +7823,15 @@ static void test_create_process_token(void) ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); ok(ret, "got error %u\n", GetLastError()); ret = CreateProcessAsUserA(token, NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - todo_wine ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); - if (ret) join_process(&pi); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); CloseHandle(token); ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ASSIGN_PRIMARY, &token); ok(ret, "got error %u\n", GetLastError()); ret = CreateProcessAsUserA(token, NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - todo_wine ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); - if (ret) join_process(&pi); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); CloseHandle(token); ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE, &token); @@ -7875,8 +7873,8 @@ static void test_create_process_token_child(void) } else { - todo_wine ok(!event, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + ok(!event, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); } } diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index a6be00646a8..5ccf435e9ff 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -894,7 +894,6 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_ TRACE( "%s image %s cmdline %s parent %p\n", debugstr_us( &path ), debugstr_us( ¶ms->ImagePathName ), debugstr_us( ¶ms->CommandLine ), parent ); if (debug) FIXME( "debug port %p not supported yet\n", debug ); - if (token) FIXME( "token %p not supported yet\n", token ); unixdir = get_unix_curdir( params ); @@ -942,6 +941,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_ SERVER_START_REQ( new_process ) { + req->token = wine_server_obj_handle( token ); req->parent_process = wine_server_obj_handle( parent ); req->inherit_all = !!(process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES); req->create_flags = params->DebugFlags; /* hack: creation flags stored in DebugFlags for now */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 5ca108bbf17..ea62e73f63c 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -773,6 +773,7 @@ struct rawinput_device struct new_process_request { struct request_header __header; + obj_handle_t token; obj_handle_t parent_process; int inherit_all; unsigned int create_flags; @@ -786,6 +787,7 @@ struct new_process_request /* VARARG(handles,uints,handles_size); */ /* VARARG(info,startup_info,info_size); */ /* VARARG(env,unicode_str); */ + char __pad_52[4]; }; struct new_process_reply { @@ -6300,7 +6302,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 646 +#define SERVER_PROTOCOL_VERSION 647 /* ### protocol_version end ### */ diff --git a/server/process.c b/server/process.c index 1650bd8f354..26958308ca7 100644 --- a/server/process.c +++ b/server/process.c @@ -504,7 +504,7 @@ static void start_sigkill_timer( struct process *process ) /* if the function fails the fd is closed */ struct process *create_process( int fd, struct process *parent, int inherit_all, const struct security_descriptor *sd, const obj_handle_t *handles, - unsigned int handle_count ) + unsigned int handle_count, struct token *token ) { struct process *process; @@ -581,7 +581,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all, : alloc_handle_table( process, 0 ); /* Note: for security reasons, starting a new process does not attempt * to use the current impersonation token for the new process */ - process->token = token_duplicate( parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 ); + process->token = token_duplicate( token ? token : parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 ); process->affinity = parent->affinity; } if (!process->handles || !process->token) goto error; @@ -1102,6 +1102,7 @@ DECL_HANDLER(new_process) const struct security_descriptor *sd; const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL ); struct process *process = NULL; + struct token *token = NULL; struct process *parent; struct thread *parent_thread = current; int socket_fd = thread_get_inflight_fd( current, req->socket_fd ); @@ -1220,7 +1221,14 @@ DECL_HANDLER(new_process) #undef FIXUP_LEN } - if (!(process = create_process( socket_fd, parent, req->inherit_all, sd, handles, req->handles_size / sizeof(*handles) ))) + if (req->token && !(token = get_token_obj( current->process, req->token, TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY ))) + { + close( socket_fd ); + goto done; + } + + if (!(process = create_process( socket_fd, parent, req->inherit_all, sd, + handles, req->handles_size / sizeof(*handles), token ))) goto done; process->startup_info = (struct startup_info *)grab_object( info ); @@ -1284,6 +1292,7 @@ DECL_HANDLER(new_process) done: if (process) release_object( process ); + if (token) release_object( token ); release_object( parent ); release_object( info ); } @@ -1316,7 +1325,7 @@ DECL_HANDLER(exec_process) close( socket_fd ); return; } - if (!(process = create_process( socket_fd, NULL, 0, NULL, NULL, 0 ))) return; + if (!(process = create_process( socket_fd, NULL, 0, NULL, NULL, 0, NULL ))) return; create_thread( -1, process, NULL ); release_object( process ); } diff --git a/server/process.h b/server/process.h index 7facc4f6dfa..bc81d563b47 100644 --- a/server/process.h +++ b/server/process.h @@ -110,7 +110,7 @@ extern void free_ptid( unsigned int id ); extern void *get_ptid_entry( unsigned int id ); extern struct process *create_process( int fd, struct process *parent, int inherit_all, const struct security_descriptor *sd, const obj_handle_t *handles, - unsigned int handle_count ); + unsigned int handle_count, struct token *token ); extern data_size_t init_process( struct thread *thread ); extern struct thread *get_process_first_thread( struct process *process ); extern struct process *get_process_from_id( process_id_t id ); diff --git a/server/protocol.def b/server/protocol.def index 85af5f0061c..f538c6dcf51 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -787,6 +787,7 @@ struct rawinput_device /* Create a new process from the context of the parent */ @REQ(new_process) + obj_handle_t token; /* process token */ obj_handle_t parent_process; /* parent process */ int inherit_all; /* inherit all handles from parent */ unsigned int create_flags; /* creation flags */ diff --git a/server/request.c b/server/request.c index 3ef4a244b84..40e9478e09e 100644 --- a/server/request.c +++ b/server/request.c @@ -583,7 +583,7 @@ static void master_socket_poll_event( struct fd *fd, int event ) int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len ); if (client == -1) return; fcntl( client, F_SETFL, O_NONBLOCK ); - if ((process = create_process( client, NULL, 0, NULL, NULL, 0 ))) + if ((process = create_process( client, NULL, 0, NULL, NULL, 0, NULL ))) { create_thread( -1, process, NULL ); release_object( process ); diff --git a/server/request.h b/server/request.h index f407ef2051e..bc6f29f2110 100644 --- a/server/request.h +++ b/server/request.h @@ -719,16 +719,17 @@ C_ASSERT( sizeof(unsigned char) == 1 ); C_ASSERT( sizeof(unsigned int) == 4 ); C_ASSERT( sizeof(unsigned short) == 2 ); C_ASSERT( sizeof(user_handle_t) == 4 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, parent_process) == 12 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 16 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 20 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 24 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 28 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 32 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 36 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 40 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, handles_size) == 44 ); -C_ASSERT( sizeof(struct new_process_request) == 48 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, token) == 12 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, parent_process) == 16 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 20 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 24 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 28 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 32 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 36 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 40 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 44 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, handles_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, handle) == 16 ); diff --git a/server/security.h b/server/security.h index 7c35300afe4..bece7f54048 100644 --- a/server/security.h +++ b/server/security.h @@ -53,6 +53,7 @@ extern const PSID security_high_label_sid; /* token functions */ +extern struct token *get_token_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern struct token *token_create_admin(void); extern int token_assign_label( struct token *token, PSID label ); extern struct token *token_duplicate( struct token *src_token, unsigned primary, diff --git a/server/token.c b/server/token.c index 8404e651196..8a106b7d34f 100644 --- a/server/token.c +++ b/server/token.c @@ -835,6 +835,11 @@ int token_assign_label( struct token *token, PSID label ) return ret; } +struct token *get_token_obj( struct process *process, obj_handle_t handle, unsigned int access ) +{ + return (struct token *)get_handle_obj( process, handle, access, &token_ops ); +} + struct token *token_create_admin( void ) { struct token *token = NULL; diff --git a/server/trace.c b/server/trace.c index 17ae88aa9a4..ffe9d6e19c6 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1284,7 +1284,8 @@ typedef void (*dump_func)( const void *req ); static void dump_new_process_request( const struct new_process_request *req ) { - fprintf( stderr, " parent_process=%04x", req->parent_process ); + fprintf( stderr, " token=%04x", req->token ); + fprintf( stderr, ", parent_process=%04x", req->parent_process ); fprintf( stderr, ", inherit_all=%d", req->inherit_all ); fprintf( stderr, ", create_flags=%08x", req->create_flags ); fprintf( stderr, ", socket_fd=%d", req->socket_fd );