Otherwise, NtDeviceIoControlFile fails because of a structure size mismatch. This happens since SCSI_PASS_THROUGH_DIRECT and SCSI_PASS_THROUGH structures contain a pointer-type member, which is 4 bytes in a 32-bit system and 8 bytes in a 64-bit system.
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/wow64/file.c | 92 +++++++++++++++++++++++++++++++++++++++++-- dlls/wow64/struct32.h | 17 ++++++++ 2 files changed, 105 insertions(+), 4 deletions(-)
diff --git a/dlls/wow64/file.c b/dlls/wow64/file.c index d3358000def..67e4a6d67d7 100644 --- a/dlls/wow64/file.c +++ b/dlls/wow64/file.c @@ -19,6 +19,7 @@ */
#include <stdarg.h> +#include <limits.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -27,6 +28,7 @@ #include "winnt.h" #include "winternl.h" #include "winioctl.h" +#include "ntddscsi.h" #include "wow64_private.h" #include "wine/debug.h"
@@ -389,10 +391,92 @@ NTSTATUS WINAPI wow64_NtDeviceIoControlFile( UINT *args ) IO_STATUS_BLOCK io; NTSTATUS status;
- status = NtDeviceIoControlFile( handle, event, apc_32to64( apc ), apc_param_32to64( apc, apc_param ), - iosb_32to64( &io, io32 ), code, in_buf, in_len, out_buf, out_len ); - put_iosb( io32, &io ); - return status; + switch (code) + { + case IOCTL_SCSI_PASS_THROUGH: + { + SCSI_PASS_THROUGH32 *in32 = (SCSI_PASS_THROUGH32 *)in_buf; + SCSI_PASS_THROUGH32 *out32 = (SCSI_PASS_THROUGH32 *)out_buf; + SCSI_PASS_THROUGH *pkt; + size_t size; + + if (in_len < sizeof(*in32)) + return STATUS_INVALID_PARAMETER; + if (in32->Length < sizeof(*in32)) + return STATUS_REVISION_MISMATCH; + if (in32->DataTransferLength > 0) + { + if (in32->DataBufferOffset < sizeof(*in32)) + return STATUS_INVALID_PARAMETER; + if (ULONG_MAX - in32->DataTransferLength < in32->DataBufferOffset) + return STATUS_INVALID_PARAMETER; + if (out_len < in32->DataTransferLength + in32->DataBufferOffset) + return STATUS_INVALID_PARAMETER; + } + if (in32->SenseInfoLength > 0) + { + if (in32->SenseInfoOffset < sizeof(*in32)) + return STATUS_INVALID_PARAMETER; + if (ULONG_MAX - in32->SenseInfoLength < in32->SenseInfoOffset) + return STATUS_INVALID_PARAMETER; + if (out_len < in32->SenseInfoLength + in32->SenseInfoOffset) + return STATUS_INVALID_PARAMETER; + } + if (!in32->DataTransferLength && !in32->SenseInfoLength && out_len < sizeof(*out32)) + return STATUS_INVALID_PARAMETER; + + size = sizeof(*pkt) + in32->SenseInfoLength + in32->DataTransferLength; + pkt = Wow64AllocateTemp( size ); + + pkt->Length = sizeof(*pkt); + pkt->ScsiStatus = in32->ScsiStatus; + pkt->PathId = in32->PathId; + pkt->TargetId = in32->TargetId; + pkt->Lun = in32->Lun; + pkt->CdbLength = in32->CdbLength; + pkt->SenseInfoLength = in32->SenseInfoLength; + pkt->DataIn = in32->DataIn; + pkt->DataTransferLength = in32->DataTransferLength; + pkt->TimeOutValue = in32->TimeOutValue; + pkt->SenseInfoOffset = sizeof(*pkt); + pkt->DataBufferOffset = pkt->SenseInfoOffset + pkt->SenseInfoLength; + memcpy( pkt->Cdb, in32->Cdb, sizeof(pkt->Cdb) ); + + status = NtDeviceIoControlFile( handle, event, apc_32to64( apc ), + apc_param_32to64( apc, apc_param ), + iosb_32to64( &io, io32 ), code, + pkt, size, pkt, size ); + + if (NT_SUCCESS(status)) + { + out32->Length = sizeof(*out32); + out32->ScsiStatus = pkt->ScsiStatus; + out32->PathId = pkt->PathId; + out32->TargetId = pkt->TargetId; + out32->Lun = pkt->Lun; + out32->CdbLength = pkt->CdbLength; + out32->SenseInfoLength = pkt->SenseInfoLength; + out32->DataIn = pkt->DataIn; + out32->DataTransferLength = pkt->DataTransferLength; + out32->TimeOutValue = pkt->TimeOutValue; + out32->SenseInfoOffset = in32->SenseInfoOffset; + out32->DataBufferOffset = in32->DataBufferOffset; + memcpy( out32->Cdb, pkt->Cdb, sizeof(out32->Cdb) ); + memcpy( (char *)out32 + out32->SenseInfoOffset, + (char *)pkt + pkt->SenseInfoOffset, pkt->SenseInfoLength ); + memcpy( (char *)out32 + out32->DataBufferOffset, + (char *)pkt + pkt->DataBufferOffset, pkt->DataTransferLength ); + } + put_iosb( io32, &io ); + return status; + } + default: + status = NtDeviceIoControlFile( handle, event, apc_32to64( apc ), apc_param_32to64( apc, apc_param ), + iosb_32to64( &io, io32 ), code, in_buf, in_len, out_buf, out_len ); + put_iosb( io32, &io ); + return status; + } + }
diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index fe2bbc758ee..261bdc032c5 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -632,6 +632,23 @@ typedef struct PROCESSOR_GROUP_INFO32 GroupInfo[ANYSIZE_ARRAY]; } GROUP_RELATIONSHIP32;
+typedef struct +{ + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH32; + typedef struct { LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
From: Akihiro Sagawa sagawa.aki@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58257 --- dlls/wow64/file.c | 66 +++++++++++++++++++++++++++++++++++++++++++ dlls/wow64/struct32.h | 17 +++++++++++ 2 files changed, 83 insertions(+)
diff --git a/dlls/wow64/file.c b/dlls/wow64/file.c index 67e4a6d67d7..4178cb3cc89 100644 --- a/dlls/wow64/file.c +++ b/dlls/wow64/file.c @@ -470,6 +470,72 @@ NTSTATUS WINAPI wow64_NtDeviceIoControlFile( UINT *args ) put_iosb( io32, &io ); return status; } + case IOCTL_SCSI_PASS_THROUGH_DIRECT: + { + SCSI_PASS_THROUGH_DIRECT32 *in32 = (SCSI_PASS_THROUGH_DIRECT32 *)in_buf; + SCSI_PASS_THROUGH_DIRECT32 *out32 = (SCSI_PASS_THROUGH_DIRECT32 *)out_buf; + SCSI_PASS_THROUGH_DIRECT *pkt; + size_t size; + + if (in_len < sizeof(*in32)) + return STATUS_INVALID_PARAMETER; + if (in32->Length < sizeof(*in32)) + return STATUS_REVISION_MISMATCH; + if (in32->SenseInfoLength > 0) + { + if (in32->SenseInfoOffset < sizeof(*in32)) + return STATUS_INVALID_PARAMETER; + if (ULONG_MAX - in32->SenseInfoLength < in32->SenseInfoOffset) + return STATUS_INVALID_PARAMETER; + if (out_len < in32->SenseInfoLength + in32->SenseInfoOffset) + return STATUS_INVALID_PARAMETER; + } + else if (out_len < sizeof(*out32)) + return STATUS_INVALID_PARAMETER; + + size = sizeof(*pkt) + in32->SenseInfoLength; + pkt = Wow64AllocateTemp( size ); + + pkt->Length = sizeof(*pkt); + pkt->ScsiStatus = in32->ScsiStatus; + pkt->PathId = in32->PathId; + pkt->TargetId = in32->TargetId; + pkt->Lun = in32->Lun; + pkt->CdbLength = in32->CdbLength; + pkt->SenseInfoLength = in32->SenseInfoLength; + pkt->DataIn = in32->DataIn; + pkt->DataTransferLength = in32->DataTransferLength; + pkt->TimeOutValue = in32->TimeOutValue; + pkt->SenseInfoOffset = sizeof(*pkt); + pkt->DataBuffer = ULongToPtr( in32->DataBuffer ); + memcpy( pkt->Cdb, in32->Cdb, sizeof(pkt->Cdb) ); + + status = NtDeviceIoControlFile( handle, event, apc_32to64( apc ), + apc_param_32to64( apc, apc_param ), + iosb_32to64( &io, io32 ), code, + pkt, size, pkt, size ); + + if (NT_SUCCESS(status)) + { + out32->Length = sizeof(*out32); + out32->ScsiStatus = pkt->ScsiStatus; + out32->PathId = pkt->PathId; + out32->TargetId = pkt->TargetId; + out32->Lun = pkt->Lun; + out32->CdbLength = pkt->CdbLength; + out32->SenseInfoLength = pkt->SenseInfoLength; + out32->DataIn = pkt->DataIn; + out32->DataTransferLength = pkt->DataTransferLength; + out32->TimeOutValue = pkt->TimeOutValue; + out32->SenseInfoOffset = in32->SenseInfoOffset; + out32->DataBuffer = PtrToUlong( pkt->DataBuffer ); + memcpy( out32->Cdb, pkt->Cdb, sizeof(out32->Cdb) ); + memcpy( (char *)out32 + out32->SenseInfoOffset, + (char *)pkt + pkt->SenseInfoOffset, pkt->SenseInfoLength ); + } + put_iosb( io32, &io ); + return status; + } default: status = NtDeviceIoControlFile( handle, event, apc_32to64( apc ), apc_param_32to64( apc, apc_param ), iosb_32to64( &io, io32 ), code, in_buf, in_len, out_buf, out_len ); diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index 261bdc032c5..c35c453043d 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -649,6 +649,23 @@ typedef struct UCHAR Cdb[16]; } SCSI_PASS_THROUGH32;
+typedef struct +{ + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT32; + typedef struct { LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
I don't think Windows handles any ioctl conversion in generic code. Rather we should be handling this in the ioctl handler itself. For an ioctl implemented in ntdll we have the in_wow64_call() helper for this; cf. its usage in socket.c.