[PATCH 2/4] ntoskrnl.exe: Always copy the buffer for non-METHOD_BUFFERED ioctls.
Chip Davis
cdavis at codeweavers.com
Sun Nov 24 19:52:33 CST 2019
In these cases, the driver expects to have direct access to some memory
within the user-mode client, either via an MDL (as in the
METHOD_IN_DIRECT/METHOD_OUT_DIRECT case) or via a raw address (as in the
METHOD_NEITHER case). Because of this, we have to copy the buffer back,
no matter what status is returned.
Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---
dlls/ntoskrnl.exe/ntoskrnl.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 3a3c543be83..4c196bc1c98 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -424,16 +424,48 @@ static void WINAPI cancel_completed_irp( DEVICE_OBJECT *device, IRP *irp )
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
+static ULONG get_irp_out_size( IRP *irp, BOOLEAN *need_copy )
+{
+ IO_STACK_LOCATION *irpsp = IoGetNextIrpStackLocation(irp);
+ switch (irpsp->MajorFunction)
+ {
+ case IRP_MJ_FILE_SYSTEM_CONTROL:
+ case IRP_MJ_DEVICE_CONTROL:
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+ /* For an ioctl not using METHOD_BUFFERED, the driver is supposed to have
+ * direct access to userland's output buffer, either via an MDL (as in METHOD_OUT_DIRECT)
+ * or with the raw user VA (as in METHOD_NEITHER). In these cases, we need
+ * to copy the entire buffer back to the caller, whether or not Information
+ * is non-zero and whether or not the call succeeded. */
+ switch (irpsp->Parameters.DeviceIoControl.IoControlCode & 3)
+ {
+ case METHOD_BUFFERED:
+ break;
+ default:
+ *need_copy = TRUE;
+ return irpsp->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+ break;
+ default:
+ break;
+ }
+ return irp->IoStatus.Information;
+}
+
/* transfer result of IRP back to wineserver */
static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp, void *context )
{
HANDLE irp_handle = context;
void *out_buff = irp->UserBuffer;
NTSTATUS status;
+ ULONG out_size;
+ BOOLEAN need_copy = FALSE;
if (irp->Flags & IRP_WRITE_OPERATION)
out_buff = NULL; /* do not transfer back input buffer */
+ out_size = get_irp_out_size( irp, &need_copy );
+
EnterCriticalSection( &irp_completion_cs );
SERVER_START_REQ( set_irp_result )
@@ -441,9 +473,9 @@ static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp,
req->handle = wine_server_obj_handle( irp_handle );
req->status = irp->IoStatus.u.Status;
req->size = irp->IoStatus.Information;
- if (!NT_ERROR(irp->IoStatus.u.Status))
+ if (!NT_ERROR(irp->IoStatus.u.Status) || need_copy)
{
- if (out_buff) wine_server_add_data( req, out_buff, irp->IoStatus.Information );
+ if (out_buff) wine_server_add_data( req, out_buff, out_size );
}
status = wine_server_call( req );
}
--
2.21.0
More information about the wine-devel
mailing list