Added ntoskrnl-safedisc-2 patchset

This commit is contained in:
Alistair Leslie-Hughes 2019-12-17 08:19:06 +11:00
parent d36d63ac84
commit 73caf7ace2
6 changed files with 427 additions and 1 deletions

View File

@ -0,0 +1,119 @@
From b2b7bc84befea8100d1996262ef1b36091df7ebc Mon Sep 17 00:00:00 2001
From: Chip Davis <cdavis@codeweavers.com>
Date: Tue, 18 Jun 2019 00:54:35 -0500
Subject: [PATCH 1/4] ntoskrnl.exe: Return driver dispatch result to caller.
As native does.
Signed-off-by: Chip Davis <cdavis@codeweavers.com>
---
dlls/ntoskrnl.exe/ntoskrnl.c | 31 ++++++++++++-------------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 93c9720e96..9b1efed6de 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -479,9 +479,10 @@ struct dispatch_context
void *in_buff;
};
-static void dispatch_irp( DEVICE_OBJECT *device, IRP *irp, struct dispatch_context *context )
+static NTSTATUS dispatch_irp( DEVICE_OBJECT *device, IRP *irp, struct dispatch_context *context )
{
LARGE_INTEGER count;
+ NTSTATUS status;
IoSetCompletionRoutine( irp, dispatch_irp_completion, context->handle, TRUE, TRUE, TRUE );
context->handle = 0;
@@ -491,9 +492,10 @@ static void dispatch_irp( DEVICE_OBJECT *device, IRP *irp, struct dispatch_conte
context->irp = irp;
device->CurrentIrp = irp;
KeEnterCriticalRegion();
- IoCallDriver( device, irp );
+ status = IoCallDriver( device, irp );
KeLeaveCriticalRegion();
device->CurrentIrp = NULL;
+ return status;
}
/* process a create request for a given file */
@@ -536,9 +538,7 @@ static NTSTATUS dispatch_create( struct dispatch_context *context )
irp->UserEvent = NULL;
irp->Flags |= IRP_CREATE_OPERATION;
- dispatch_irp( device, irp, context );
-
- return STATUS_SUCCESS;
+ return dispatch_irp( device, irp, context );
}
/* process a close request for a given file */
@@ -574,9 +574,7 @@ static NTSTATUS dispatch_close( struct dispatch_context *context )
irp->UserEvent = NULL;
irp->Flags |= IRP_CLOSE_OPERATION;
- dispatch_irp( device, irp, context );
-
- return STATUS_SUCCESS;
+ return dispatch_irp( device, irp, context );
}
/* process a read request for a given device */
@@ -616,9 +614,7 @@ static NTSTATUS dispatch_read( struct dispatch_context *context )
irp->Flags |= IRP_READ_OPERATION;
irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate out_buff */
- dispatch_irp( device, irp, context );
-
- return STATUS_SUCCESS;
+ return dispatch_irp( device, irp, context );
}
/* process a write request for a given device */
@@ -652,9 +648,7 @@ static NTSTATUS dispatch_write( struct dispatch_context *context )
irp->Flags |= IRP_WRITE_OPERATION;
irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate in_buff */
- dispatch_irp( device, irp, context );
-
- return STATUS_SUCCESS;
+ return dispatch_irp( device, irp, context );
}
/* process a flush request for a given device */
@@ -681,9 +675,7 @@ static NTSTATUS dispatch_flush( struct dispatch_context *context )
irpsp = IoGetNextIrpStackLocation( irp );
irpsp->FileObject = file;
- dispatch_irp( device, irp, context );
-
- return STATUS_SUCCESS;
+ return dispatch_irp( device, irp, context );
}
/* process an ioctl request for a given device */
@@ -696,6 +688,7 @@ static NTSTATUS dispatch_ioctl( struct dispatch_context *context )
DEVICE_OBJECT *device;
FILE_OBJECT *file = wine_server_get_ptr( context->params.ioctl.file );
ULONG out_size = context->params.ioctl.out_size;
+ NTSTATUS status;
if (!file) return STATUS_INVALID_HANDLE;
@@ -744,10 +737,10 @@ static NTSTATUS dispatch_ioctl( struct dispatch_context *context )
context->in_buff = NULL;
irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate in_buff */
- dispatch_irp( device, irp, context );
+ status = dispatch_irp( device, irp, context );
HeapFree( GetProcessHeap(), 0, to_free );
- return STATUS_SUCCESS;
+ return status;
}
static NTSTATUS dispatch_free( struct dispatch_context *context )
--
2.17.1

View File

@ -0,0 +1,85 @@
From 3d09e621ab0ed20a4e7fd6f120cd2251d15b5e43 Mon Sep 17 00:00:00 2001
From: Chip Davis <cdavis@codeweavers.com>
Date: Wed, 10 Jul 2019 19:12:06 -0500
Subject: [PATCH 2/4] ntoskrnl.exe: Always copy the buffer for
non-METHOD_BUFFERED ioctls.
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@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 9b1efed6de..368bfcfd20 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.17.1

View File

@ -0,0 +1,139 @@
From 3ad0085d6003a4521dfd7089f34c431f105835df Mon Sep 17 00:00:00 2001
From: Chip Davis <cdavis@codeweavers.com>
Date: Wed, 10 Jul 2019 19:14:45 -0500
Subject: [PATCH 3/4] server: Delay completing a synchronous IRP.
Wait until the client fetches the result. Save any buffer that the
driver provided so it can be copied back to the client.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30155
Signed-off-by: Chip Davis <cdavis@codeweavers.com>
---
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 4 +--
server/device.c | 50 ++++++++++++++++++++----------
2 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 2535ed903e..1765ae7ddf 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -216,8 +216,8 @@ static void test_mismatched_status_ioctl(void)
res = DeviceIoControl(device, IOCTL_WINETEST_MISMATCHED_STATUS, NULL, 0, buf,
sizeof(buf), &written, NULL);
- todo_wine ok(res, "DeviceIoControl failed: %u\n", GetLastError());
- todo_wine ok(!strcmp(buf, teststr), "got '%s'\n", buf);
+ ok(res, "DeviceIoControl failed: %u\n", GetLastError());
+ ok(!strcmp(buf, teststr), "got '%s'\n", buf);
}
static void test_overlapped(void)
diff --git a/server/device.c b/server/device.c
index d3e2a84c1e..99492f8202 100644
--- a/server/device.c
+++ b/server/device.c
@@ -52,6 +52,7 @@ struct irp_call
struct async *async; /* pending async op */
irp_params_t params; /* irp parameters */
struct iosb *iosb; /* I/O status block */
+ int dispatched; /* the call's dispatch returned */
int canceled; /* the call was canceled */
client_ptr_t user_ptr; /* client side pointer */
};
@@ -349,13 +350,14 @@ static struct irp_call *create_irp( struct device_file *file, const irp_params_t
if ((irp = alloc_object( &irp_call_ops )))
{
- irp->file = file ? (struct device_file *)grab_object( file ) : NULL;
- irp->thread = NULL;
- irp->async = NULL;
- irp->params = *params;
- irp->iosb = NULL;
- irp->canceled = 0;
- irp->user_ptr = 0;
+ irp->file = file ? (struct device_file *)grab_object( file ) : NULL;
+ irp->thread = NULL;
+ irp->async = NULL;
+ irp->params = *params;
+ irp->iosb = NULL;
+ irp->dispatched = 0;
+ irp->canceled = 0;
+ irp->user_ptr = 0;
if (async) irp->iosb = async_get_iosb( async );
if (!irp->iosb && !(irp->iosb = create_iosb( NULL, 0, 0 )))
@@ -367,6 +369,19 @@ static struct irp_call *create_irp( struct device_file *file, const irp_params_t
return irp;
}
+static void set_irp_result_buffer( struct irp_call *irp, const void *out_data,
+ data_size_t out_size, data_size_t result )
+{
+ struct iosb *iosb = irp->iosb;
+
+ if (!irp->file) return; /* already finished */
+
+ iosb->result = result;
+ iosb->out_size = min( iosb->out_size, out_size );
+ if (iosb->out_size && !(iosb->out_data = memdup( out_data, iosb->out_size )))
+ iosb->out_size = 0;
+}
+
static void set_irp_result( struct irp_call *irp, unsigned int status,
const void *out_data, data_size_t out_size, data_size_t result )
{
@@ -377,17 +392,15 @@ static void set_irp_result( struct irp_call *irp, unsigned int status,
/* FIXME: handle the STATUS_PENDING case */
iosb->status = status;
- iosb->result = result;
- iosb->out_size = min( iosb->out_size, out_size );
- if (iosb->out_size && !(iosb->out_data = memdup( out_data, iosb->out_size )))
- iosb->out_size = 0;
+ if (!iosb->out_data || irp->dispatched)
+ set_irp_result_buffer( irp, out_data, out_size, result );
/* remove it from the device queue */
list_remove( &irp->dev_entry );
irp->file = NULL;
if (irp->async)
{
- if (result) status = STATUS_ALERTED;
+ if (iosb->out_size || result) status = STATUS_ALERTED;
async_terminate( irp->async, status );
release_object( irp->async );
irp->async = NULL;
@@ -933,13 +946,15 @@ DECL_HANDLER(get_next_device_request)
irp = manager->current_call;
irp->user_ptr = req->user_ptr;
- if (req->status)
- set_irp_result( irp, req->status, NULL, 0, 0 );
+ if (req->status != STATUS_PENDING)
+ set_irp_result( irp, req->status, NULL, 0, irp->iosb->result );
+ else
+ irp->dispatched = 1;
if (irp->canceled)
/* if it was canceled during dispatch, we couldn't queue cancel call without client pointer,
* so we need to do it now */
cancel_irp_call( irp );
- else if (irp->async)
+ else if (irp->async && req->status == STATUS_PENDING)
set_async_pending( irp->async, irp->file && is_fd_overlapped( irp->file->fd ) );
free_irp_params( irp );
@@ -991,7 +1006,10 @@ DECL_HANDLER(set_irp_result)
if ((irp = (struct irp_call *)get_handle_obj( current->process, req->handle, 0, &irp_call_ops )))
{
- if (!irp->canceled)
+ if (!irp->canceled && !irp->dispatched && irp->file && !is_fd_overlapped( irp->file->fd ))
+ /* Don't complete the IRP right away, but save the buffer. */
+ set_irp_result_buffer( irp, get_req_data(), get_req_data_size(), req->size );
+ else if (!irp->canceled)
set_irp_result( irp, req->status, get_req_data(), get_req_data_size(), req->size );
else if(irp->user_ptr) /* cancel already queued */
set_error( STATUS_MORE_PROCESSING_REQUIRED );
--
2.17.1

View File

@ -0,0 +1,56 @@
From d60f2de8b419618674457e5539b081421c110f1e Mon Sep 17 00:00:00 2001
From: Chip Davis <cdavis@codeweavers.com>
Date: Sat, 14 Dec 2019 01:58:26 -0600
Subject: [PATCH 4/4] server: Return the driver's 'Information' from ioctl.
This actually shouldn't matter for driver modules, since those always
call out to another process, but it seems more correct.
Signed-off-by: Chip Davis <cdavis@codeweavers.com>
---
dlls/ntdll/file.c | 2 +-
server/fd.c | 2 +-
server/protocol.def | 1 +
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 26acc066cd..087a92cda2 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1536,7 +1536,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
if (wait_handle && status != STATUS_PENDING)
{
io->u.Status = status;
- io->Information = wine_server_reply_size( reply );
+ io->Information = reply->size;
}
}
SERVER_END_REQ;
diff --git a/server/fd.c b/server/fd.c
index 5d80e218b9..dbfb65abd0 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2579,7 +2579,7 @@ DECL_HANDLER(ioctl)
if ((async = create_request_async( fd, fd->comp_flags, &req->async )))
{
- reply->wait = async_handoff( async, fd->fd_ops->ioctl( fd, req->code, async ), NULL, 0 );
+ reply->wait = async_handoff( async, fd->fd_ops->ioctl( fd, req->code, async ), &reply->size, 0 );
reply->options = fd->options;
release_object( async );
}
diff --git a/server/protocol.def b/server/protocol.def
index 6c44b2b43f..f1f694bf96 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2484,6 +2484,7 @@ enum message_type
@REPLY
obj_handle_t wait; /* handle to wait on for blocking ioctl */
unsigned int options; /* device open options */
+ data_size_t size; /* result size */
VARARG(out_data,bytes); /* ioctl output data */
@END
--
2.17.1

View File

@ -0,0 +1 @@
Fixes: [30155] Improve support for SafeDisc v2.05.030

View File

@ -52,7 +52,7 @@ usage()
# Get the upstream commit sha
upstream_commit()
{
echo "ce7e10868a1279573acc5be5a9659d254e936b27"
echo "6e986bbd810890339569f82aca39273e41427f24"
}
# Show version information
@ -231,6 +231,7 @@ patch_enable_all ()
enable_ntdll_set_full_cpu_context="$1"
enable_ntdll_x86_64_SegDs="$1"
enable_ntoskrnl_Stubs="$1"
enable_ntoskrnl_safedisc_2="$1"
enable_nvapi_Stub_DLL="$1"
enable_nvcuda_CUDA_Support="$1"
enable_nvcuvid_CUDA_Video_Support="$1"
@ -817,6 +818,9 @@ patch_enable ()
ntoskrnl-Stubs)
enable_ntoskrnl_Stubs="$2"
;;
ntoskrnl-safedisc-2)
enable_ntoskrnl_safedisc_2="$2"
;;
nvapi-Stub_DLL)
enable_nvapi_Stub_DLL="$2"
;;
@ -5231,6 +5235,28 @@ if test "$enable_ntoskrnl_Stubs" -eq 1; then
) >> "$patchlist"
fi
# Patchset ntoskrnl-safedisc-2
# |
# | This patchset fixes the following Wine bugs:
# | * [#30155] Improve support for SafeDisc v2.05.030
# |
# | Modified files:
# | * dlls/ntdll/file.c, dlls/ntoskrnl.exe/ntoskrnl.c, dlls/ntoskrnl.exe/tests/ntoskrnl.c, server/device.c, server/fd.c,
# | server/protocol.def
# |
if test "$enable_ntoskrnl_safedisc_2" -eq 1; then
patch_apply ntoskrnl-safedisc-2/0001-ntoskrnl.exe-Return-driver-dispatch-result-to-caller.patch
patch_apply ntoskrnl-safedisc-2/0002-ntoskrnl.exe-Always-copy-the-buffer-for-non-METHOD_B.patch
patch_apply ntoskrnl-safedisc-2/0003-server-Delay-completing-a-synchronous-IRP.patch
patch_apply ntoskrnl-safedisc-2/0004-server-Return-the-driver-s-Information-from-ioctl.patch
(
printf '%s\n' '+ { "Chip Davis", "ntoskrnl.exe: Return driver dispatch result to caller.", 1 },';
printf '%s\n' '+ { "Chip Davis", "ntoskrnl.exe: Always copy the buffer for non-METHOD_BUFFERED ioctls.", 1 },';
printf '%s\n' '+ { "Chip Davis", "server: Delay completing a synchronous IRP.", 1 },';
printf '%s\n' '+ { "Chip Davis", "server: Return the driver'\''s '\''Information'\'' from ioctl.", 1 },';
) >> "$patchlist"
fi
# Patchset nvcuvid-CUDA_Video_Support
# |
# | This patchset has the following (direct or indirect) dependencies: