Zebediah Figura : ntdll: Use a kernel APC to call NtDuplicateObject() if DUPLICATE_CLOSE_SOURCE is used on another process.
Alexandre Julliard
julliard at winehq.org
Tue Mar 23 16:54:31 CDT 2021
Module: wine
Branch: master
Commit: 5df0f5f6fb90e1326b71cd1094a7b710b94916d4
URL: https://source.winehq.org/git/wine.git/?a=commit;h=5df0f5f6fb90e1326b71cd1094a7b710b94916d4
Author: Zebediah Figura <z.figura12 at gmail.com>
Date: Mon Mar 22 23:04:27 2021 -0500
ntdll: Use a kernel APC to call NtDuplicateObject() if DUPLICATE_CLOSE_SOURCE is used on another process.
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/unix/server.c | 36 ++++++++++++++++++++++++++++++++++++
include/wine/server_protocol.h | 22 ++++++++++++++++++----
server/handle.c | 3 +--
server/protocol.def | 18 ++++++++++++++++--
server/request.h | 4 +---
server/thread.c | 15 +++++++++++++++
server/trace.c | 11 +++++++++--
7 files changed, 96 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 4f149c0f644..1f8cf546977 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -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 );
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 238d0d6045d..e948799b05d 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -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 ### */
diff --git a/server/handle.c b/server/handle.c
index 6e0848eedf0..d86f0960ccf 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -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 );
}
}
diff --git a/server/protocol.def b/server/protocol.def
index 2bfdcca6de1..c2792e9551c 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -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
diff --git a/server/request.h b/server/request.h
index 9303496b7fb..a4d003e5c6a 100644
--- a/server/request.h
+++ b/server/request.h
@@ -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 );
diff --git a/server/thread.c b/server/thread.c
index e4abe4fab94..fe9f9bdec37 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -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;
diff --git a/server/trace.c b/server/trace.c
index 5f906a5abfa..c0d2e3dfab7 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -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 )
More information about the wine-cvs
mailing list