ntdll: Validate job handles at process creation.

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2021-05-20 03:29:03 +03:00 committed by Alexandre Julliard
parent 0f4bc32286
commit ddd161f339
7 changed files with 82 additions and 5 deletions

View File

@ -4540,6 +4540,9 @@ static void test_nested_jobs(void)
static void test_job_list_attribute(void)
{
PPROC_THREAD_ATTRIBUTE_LIST attrs;
char buffer[MAX_PATH + 19];
PROCESS_INFORMATION pi;
STARTUPINFOEXA si;
HANDLE jobs[2];
SIZE_T size;
BOOL ret;
@ -4586,6 +4589,30 @@ static void test_job_list_attribute(void)
sizeof(*jobs) * 2, NULL, NULL);
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
sizeof(*jobs), NULL, NULL);
memset(&si, 0, sizeof(si));
si.StartupInfo.cb = sizeof(si);
si.lpAttributeList = attrs;
sprintf(buffer, "\"%s\" process wait", selfname);
ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
(STARTUPINFOA *)&si, &pi);
ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %u.\n",
ret, GetLastError());
ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
sizeof(*jobs), NULL, NULL);
ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
(STARTUPINFOA *)&si, &pi);
ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %u.\n",
ret, GetLastError());
pDeleteProcThreadAttributeList(attrs);
heap_free(attrs);
}

View File

@ -628,9 +628,9 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
UNICODE_STRING redir, path = {0};
OBJECT_ATTRIBUTES attr, empty_attr = { sizeof(empty_attr) };
SIZE_T i, attr_count = (ps_attr->TotalLength - sizeof(ps_attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
const PS_ATTRIBUTE *handles_attr = NULL;
data_size_t handles_size;
obj_handle_t *handles;
const PS_ATTRIBUTE *handles_attr = NULL, *jobs_attr = NULL;
data_size_t handles_size, jobs_size;
obj_handle_t *handles, *jobs;
for (i = 0; i < attr_count; i++)
{
@ -653,6 +653,9 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
if (process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
handles_attr = &ps_attr->Attributes[i];
break;
case PS_ATTRIBUTE_JOB_LIST:
jobs_attr = &ps_attr->Attributes[i];
break;
default:
if (ps_attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
FIXME( "unhandled input attribute %lx\n", ps_attr->Attributes[i].Attribute );
@ -690,6 +693,13 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
goto done;
}
if ((status = alloc_handle_list( jobs_attr, &jobs, &jobs_size )))
{
free( objattr );
free( handles );
goto done;
}
/* create the socket for the new process */
if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
@ -697,6 +707,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
status = STATUS_TOO_MANY_OPENED_FILES;
free( objattr );
free( handles );
free( jobs );
goto done;
}
#ifdef SO_PASSCRED
@ -722,8 +733,10 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
req->access = process_access;
req->info_size = startup_info_size;
req->handles_size = handles_size;
req->jobs_size = jobs_size;
wine_server_add_data( req, objattr, attr_len );
wine_server_add_data( req, handles, handles_size );
wine_server_add_data( req, jobs, jobs_size );
wine_server_add_data( req, startup_info, startup_info_size );
wine_server_add_data( req, params->Environment, env_size );
if (!(status = wine_server_call( req )))
@ -736,6 +749,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
SERVER_END_REQ;
free( objattr );
free( handles );
free( jobs );
if (status)
{

View File

@ -841,10 +841,13 @@ struct new_process_request
char __pad_38[2];
data_size_t info_size;
data_size_t handles_size;
data_size_t jobs_size;
/* VARARG(objattr,object_attributes); */
/* VARARG(handles,uints,handles_size); */
/* VARARG(jobs,uints,jobs_size); */
/* VARARG(info,startup_info,info_size); */
/* VARARG(env,unicode_str); */
char __pad_52[4];
};
struct new_process_reply
{
@ -6244,7 +6247,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 701
#define SERVER_PROTOCOL_VERSION 702
/* ### protocol_version end ### */

View File

@ -1106,6 +1106,8 @@ DECL_HANDLER(new_process)
struct thread *parent_thread = current;
int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
const obj_handle_t *handles = NULL;
const obj_handle_t *job_handles = NULL;
unsigned int i, job_handle_count;
struct job *job;
if (socket_fd == -1)
@ -1178,6 +1180,31 @@ DECL_HANDLER(new_process)
info_ptr = (const char *)info_ptr + req->handles_size;
info->data_size -= req->handles_size;
}
if ((req->jobs_size & 3) || req->jobs_size > info->data_size)
{
set_error( STATUS_INVALID_PARAMETER );
close( socket_fd );
goto done;
}
if (req->jobs_size)
{
job_handles = info_ptr;
info_ptr = (const char *)info_ptr + req->jobs_size;
info->data_size -= req->jobs_size;
}
job_handle_count = req->jobs_size / sizeof(*handles);
for (i = 0; i < job_handle_count; ++i)
{
if (!(job = get_job_obj( current->process, job_handles[i], JOB_OBJECT_ASSIGN_PROCESS )))
{
close( socket_fd );
goto done;
}
release_object( job );
}
info->info_size = min( req->info_size, info->data_size );
if (req->info_size < sizeof(*info->data))

View File

@ -854,8 +854,10 @@ typedef struct
unsigned short machine; /* architecture that the new process will use */
data_size_t info_size; /* size of startup info */
data_size_t handles_size; /* length of explicit handles list */
data_size_t jobs_size; /* length of jobs list */
VARARG(objattr,object_attributes); /* object attributes */
VARARG(handles,uints,handles_size); /* handles list */
VARARG(jobs,uints,jobs_size); /* jobs list */
VARARG(info,startup_info,info_size); /* startup information */
VARARG(env,unicode_str); /* environment for new process */
@REPLY

View File

@ -714,7 +714,8 @@ C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 32 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, machine) == 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, jobs_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 );

View File

@ -1388,8 +1388,10 @@ static void dump_new_process_request( const struct new_process_request *req )
fprintf( stderr, ", machine=%04x", req->machine );
fprintf( stderr, ", info_size=%u", req->info_size );
fprintf( stderr, ", handles_size=%u", req->handles_size );
fprintf( stderr, ", jobs_size=%u", req->jobs_size );
dump_varargs_object_attributes( ", objattr=", cur_size );
dump_varargs_uints( ", handles=", min(cur_size,req->handles_size) );
dump_varargs_uints( ", jobs=", min(cur_size,req->jobs_size) );
dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) );
dump_varargs_unicode_str( ", env=", cur_size );
}
@ -5329,6 +5331,7 @@ static const struct
{ "CANT_OPEN_ANONYMOUS", STATUS_CANT_OPEN_ANONYMOUS },
{ "CHILD_MUST_BE_VOLATILE", STATUS_CHILD_MUST_BE_VOLATILE },
{ "CONNECTION_ABORTED", STATUS_CONNECTION_ABORTED },
{ "CONNECTION_ACTIVE", STATUS_CONNECTION_ACTIVE },
{ "CONNECTION_REFUSED", STATUS_CONNECTION_REFUSED },
{ "CONNECTION_RESET", STATUS_CONNECTION_RESET },
{ "DEBUGGER_INACTIVE", STATUS_DEBUGGER_INACTIVE },