我有一个程序分配一个缓冲区,其指针通过自定义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