我有一個程序分配一個緩衝區,其指針通過自定義IOCTL傳遞給內核驅動程序。在驅動程序中,我獲得一個Mdl並用「MmGetSystemAddressForMdlSafe」鎖定用戶程序緩衝區的頁面,然後使用Mdl填充用戶程序緩衝區。爲什麼在用戶程序中動態分配緩衝區會導致內核驅動程序崩潰?
如果在用戶程序中緩衝區是普通數組,那麼驅動程序總是按照它應該的那樣工作。 (WORD緩衝器[256],其中,字是一個無符號短)
如果用戶程序緩衝液代替使用新關鍵字(WORD *buffer = new WORD[256])
或malloc的關鍵字(WORD *buffer=(WORD*) malloc(sizeof(*buffer)*256)))
不時我得到一個BSOD分配和錯誤是「非分頁區域中的頁面錯誤「。
爲什麼?
謝謝!
EDIT(額外的細節):
在驅動程序我使用MmGetSystemAddressForMdlSafe
這種方式:
PVOID p_buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
的Irp是我接收作爲第二個參數,當我處理IRP_MJ_DEVICE_CONTROL
的MajorFunction一個PIRP。
後,我檢查了p_buffer
不爲空,我用指針來寫用戶緩衝區:
READ_PORT_BUFFER_USHORT((PUSHORT)(USHORT)current_port.address, (PUSHORT)p_buffer, 256)
IOCTL定義:
,處理IRP_MJ_DEVICE_CONTROL
#define IOCTL_TEST_READPORT CTL_CODE(FILE_DEVICE_TEST, \
TEST_IOCTL_INDEX + 0, \
METHOD_OUT_DIRECT, \
FILE_ANY_ACCESS)
驅動程序功能:
NTSTATUS TESTDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
ULONG input_buffer_size;
ULONG output_buffer_size;
ULONG control_code;
PVOID p_buffer;
NTSTATUS nt_status;
struct port current_port;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
switch (IrpStack->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
control_code = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (control_code)
{
case IOCTL_TEST_READPORT:
p_buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
input_buffer_size = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
if (!p_buffer)
{
nt_status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
if (input_buffer_size)
{
memcpy (¤t_port, Irp->AssociatedIrp.SystemBuffer, input_buffer_size);
switch (current_port.size)
{
case 1:
current_port.value = (ULONG)READ_PORT_UCHAR((PUCHAR)(USHORT)current_port.address);
memcpy (p_buffer, ¤t_port.value, sizeof(current_port.value));
Irp->IoStatus.Information = sizeof(current_port.value);
break;
case 0xF0:
READ_PORT_BUFFER_USHORT((PUSHORT)(USHORT)current_port.address, (PUSHORT)p_buffer, 256);
Irp->IoStatus.Information = sizeof(current_port.value);
break;
case 2:
current_port.value = (ULONG)READ_PORT_USHORT((PUSHORT)(USHORT)current_port.address);
memcpy (p_buffer, ¤t_port.value, sizeof(current_port.value));
Irp->IoStatus.Information = sizeof(current_port.value);
break;
}
}
else
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
case IRP_MJ_CREATE:
KdPrint(("IRP_MJ_CREATE"));
break;
case IRP_MJ_CLOSE:
KdPrint(("IRP_MJ_CLOSE"));
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
break;
}
nt_status = Irp->IoStatus.Status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return nt_status;
}
相關案例是case 0xF0:
裏面case IOCTL_TEST_READPORT:
你能告訴我們你的IOCTL和鎖定頁面的代碼嗎?你可能會計算出一些錯誤的尺寸。什麼是導致BSOD和鎖定的緩衝區的起始地址的內存地址?這是爲了查看第一個元素是否導致藍屏死機或中間的某處,並查看它是否在某個邊界 – Codeguard 2013-02-14 09:11:42
在任何情況下(如果這是您的驅動程序),驅動程序應驗證從用戶程序傳遞的地址和緩衝區不觸發頁面錯誤。 – sstn 2013-02-14 09:18:16
不好意思,但是你發佈的代碼並沒有顯示你在哪裏使用過你剛纔提到的'malloc'緩衝區。它只顯示你正在獲得一個MDL的虛擬地址,所以你可以將該指針傳遞給'READ_PORT_BUFFER_USHORT'。這看起來是正確的,AFAIK。 – 2013-02-14 11:22:34