привет. при вызове NdisZeroMemory получаю bsod(BAD_POOL_HEADER) Вызов DeviceIoControl из польз. режима Код (Text): //.. typedef __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) QueryBindingCharBuf; QueryBindingCharBuf Buf[1024]; DWORD BufLength = sizeof(Buf); DWORD BytesWritten; PTELINK_QUERY_BINDING pQueryBinding; pQueryBinding = (PTELINK_QUERY_BINDING)Buf; if(DeviceIoControl(hndl, IOCTL_TELINK_QUERY_BINDING, pQueryBinding, sizeof(TELINK_QUERY_BINDING),Buf, BufLength, &BytesWritten, NULL)) { //... } //.. Обработчик IRP_MJ_DEVICE_CONTROL Код (Text): //... case IOCTL_TELINK_QUERY_BINDING: Status = TeLinkQueryBinding((PUCHAR)pIrp->AssociatedIrp.SystemBuffer, pIrpStk->Parameters.DeviceIoControl.InputBufferLength, pIrpStk->Parameters.DeviceIoControl.OutputBufferLength, &Bts); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); break; //.. TeLinkQueryBinding Код (Text): NTSTATUS TeLinkQueryBinding(IN PUCHAR pBuffer, IN ULONG InputLength, IN ULONG OutputLength, OUT PULONG pBytesReturned) { PLIST_ENTRY pEnt; NDIS_STATUS Status; ULONG Remaining; PTELINK_QUERY_BINDING pQueryBinding; ULONG BindingIndex; t_nic* nic; do { if (InputLength < sizeof(TELINK_QUERY_BINDING)) { Status = NDIS_STATUS_RESOURCES; //break; } if (OutputLength < sizeof(TELINK_QUERY_BINDING)) { Status = NDIS_STATUS_BUFFER_OVERFLOW; //break; } Remaining = OutputLength - sizeof(TELINK_QUERY_BINDING); pQueryBinding = (PTELINK_QUERY_BINDING)pBuffer; BindingIndex = pQueryBinding->BindingIndex; Status = NDIS_STATUS_ADAPTER_NOT_FOUND; nic = NULL; NdisAcquireSpinLock(&GLOBAL_DATA.NDIS_LOCK); for (pEnt = GLOBAL_DATA.NICs.Flink; pEnt != &GLOBAL_DATA.NICs; pEnt = pEnt->Flink) { nic = CONTAINING_RECORD(pEnt, t_nic, Link); NdisAcquireSpinLock(&nic->Lock); //NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE)) if(BindingIndex == 0) { pQueryBinding->DeviceNameLength = nic->Name.Length + sizeof(WCHAR); pQueryBinding->DeviceDescrLength = nic->FriendlyName.Length + sizeof(WCHAR); if (Remaining < pQueryBinding->DeviceNameLength + pQueryBinding->DeviceDescrLength) { NdisReleaseSpinLock(&nic->Lock); Status = NDIS_STATUS_BUFFER_OVERFLOW; break; } //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NdisZeroMemory((PUCHAR)pBuffer + sizeof(TELINK_QUERY_BINDING), pQueryBinding->DeviceNameLength + pQueryBinding->DeviceDescrLength); pQueryBinding->DeviceNameOffset = sizeof(TELINK_QUERY_BINDING); NdisMoveMemory((PUCHAR)pBuffer + pQueryBinding->DeviceNameOffset, nic->Name.Buffer, nic->Name.Length); pQueryBinding->DeviceDescrOffset = pQueryBinding->DeviceNameOffset + pQueryBinding->DeviceNameLength; NdisMoveMemory((PUCHAR)pBuffer + pQueryBinding->DeviceDescrOffset, nic->FriendlyName.Buffer, nic->FriendlyName.Length); NdisReleaseSpinLock(&nic->Lock); *pBytesReturned = pQueryBinding->DeviceDescrOffset + pQueryBinding->DeviceDescrLength; */ Status = NDIS_STATUS_SUCCESS; break; } NdisReleaseSpinLock(&nic->Lock); BindingIndex--; } NdisReleaseSpinLock(&GLOBAL_DATA.NDIS_LOCK); } while(FALSE); return (Status); } TELINK_QUERY_BINDING Код (Text): typedef struct _TELINK_QUERY_BINDING { ULONG BindingIndex; ULONG DeviceNameOffset; ULONG DeviceNameLength; ULONG DeviceDescrOffset; ULONG DeviceDescrLength; } TELINK_QUERY_BINDING, *PTELINK_QUERY_BINDING; kd> !analyze -v Код (Text): ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* BAD_POOL_HEADER (19) The pool is already corrupt at the time of the current request. This may or may not be due to the caller. The internal pool links must be walked to figure out a possible cause of the problem, and then special pool applied to the suspect tags or the driver verifier to a suspect driver. Arguments: Arg1: 00000020, a pool block header size is corrupt. Arg2: 8a209a50, The pool entry we were looking for within the page. Arg3: 8a209a70, The next pool entry. Arg4: 1a040001, (reserved) Debugging Details: ------------------ BUGCHECK_STR: 0x19_20 POOL_ADDRESS: 8a209a50 CUSTOMER_CRASH_COUNT: 4 DEFAULT_BUCKET_ID: COMMON_SYSTEM_FAULT PROCESS_NAME: utelink.exe IRP_ADDRESS: 8a20f150 LAST_CONTROL_TRANSFER: from 80874583 to 80822f43 STACK_TEXT: b319aa40 80874583 00000019 00000020 8a209a50 nt!KeBugCheckEx+0x1b b319aa90 8081dc20 8a209a58 00000000 8a20f190 nt!ExFreePoolWithTag+0x2a3 b319aae8 80828853 8a20f190 b319ab34 b319ab28 nt!IopCompleteRequest+0xf4 b319ab38 80a0fef2 00000000 00000000 b319ab50 nt!KiDeliverApc+0xb3 b319ab38 80a0fae4 00000000 00000000 b319ab50 hal!HalpApcInterrupt+0xc6 b319abc0 808254f7 8a20f190 8a20f150 00000000 hal!KeReleaseQueuedSpinLock+0x3c b319abe0 8081a7f6 8a20f190 8a0e7470 00000000 nt!KeInsertQueueApc+0x6d b319ac14 b8488e35 00000005 00000000 0006ff60 nt!IopfCompleteRequest+0x1d8 WARNING: Stack unwind information not available. Following frames may be wrong. b319ac40 8081819f 8a23b780 8a20f150 80a0f410 TeLink+0xe35 b319ac50 808a8982 8a20f1c0 8a0e7470 8a20f150 nt!IopfCallDriver+0x31 b319ac64 808a97f7 8a23b780 8a20f150 8a0e7470 nt!IopSynchronousServiceTail+0x70 b319ad00 808a2274 0000001c 00000000 00000000 nt!IopXxxControlFile+0x5c5 b319ad34 8086a64c 0000001c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a b319ad34 7c90e514 0000001c 00000000 00000000 nt!KiFastCallEntry+0xfc 0006ef28 00000000 00000000 00000000 00000000 0x7c90e514 STACK_COMMAND: kb FOLLOWUP_IP: TeLink+e35 b8488e35 ?? ??? SYMBOL_STACK_INDEX: 8 SYMBOL_NAME: TeLink+e35 FOLLOWUP_NAME: MachineOwner MODULE_NAME: TeLink IMAGE_NAME: TeLink.sys DEBUG_FLR_IMAGE_TIMESTAMP: 4d458dd7 FAILURE_BUCKET_ID: 0x19_20_TeLink+e35 BUCKET_ID: 0x19_20_TeLink+e35 Followup: MachineOwner --------- Оригинал D:\WinDDK\src\network\ndis\ndisprot\5x. Не пойму где я лажаю(
Ошибка в работе с выделенной через ExAllocatePoolWithTag памятью. Переписан заголовок, такое часто бывает при выходе за границу массива.
Не пойму - как это связано. ExAllocatePoolWithTag у меня вызывается один раз, при инициализации протокола. ps: посмотрел в windbg, всё падает на IoCompleteRequest(pIrp, IO_NO_INCREMENT);
Код (Text): Remaining = OutputLength - sizeof(TELINK_QUERY_BINDING); //OutputLength - pIrpStk->Parameters.DeviceIoControl.OutputBufferLength, //....Помещается ли имя адаптера в буфер pQueryBinding->DeviceNameLength = nic->Name.Length + sizeof(WCHAR); pQueryBinding->DeviceDescrLength = nic->FriendlyName.Length + sizeof(WCHAR); if (Remaining < pQueryBinding->DeviceNameLength + pQueryBinding->DeviceDescrLength) { NdisReleaseSpinLock(&nic->Lock); Status = NDIS_STATUS_BUFFER_OVERFLOW; break; } //всё ок, забиваем нулями нужный кусок памяти NdisZeroMemory((PUCHAR)pBuffer + sizeof(TELINK_QUERY_BINDING), pQueryBinding->DeviceNameLength + pQueryBinding->DeviceDescrLength); И всё равно всё слетает. В отладчике при входе в IRP_MJ_DEVICE_CONTROL pBuffer - 0x8211ae50 "" И затем BugCheck 19, {20, 8211ae48, 8211ae68, 1a040001} И в NdisZeroMemory понятно, что затираю заголовок. Но почему pIrp->AssociatedIrp.SystemBuffer указывает на эту область(NonPaged pool table?),а не на выделенный кусок памяти?
Не уловил двух вещей: 1. Как инициализируется pBuffer? 2. Почему pIrp->AssociatedIrp.SystemBuffer должно указывать на некий выделенный кусок памяти? Его выделяет и заполняет I/O Manager же.
1. Код (Text): NTSTATUS TeLinkQueryBinding(IN PUCHAR pBuffer, IN ULONG InputLength, IN ULONG OutputLength, OUT PULONG pBytesReturned) { //... } Вызов: Код (Text): Status = TeLinkQueryBinding((PUCHAR)pIrp->AssociatedIrp.SystemBuffer, pIrpStk->Parameters.DeviceIoControl.InputBufferLength, pIrpStk->Parameters.DeviceIoControl.OutputBufferLength, &Bts); Т.е. pBuffer == (PUCHAR)pIrp->AssociatedIrp.SystemBuffer 2. Я в юзер моде вызываю Код (Text): if(DeviceIoControl(hndl, IOCTL_TELINK_QUERY_BINDING, pQueryBinding, sizeof(TELINK_QUERY_BINDING),Buf, BufLength, &BytesWritten, NULL)) { //... } Т.е. Buf Ну я имел ввиду, что на кусок памяти(выделенный I/O Manager), объёмом указанным в параметре DeviceIoControl зы: Получили BugCheck 19, {20, 8211ae48, 8211ae68, 1a040001} 8211ae68 - 8211ae48 = 00000020 это размер памяти pIrp->AssociatedIrp.SystemBuffer?
Почему pIrp->AssociatedIrp.SystemBuffer должно указывать на некий выделенный кусок памяти? Его выделяет и заполняет I/O Manager же. http://msdn.microsoft.com/en-us/library/ff554436%28v=VS.85%29.aspx
Надо полагать, что вызов должен быть таким: Код (Text): NdisZeroMemory((PUCHAR)pBuffer + sizeof(TELINK_QUERY_BINDING), pQueryBinding->DeviceNameLength + pQueryBinding->DeviceDescrLength - sizeof(TELINK_QUERY_BINDING));
DeviceIoControl(IOCTL_TELINK_QUERY_BINDING) -> I/O Manager -> IRP ----- NTSTATUS TeLinkIoControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) - > (pIrp->AssociatedIrp.SystemBuffer) Если он будет таким, то не влезет имя адаптера. зы вот pIrpStk->Parameters.DeviceIoControl.InputBufferLength //20 байт sizeof(TELINK_QUERY_BINDING) pIrpStk->Parameters.DeviceIoControl.OutputBufferLength //4096 (1024*4)
Я правильно понимаю, что в юзер моде передал указатель на кусок памяти. I/O Manager сделал "нешто" и в обработчике TeLinkIoControl, вынимая pIrp->AssociatedIrp.SystemBuffer, я могу работать как с буфером из юзер мода? И по завершению I/O Manager скопирует данные в буфер юзер мода?
Да, точно, сейчас внимательнее посмотрел. А Remaining объявлена как знаковая переменная? Если беззнаковая и 'Remaining = OutputLength - sizeof(TELINK_QUERY_BINDING);' дает отрицательное значение, то сравнение 'if (Remaining < pQueryBinding->DeviceNameLength + pQueryBinding->DeviceDescrLength)' даст неверный результат.
tapa Да, но при работе с драйвером есть несколько методов в частности DO_BUFFERED_IO, DO_DIRECT_IO, neither как выбрали вы?
pQueryBinding->DeviceNameLength 0х5e pQueryBinding->DeviceDescrLength 0x96 OutputLength 0x1000 sizeof(TELINK_QUERY_BINDING) 0x14 ============================== Remaining =0x1000 - 0x14 = 0xfec Это частный случай, но всё равно ошибка NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) { PDEVICE_OBJECT nt_dev_object; //.... nt_dev_object->Flags |= DO_DIRECT_IO; } В обработчике "IRP_MJ_DEVICE_CONTROL" Код (Text): if (pIrp->Flags&DO_BUFFERED_IO) DbgPrint("DO_BUFFERED_IO"); else if (pIrp->Flags&DO_DIRECT_IO) DbgPrint("DO_DIRECT_IO"); DO_DIRECT_IO. Понимаю, что по логике должно быть MdlAddress. Но в примере DDK Код (Text): NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ){ //.. deviceObject->Flags |= DO_DIRECT_IO; } Код (Text): case IOCTL_NDISPROT_QUERY_BINDING: NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED); Status = ndisprotQueryBinding( pIrp->AssociatedIrp.SystemBuffer, pIrpSp->Parameters.DeviceIoControl.InputBufferLength, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, &BytesReturned ); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); DEBUGP(DL_LOUD, ("IoControl: QueryBinding returning %x\n", NtStatus)); Так что оставил как есть, может я какой-то момент пропустил и поэтому такая фигня?
tapa Да, но для DEVICE_IO_CONTROL (и для INTERNAL_DEVICE_CONTROL) метод передачи задается в самой константе IOCTL_XXX.