ntdll: Use a kernel APC to call NtDuplicateObject() if DUPLICATE_CLOSE_SOURCE is used on another process.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e69d5b9f46
commit
5df0f5f6fb
|
@ -580,6 +580,21 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result )
|
|||
else result->create_thread.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
case APC_DUP_HANDLE:
|
||||
{
|
||||
HANDLE dst_handle = NULL;
|
||||
|
||||
result->type = call->type;
|
||||
|
||||
result->dup_handle.status = NtDuplicateObject( NtCurrentProcess(),
|
||||
wine_server_ptr_handle(call->dup_handle.src_handle),
|
||||
wine_server_ptr_handle(call->dup_handle.dst_process),
|
||||
&dst_handle, call->dup_handle.access,
|
||||
call->dup_handle.attributes, call->dup_handle.options );
|
||||
result->dup_handle.handle = wine_server_obj_handle( dst_handle );
|
||||
NtClose( wine_server_ptr_handle(call->dup_handle.dst_process) );
|
||||
break;
|
||||
}
|
||||
case APC_BREAK_PROCESS:
|
||||
{
|
||||
HANDLE handle;
|
||||
|
@ -1679,6 +1694,27 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE
|
|||
{
|
||||
NTSTATUS ret;
|
||||
|
||||
if ((options & DUPLICATE_CLOSE_SOURCE) && source_process != NtCurrentProcess())
|
||||
{
|
||||
apc_call_t call;
|
||||
apc_result_t result;
|
||||
|
||||
memset( &call, 0, sizeof(call) );
|
||||
|
||||
call.dup_handle.type = APC_DUP_HANDLE;
|
||||
call.dup_handle.src_handle = wine_server_obj_handle( source );
|
||||
call.dup_handle.dst_process = wine_server_obj_handle( dest_process );
|
||||
call.dup_handle.access = access;
|
||||
call.dup_handle.attributes = attributes;
|
||||
call.dup_handle.options = options;
|
||||
ret = server_queue_process_apc( source_process, &call, &result );
|
||||
if (ret != STATUS_SUCCESS) return ret;
|
||||
|
||||
if (!result.dup_handle.status)
|
||||
*dest = wine_server_ptr_handle( result.dup_handle.handle );
|
||||
return result.dup_handle.status;
|
||||
}
|
||||
|
||||
SERVER_START_REQ( dup_handle )
|
||||
{
|
||||
req->src_process = wine_server_obj_handle( source_process );
|
||||
|
|
|
@ -467,6 +467,7 @@ enum apc_type
|
|||
APC_MAP_VIEW,
|
||||
APC_UNMAP_VIEW,
|
||||
APC_CREATE_THREAD,
|
||||
APC_DUP_HANDLE,
|
||||
APC_BREAK_PROCESS
|
||||
};
|
||||
|
||||
|
@ -577,6 +578,15 @@ typedef union
|
|||
mem_size_t reserve;
|
||||
mem_size_t commit;
|
||||
} create_thread;
|
||||
struct
|
||||
{
|
||||
enum apc_type type;
|
||||
obj_handle_t src_handle;
|
||||
obj_handle_t dst_process;
|
||||
unsigned int access;
|
||||
unsigned int attributes;
|
||||
unsigned int options;
|
||||
} dup_handle;
|
||||
} apc_call_t;
|
||||
|
||||
typedef union
|
||||
|
@ -665,6 +675,12 @@ typedef union
|
|||
obj_handle_t handle;
|
||||
} create_thread;
|
||||
struct
|
||||
{
|
||||
enum apc_type type;
|
||||
unsigned int status;
|
||||
obj_handle_t handle;
|
||||
} dup_handle;
|
||||
struct
|
||||
{
|
||||
enum apc_type type;
|
||||
unsigned int status;
|
||||
|
@ -1253,9 +1269,7 @@ struct dup_handle_reply
|
|||
{
|
||||
struct reply_header __header;
|
||||
obj_handle_t handle;
|
||||
int self;
|
||||
int closed;
|
||||
char __pad_20[4];
|
||||
char __pad_12[4];
|
||||
};
|
||||
|
||||
|
||||
|
@ -6229,7 +6243,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 686
|
||||
#define SERVER_PROTOCOL_VERSION 687
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -678,8 +678,7 @@ DECL_HANDLER(dup_handle)
|
|||
}
|
||||
/* close the handle no matter what happened */
|
||||
if ((req->options & DUPLICATE_CLOSE_SOURCE) && (src != dst || req->src_handle != reply->handle))
|
||||
reply->closed = !close_handle( src, req->src_handle );
|
||||
reply->self = (src == current->process);
|
||||
close_handle( src, req->src_handle );
|
||||
release_object( src );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -483,6 +483,7 @@ enum apc_type
|
|||
APC_MAP_VIEW,
|
||||
APC_UNMAP_VIEW,
|
||||
APC_CREATE_THREAD,
|
||||
APC_DUP_HANDLE,
|
||||
APC_BREAK_PROCESS
|
||||
};
|
||||
|
||||
|
@ -593,6 +594,15 @@ typedef union
|
|||
mem_size_t reserve; /* reserve size for thread stack */
|
||||
mem_size_t commit; /* commit size for thread stack */
|
||||
} create_thread;
|
||||
struct
|
||||
{
|
||||
enum apc_type type; /* APC_DUP_HANDLE */
|
||||
obj_handle_t src_handle; /* src handle to duplicate */
|
||||
obj_handle_t dst_process; /* dst process handle */
|
||||
unsigned int access; /* wanted access rights */
|
||||
unsigned int attributes; /* object attributes */
|
||||
unsigned int options; /* duplicate options */
|
||||
} dup_handle;
|
||||
} apc_call_t;
|
||||
|
||||
typedef union
|
||||
|
@ -681,6 +691,12 @@ typedef union
|
|||
obj_handle_t handle; /* handle to new thread */
|
||||
} create_thread;
|
||||
struct
|
||||
{
|
||||
enum apc_type type; /* APC_DUP_HANDLE */
|
||||
unsigned int status; /* status returned by call */
|
||||
obj_handle_t handle; /* duplicated handle in dst process */
|
||||
} dup_handle;
|
||||
struct
|
||||
{
|
||||
enum apc_type type; /* APC_BREAK_PROCESS */
|
||||
unsigned int status; /* status returned by call */
|
||||
|
@ -1117,8 +1133,6 @@ typedef struct
|
|||
unsigned int options; /* duplicate options */
|
||||
@REPLY
|
||||
obj_handle_t handle; /* duplicated handle in dst process */
|
||||
int self; /* is the source the current process? */
|
||||
int closed; /* whether the source handle has been closed */
|
||||
@END
|
||||
|
||||
|
||||
|
|
|
@ -879,9 +879,7 @@ C_ASSERT( FIELD_OFFSET(struct dup_handle_request, attributes) == 28 );
|
|||
C_ASSERT( FIELD_OFFSET(struct dup_handle_request, options) == 32 );
|
||||
C_ASSERT( sizeof(struct dup_handle_request) == 40 );
|
||||
C_ASSERT( FIELD_OFFSET(struct dup_handle_reply, handle) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct dup_handle_reply, self) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct dup_handle_reply, closed) == 16 );
|
||||
C_ASSERT( sizeof(struct dup_handle_reply) == 24 );
|
||||
C_ASSERT( sizeof(struct dup_handle_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct make_temporary_request, handle) == 12 );
|
||||
C_ASSERT( sizeof(struct make_temporary_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct open_process_request, pid) == 12 );
|
||||
|
|
|
@ -1756,6 +1756,21 @@ DECL_HANDLER(queue_apc)
|
|||
case APC_BREAK_PROCESS:
|
||||
process = get_process_from_handle( req->handle, PROCESS_CREATE_THREAD );
|
||||
break;
|
||||
case APC_DUP_HANDLE:
|
||||
process = get_process_from_handle( req->handle, PROCESS_DUP_HANDLE );
|
||||
if (process && process != current->process)
|
||||
{
|
||||
/* duplicate the destination process handle into the target process */
|
||||
obj_handle_t handle = duplicate_handle( current->process, apc->call.dup_handle.dst_process,
|
||||
process, 0, 0, DUPLICATE_SAME_ACCESS );
|
||||
if (handle) apc->call.dup_handle.dst_process = handle;
|
||||
else
|
||||
{
|
||||
release_object( process );
|
||||
process = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
break;
|
||||
|
|
|
@ -235,6 +235,11 @@ static void dump_apc_call( const char *prefix, const apc_call_t *call )
|
|||
dump_uint64( ",commit=", &call->create_thread.commit );
|
||||
fprintf( stderr, ",flags=%x", call->create_thread.flags );
|
||||
break;
|
||||
case APC_DUP_HANDLE:
|
||||
fprintf( stderr, "APC_DUP_HANDLE,src_handle=%04x,dst_process=%04x,access=%x,attributes=%x,options=%x",
|
||||
call->dup_handle.src_handle, call->dup_handle.dst_process, call->dup_handle.access,
|
||||
call->dup_handle.attributes, call->dup_handle.options );
|
||||
break;
|
||||
case APC_BREAK_PROCESS:
|
||||
fprintf( stderr, "APC_BREAK_PROCESS" );
|
||||
break;
|
||||
|
@ -318,6 +323,10 @@ static void dump_apc_result( const char *prefix, const apc_result_t *result )
|
|||
get_status_name( result->create_thread.status ),
|
||||
result->create_thread.pid, result->create_thread.tid, result->create_thread.handle );
|
||||
break;
|
||||
case APC_DUP_HANDLE:
|
||||
fprintf( stderr, "APC_DUP_HANDLE,status=%s,handle=%04x",
|
||||
get_status_name( result->dup_handle.status ), result->dup_handle.handle );
|
||||
break;
|
||||
case APC_BREAK_PROCESS:
|
||||
fprintf( stderr, "APC_BREAK_PROCESS,status=%s", get_status_name( result->break_process.status ) );
|
||||
break;
|
||||
|
@ -1676,8 +1685,6 @@ static void dump_dup_handle_request( const struct dup_handle_request *req )
|
|||
static void dump_dup_handle_reply( const struct dup_handle_reply *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%04x", req->handle );
|
||||
fprintf( stderr, ", self=%d", req->self );
|
||||
fprintf( stderr, ", closed=%d", req->closed );
|
||||
}
|
||||
|
||||
static void dump_make_temporary_request( const struct make_temporary_request *req )
|
||||
|
|
Loading…
Reference in New Issue