[PATCH 3/5] ntdll: Remove the source fd from the cache before calling the dup_handle request.

Zebediah Figura z.figura12 at gmail.com
Mon Mar 22 23:04:28 CDT 2021


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 <z.figura12 at gmail.com>
---
This fixes the race mentioned here:
 <https://www.winehq.org/pipermail/wine-devel/2021-January/179733.html>

 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 )
-- 
2.30.2




More information about the wine-devel mailing list