[PATCH v3 3/3] nsiproxy: Wait for all async requests to complete before closing.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Oct 11 10:14:40 CDT 2021


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

IMO it's better to have it for safety. Because this would be hell to debug
if an app does depend on it and then we get corrupted memory (assuming it
releases the buffers after it closes it, for example).

 dlls/iphlpapi/iphlpapi_main.c |  10 +++
 dlls/nsiproxy.sys/device.c    | 131 +++++++++++++++++++++++++++++++++-
 include/wine/nsi.h            |   1 +
 3 files changed, 139 insertions(+), 3 deletions(-)

diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index cfb735c..2730c36 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -4536,7 +4536,17 @@ struct icmp_handle_data
 BOOL WINAPI IcmpCloseHandle( HANDLE handle )
 {
     struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS status;
+    HANDLE event;
 
+    event = CreateEventW( NULL, 0, 0, NULL );
+    status = NtDeviceIoControlFile( data->nsi_device, event, NULL, NULL,
+                                    &iosb, IOCTL_NSIPROXY_WINE_ICMP_CLOSE, NULL, 0,
+                                    NULL, 0 );
+    if (status == STATUS_PENDING)
+        WaitForSingleObject( event, INFINITE );
+    CloseHandle( event );
     CloseHandle( data->nsi_device );
     heap_free( data );
     return TRUE;
diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c
index e310805..93415f5 100644
--- a/dlls/nsiproxy.sys/device.c
+++ b/dlls/nsiproxy.sys/device.c
@@ -52,6 +52,12 @@ DECLARE_CRITICAL_SECTION( nsiproxy_cs );
 #define LIST_ENTRY_INIT( list )  { .Flink = &(list), .Blink = &(list) }
 static LIST_ENTRY request_queue = LIST_ENTRY_INIT( request_queue );
 
+struct irp_file_ctx
+{
+    HANDLE async_event;
+    ULONG_PTR async_count;
+};
+
 static NTSTATUS nsiproxy_call( unsigned int code, void *args )
 {
     return __wine_unix_call( nsiproxy_handle, code, args );
@@ -68,6 +74,18 @@ enum unix_calls
     nsi_get_parameter_ex,
 };
 
+static void complete_async( IRP *irp )
+{
+    struct irp_file_ctx *ctx = IoGetCurrentIrpStackLocation( irp )->FileObject->FsContext;
+
+    if (ctx)
+    {
+        ctx->async_count--;
+        SetEvent( ctx->async_event );
+    }
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+}
+
 static NTSTATUS nsiproxy_enumerate_all( IRP *irp )
 {
     IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
@@ -269,6 +287,7 @@ static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
     struct nsiproxy_icmp_echo *in = (struct nsiproxy_icmp_echo *)irp->AssociatedIrp.SystemBuffer;
     DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
     DWORD out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
+    struct irp_file_ctx *ctx;
 
     TRACE( "\n" );
 
@@ -297,6 +316,10 @@ static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
         return STATUS_CANCELLED;
     }
 
+    ctx = irpsp->FileObject->FsContext;
+    if (ctx)
+        ctx->async_count++;
+
     InsertTailList( &request_queue, &irp->Tail.Overlay.ListEntry );
     IoMarkIrpPending( irp );
 
@@ -306,6 +329,58 @@ static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
     return STATUS_PENDING;
 }
 
+static DWORD WINAPI icmp_close_wait_proc( void *arg )
+{
+    IRP *irp = arg;
+    FILE_OBJECT *obj = IoGetCurrentIrpStackLocation( irp )->FileObject;
+    struct irp_file_ctx *ctx;
+    HANDLE async_event;
+
+    TRACE( "%p\n", obj );
+
+    for (;;)
+    {
+        EnterCriticalSection( &nsiproxy_cs );
+        ctx = obj->FsContext;
+        if (!ctx || !ctx->async_count)
+            break;
+        async_event = ctx->async_event;
+        LeaveCriticalSection( &nsiproxy_cs );
+        WaitForSingleObjectEx( async_event, INFINITE, TRUE );
+    }
+    irp->IoStatus.Status = STATUS_SUCCESS;
+    irp->IoStatus.Information = 0;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+
+    LeaveCriticalSection( &nsiproxy_cs );
+    return 0;
+}
+
+static NTSTATUS nsiproxy_icmp_close( IRP *irp )
+{
+    FILE_OBJECT *obj = IoGetCurrentIrpStackLocation( irp )->FileObject;
+    struct irp_file_ctx *ctx;
+
+    TRACE( "%p\n", obj );
+
+    EnterCriticalSection( &nsiproxy_cs );
+    ctx = obj->FsContext;
+    if (ctx)
+    {
+        /* Native waits until all outstanding async requests are complete or timed out */
+        if (ctx->async_count)
+        {
+            IoMarkIrpPending( irp );
+            LeaveCriticalSection( &nsiproxy_cs );
+            RtlQueueWorkItem( icmp_close_wait_proc, irp, WT_EXECUTELONGFUNCTION );
+            return STATUS_PENDING;
+        }
+    }
+    LeaveCriticalSection( &nsiproxy_cs );
+
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
 {
     IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
@@ -334,6 +409,10 @@ static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
         status = nsiproxy_icmp_echo( irp );
         break;
 
+    case IOCTL_NSIPROXY_WINE_ICMP_CLOSE:
+        status = nsiproxy_icmp_close( irp );
+        break;
+
     default:
         FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
         status = STATUS_NOT_SUPPORTED;
@@ -348,6 +427,50 @@ static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
     return status;
 }
 
+static NTSTATUS WINAPI nsi_create( DEVICE_OBJECT *device, IRP *irp )
+{
+    FILE_OBJECT *obj = IoGetCurrentIrpStackLocation( irp )->FileObject;
+    struct irp_file_ctx *ctx;
+
+    TRACE( "%p\n", obj );
+
+    if (!(ctx = heap_alloc( sizeof(*ctx) )))
+        return STATUS_NO_MEMORY;
+    if (!(ctx->async_event = CreateEventW( NULL, FALSE, FALSE, NULL )))
+    {
+        heap_free( ctx );
+        return STATUS_NO_MEMORY;
+    }
+    ctx->async_count = 0;
+    obj->FsContext = ctx;
+
+    irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS WINAPI nsi_close( DEVICE_OBJECT *device, IRP *irp )
+{
+    FILE_OBJECT *obj = IoGetCurrentIrpStackLocation( irp )->FileObject;
+    struct irp_file_ctx *ctx;
+
+    TRACE( "%p\n", obj );
+
+    EnterCriticalSection( &nsiproxy_cs );
+    ctx = obj->FsContext;
+    if (ctx)
+    {
+        obj->FsContext = NULL;
+        CloseHandle( ctx->async_event );
+        heap_free( ctx );
+    }
+    irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+
+    LeaveCriticalSection( &nsiproxy_cs );
+    return STATUS_SUCCESS;
+}
+
 static int add_device( DRIVER_OBJECT *driver )
 {
     UNICODE_STRING name, link;
@@ -410,7 +533,7 @@ static DWORD WINAPI listen_thread_proc( void *arg )
         irp->IoStatus.Information = reply_len;
     else
         irp->IoStatus.Information = 0;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
+    complete_async( irp );
 
     LeaveCriticalSection( &nsiproxy_cs );
 
@@ -459,7 +582,7 @@ static void handle_queued_send_echo( IRP *irp )
                 }
             }
         }
-        IoCompleteRequest( irp, IO_NO_INCREMENT );
+        complete_async( irp );
     }
     else
     {
@@ -484,7 +607,7 @@ static DWORD WINAPI request_thread_proc( void *arg )
             {
                 irp->IoStatus.Status = STATUS_CANCELLED;
                 TRACE( "already cancelled\n" );
-                IoCompleteRequest( irp, IO_NO_INCREMENT );
+                complete_async( irp );
                 continue;
             }
 
@@ -508,6 +631,8 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
                                    &nsiproxy_handle, sizeof(nsiproxy_handle), NULL );
     if (status) return status;
 
+    driver->MajorFunction[IRP_MJ_CREATE] = nsi_create;
+    driver->MajorFunction[IRP_MJ_CLOSE] = nsi_close;
     driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = nsi_ioctl;
 
     add_device( driver );
diff --git a/include/wine/nsi.h b/include/wine/nsi.h
index 4e60ff6..68b3ed9 100644
--- a/include/wine/nsi.h
+++ b/include/wine/nsi.h
@@ -381,6 +381,7 @@ struct nsi_udp_endpoint_static
 #define IOCTL_NSIPROXY_WINE_GET_ALL_PARAMETERS    CTL_CODE(FILE_DEVICE_NETWORK, 0x401, METHOD_BUFFERED, 0)
 #define IOCTL_NSIPROXY_WINE_GET_PARAMETER         CTL_CODE(FILE_DEVICE_NETWORK, 0x402, METHOD_BUFFERED, 0)
 #define IOCTL_NSIPROXY_WINE_ICMP_ECHO             CTL_CODE(FILE_DEVICE_NETWORK, 0x403, METHOD_BUFFERED, 0)
+#define IOCTL_NSIPROXY_WINE_ICMP_CLOSE            CTL_CODE(FILE_DEVICE_NETWORK, 0x404, METHOD_BUFFERED, 0)
 
 /* input for IOCTL_NSIPROXY_WINE_ENUMERATE_ALL */
 struct nsiproxy_enumerate_all
-- 
2.31.1




More information about the wine-devel mailing list