[2/5] ntoskrnl.exe: Add support for METHOD_IN_DIRECT/METHOD_OUT_DIRECT ioctls.

Sebastian Lackner sebastian at fds-team.de
Sun Oct 16 01:51:06 CDT 2016


Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---

For METHOD_IN_DIRECT and METHOD_OUT_DIRECT the output buffer is not only used
for output, it can also contain input data. This is the case for some HID
ioctls for example. To be compatible with such ioctls, we have to transfer
the output buffer aswell (even if it might contain garbage in some cases).
This patch also improves handling for METHOD_NEITHER, where the handling is
completely up to the driver.

To avoid complexity in the wineserver, this patch transfers (if necessary)
both buffers as a big chunk of data. For processing it is splitted again in
ntoskrnl. Please note that the only ioctl with input buffer directly
implemented in wineserver is FSCTL_PIPE_WAIT, which is METHOD_BUFFERED and
does not have to be modified.

 dlls/ntdll/file.c            |    2 ++
 dlls/ntoskrnl.exe/ntoskrnl.c |   21 +++++++++++++++++----
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 7fbde50..cefc1dd 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1561,6 +1561,8 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
         req->async.event    = wine_server_obj_handle( event );
         req->async.cvalue   = cvalue;
         wine_server_add_data( req, in_buffer, in_size );
+        if ((code & 3) != METHOD_BUFFERED)
+            wine_server_add_data( req, out_buffer, out_size );
         wine_server_set_reply( req, out_buffer, out_size );
         status = wine_server_call( req );
         wait_handle = wine_server_ptr_handle( reply->wait );
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 3c18ee6..912d084 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -428,17 +428,27 @@ static NTSTATUS dispatch_ioctl( const irp_params_t *params, void *in_buff, ULONG
     TRACE( "ioctl %x device %p file %p in_size %u out_size %u\n",
            params->ioctl.code, device, file, in_size, out_size );
 
-    if ((params->ioctl.code & 3) == METHOD_BUFFERED) out_size = max( in_size, out_size );
-
     if (out_size)
     {
-        if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
-        if ((params->ioctl.code & 3) == METHOD_BUFFERED)
+        if ((params->ioctl.code & 3) != METHOD_BUFFERED)
+        {
+            if (in_size < out_size) return STATUS_INVALID_DEVICE_REQUEST;
+            in_size -= out_size;
+            if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
+            memcpy( out_buff, (char *)in_buff + in_size, out_size );
+        }
+        else if (out_size > in_size)
         {
+            if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
             memcpy( out_buff, in_buff, in_size );
             to_free = in_buff;
             in_buff = out_buff;
         }
+        else
+        {
+            out_buff = in_buff;
+            out_size = in_size;
+        }
     }
 
     irp = IoBuildDeviceIoControlRequest( params->ioctl.code, device, in_buff, in_size, out_buff, out_size,
@@ -449,6 +459,9 @@ static NTSTATUS dispatch_ioctl( const irp_params_t *params, void *in_buff, ULONG
         return STATUS_NO_MEMORY;
     }
 
+    if (out_size && (params->ioctl.code & 3) != METHOD_BUFFERED)
+        HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, in_buff, in_size );
+
     irp->Tail.Overlay.OriginalFileObject = file;
     irp->RequestorMode = UserMode;
     irp->AssociatedIrp.SystemBuffer = in_buff;
-- 
2.9.0



More information about the wine-patches mailing list