From 64cfcc1c62c2e1ca25ade05973675c64bbc3356e Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 22 Mar 2021 23:04:28 -0500 Subject: [PATCH] ntdll: Remove the source fd from the cache before calling the dup_handle request. If another thread creates and accesses a file between the dup_handle request and the call to remove_fd_from_cache(), the file may be allocated to the same handle number, and that thread will then receive the wrong unix fd. Avoid this race by invalidating the cache first. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/ntdll/unix/server.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 1f8cf546977..506cc99e542 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1693,6 +1693,7 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE ACCESS_MASK access, ULONG attributes, ULONG options ) { NTSTATUS ret; + int fd; if ((options & DUPLICATE_CLOSE_SOURCE) && source_process != NtCurrentProcess()) { @@ -1715,6 +1716,14 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE return result.dup_handle.status; } + /* always remove the cached fd; if the server request fails we'll just + * retrieve it again */ + if (options & DUPLICATE_CLOSE_SOURCE) + { + fd = remove_fd_from_cache( source ); + if (fd != -1) close( fd ); + } + SERVER_START_REQ( dup_handle ) { req->src_process = wine_server_obj_handle( source_process ); @@ -1726,11 +1735,6 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE if (!(ret = wine_server_call( req ))) { if (dest) *dest = wine_server_ptr_handle( reply->handle ); - if (reply->closed && reply->self) - { - int fd = remove_fd_from_cache( source ); - if (fd != -1) close( fd ); - } } } SERVER_END_REQ; @@ -1745,6 +1749,9 @@ NTSTATUS WINAPI NtClose( HANDLE handle ) { HANDLE port; NTSTATUS ret; + + /* always remove the cached fd; if the server request fails we'll just + * retrieve it again */ int fd = remove_fd_from_cache( handle ); SERVER_START_REQ( close_handle )