Hello,
When i try to read from two drivers (NDIS IM & TDI) in one Windows (XP)
Service, Windows is crashing (PFN_LIST_CORRUPT (4e)). Why? When I read from
one driver all is working correctly.
Here is part of my code:
1. TDI:
TDI-Based Open Source Personal Firewall for Windows
http://tdifw.sourceforge.net/
2. NDIS IM:
#define malloc_np(size) \
ExAllocatePool( NonPagedPool, size )
#define free_np(ptr) \
ExFreePool(ptr)
struct ndis_item *AddToBuffer(PNDIS_PACKET Packet, const enum Direction
direction)
{
BOOLEAN first = FALSE;
struct ndis_item *item = NULL;
PUCHAR protocolType;
LARGE_INTEGER CurrentSystemTime, CurrentLocalTime;
TIME_FIELDS log_time;
PUCHAR buffer;
buffer = GetBuffer(Packet);
if (!buffer)
{
goto done;
}
NdisAcquireSpinLock( &bufferHelper.guard );
bufferHelper.total++;
if (!bufferHelper.Overflow)
{
item = (struct ndis_item*)malloc_np(sizeof(struct ndis_item));
item->next = NULL;
//get log reqest time
KeQuerySystemTime(&CurrentSystemTime);
ExSystemTimeToLocalTime(&CurrentSystemTime, &CurrentLocalTime);
RtlTimeToTimeFields(&CurrentLocalTime, &log_time);
item->log_time.Hour = (UCHAR)log_time.Hour;
item->log_time.Minute = (UCHAR)log_time.Minute;
item->log_time.Second = (UCHAR)log_time.Second;
item->log_time.Milliseconds = log_time.Milliseconds;
item->packetLength = GetPacketLength(Packet);
item->id = bufferHelper.total - 1;
item->direction = direction;
GetMacAddress(buffer, item->DESTINATION_ADDRESS, Destination);
GetMacAddress(buffer, item->SOURCE_ADDRESS, Source);
item->protocol = (USHORT)(buffer[12] << 8) + buffer[13];
bufferHelper.count++;
first = bufferHelper.head == NULL && bufferHelper.tail == NULL;
if (first)
{
bufferHelper.buffer = bufferHelper.head = bufferHelper.tail = item;
}
else
{
bufferHelper.tail = bufferHelper.buffer->next = item;
bufferHelper.buffer = bufferHelper.buffer->next;
}
}
bufferHelper.Overflow = bufferHelper.count >= bufferHelper.maxLength;
NdisReleaseSpinLock( &bufferHelper.guard );
// signal to user app
if (bufferHelper.event != NULL)
{
KeSetEvent(bufferHelper.event, IO_NO_INCREMENT, FALSE);
}
done:
return item;
}
void RemoveList()
{
struct ndis_item *current = bufferHelper.head;
while (current != NULL)
{
current = RemoveItem(current);
}
bufferHelper.buffer = bufferHelper.head = bufferHelper.tail = NULL;
}
NTSTATUS DevGetBuffer(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
KIRQL irql;
NTSTATUS NtStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION pIrpSp;
PUCHAR ioBuffer = NULL;
ULONG inputBufferLength;
ULONG outputBufferLength, Remaining;
struct ndis_item *cursor;
UINT cursorSize;
ULONG itemsCount;
UNREFERENCED_PARAMETER(pDeviceObject);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
ioBuffer = pIrp->AssociatedIrp.SystemBuffer;
inputBufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
Remaining = outputBufferLength;
// Sanity Check On Length
if( Remaining < sizeof( UNICODE_NULL ) )
{
inputBufferLength = 0;
NtStatus = NDIS_STATUS_BUFFER_OVERFLOW;
goto CompleteTheIRP;
}
NdisAcquireSpinLock( &bufferHelper.guard );
itemsCount = bufferHelper.count;
cursor = bufferHelper.head;
while (cursor != NULL)
{
cursorSize = sizeof(struct ndis_item);
RtlCopyMemory(ioBuffer, cursor, cursorSize);
ioBuffer += cursorSize;
inputBufferLength += cursorSize;
outputBufferLength -= cursorSize;
cursor = cursor->next;
}
RemoveList();
NdisReleaseSpinLock( &bufferHelper.guard );
CompleteTheIRP:
pIrp->IoStatus.Information = inputBufferLength;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return NtStatus;
}
NTSTATUS DevIoControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PIO_STACK_LOCATION pIrpSp;
NTSTATUS NtStatus = STATUS_SUCCESS;
ULONG BytesReturned = 0;
ULONG FunctionCode;
PUCHAR ioBuffer = NULL;
ULONG inputBufferLength;
ULONG outputBufferLength;
UNREFERENCED_PARAMETER(pDeviceObject);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
ioBuffer = pIrp->AssociatedIrp.SystemBuffer;
inputBufferLength =
pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength =
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
FunctionCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
switch (FunctionCode)
{
case IOCTL_PTUSERIO_GET_BUFFER:
return DevGetBuffer(pDeviceObject, pIrp);
default:
NtStatus = STATUS_NOT_SUPPORTED;
break;
}
if (NtStatus != STATUS_PENDING)
{
pIrp->IoStatus.Information = BytesReturned;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
return NtStatus;
}
3. Windows Service:
unsigned __stdcall dispatcher(LPVOID param)
{
HANDLE handles[2];
HANDLE handles2[2];
DWORD i, n, n2;
UCHAR *tmpText = NULL;
int reqSize = 0;
char msg[1024];
struct my_time mt;
mt.Hour = 0;
mt.Minute = 0;
mt.Second = 0;
mt.Milliseconds = 0;
handles[0] = g_event;
handles[1] = g_exit_event;
handles2[0] = g_event2;
handles2[1] = g_exit_event2;
for (;;)
{
if (!DeviceIoControl(g_device, IOCTL_CMD_GETREQUEST, NULL, 0,
g_disp_buf, DISP_BUF_SIZE, &n, NULL))
{
winerr("dispatcher: DeviceIoControl");
break;
}
if (!DeviceIoControl(g_device2, IOCTL_PTUSERIO_GET_BUFFER, NULL, 0,
g_disp_buf2, DISP_BUF_SIZE2, &n2, NULL))
{
winerr("dispatcher: Passthru DeviceIoControl");
break;
}
if (n == 0)
{
DWORD wait;
// if working with log file flush it!
if (g_logfile != NULL)
{
fflush(g_logfile);
}
// wait for data
wait = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (wait == WAIT_OBJECT_0 + 1)
{
break;
}
else
if (wait != WAIT_OBJECT_0)
{
winerr("dispatcher: WaitForSingleObject");
break;
}
continue;
}
if (n2 == 0)
{
DWORD wait;
// wait for data
wait = WaitForMultipleObjects(2, handles2, FALSE, INFINITE);
if (wait == WAIT_OBJECT_0 + 1)
{
break;
}
else
if (wait != WAIT_OBJECT_0)
{
winerr("dispatcher: Passthru WaitForSingleObject");
break;
}
continue;
}
for (i = 0; i < n;)
{
struct request_log *request;
if (n - i < sizeof(*request))
{
break;
}
request = (struct request_log *)(g_disp_buf + i);
dispatch_request(request);
i += request->struct_size;
}
for (i = 0; i < n2;)
{
struct ndis_item *ndis_request;
if (n - i < sizeof(struct ndis_item))
{
break;
}
ndis_request = (struct ndis_item *)(g_disp_buf2 + i);
if (ndis_request == NULL)
{
winerr("dispatcher: unexpected error: ndis_request cannot be a null.");
break;
}
tmpText = (UCHAR*)(g_disp_buf2 + i + sizeof(struct ndis_item));
reqSize = sizeof(struct ndis_item);
(struct ndis_item *)(g_disp_buf2 + i + reqSize);
i += sizeof(struct ndis_item);
Log(ndis_request);
}
}
return 0;
}
-------------------------------------------------------
I am getting the following error:
* Fatal System Error: 0x0000004e
(0x00000007,0x000019B7,0x00000002,0x00000000)
Wed Mar 26 19:59:30.453 2008 (GMT+1): Break instruction exception - code
80000003 (first chance)
A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.
A fatal system error has occurred.
Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
* ERROR: Symbol file could not be found. Defaulted to export symbols for
ntoskrnl.exe -
Loading Kernel Symbols
........................................................................................
Loading User Symbols
Loading unloaded module list
.....
*****************************************************************************
*
*
* Bugcheck Analysis
*
*
*
*****************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck 4E, {7, 19b7, 2, 0}
Probably caused by : ntoskrnl.exe (
nt!KeDeregisterBugCheckReasonCallback+6c7 )
Followup: MachineOwner
---------
nt!DbgBreakPointWithStatus+0x4:
804e3592 cc int 3
kd> !analyze -v
*****************************************************************************
*
*
* Bugcheck Analysis
*
*
*
*****************************************************************************
PFN_LIST_CORRUPT (4e)
Typically caused by drivers passing bad memory descriptor lists (ie: calling
MmUnlockPages twice with the same list, etc). If a kernel debugger is
available get the stack trace.
Arguments:
Arg1: 00000007, A driver has unlocked a page more times than it locked it
Arg2: 000019b7, page frame number
Arg3: 00000002, current share count
Arg4: 00000000, 0
Debugging Details:
------------------
MODULE_NAME: nt
FAULTING_MODULE: 804d7000 nt
DEBUG_FLR_IMAGE_TIMESTAMP: 45e54711
BUGCHECK_STR: 0x4E_7
DEFAULT_BUCKET_ID: WRONG_SYMBOLS
LAST_CONTROL_TRANSFER: from 80532f5e to 804e3592
STACK_TEXT:
WARNING: Stack unwind information not available. Following frames may be
wrong.
f9e732d4 80532f5e 00000003 000019b7 80c55928 nt!DbgBreakPointWithStatus+0x4
f9e736b4 8053354e 0000004e 00000007 000019b7
nt!KeDeregisterBugCheckReasonCallback+0x6c7
f9e736d4 805249de 0000004e 00000007 000019b7 nt!KeBugCheckEx+0x1b
f9e73728 805494b6 817fcf38 81473000 80561b40 nt!IoSetFileOrigin+0xcaa2
f9e73754 8054ad8b 81471000 81473000 81540af8 nt!wcstombs+0x25c6
f9e73794 f98b9de7 81471000 00000000 f9e73990 nt!ExAllocatePoolWithTag+0x247
f9e737a4 f98ba007 817ddcf8 81471000 f98b9fd1 Ntfs+0x1de7
f9e73990 f98b9c24 f9e739a0 81540af8 0110070a Ntfs+0x2007
f9e73b04 804e37f7 81744020 81540af8 81784968 Ntfs+0x1c24
f9e73b24 804e37f7 817978d0 81540af8 00a40000 nt!IofCallDriver+0x32
f9e73b48 804ed2bc 81785809 f9e73b70 f9e73c04 nt!IofCallDriver+0x32
f9e73c24 804ec231 e1334900 e1334908 e1334908
nt!MmMapLockedPagesSpecifyCache+0x7e1
f9e73c60 804ed980 817449d0 e1334900 00000a40 nt!KeQueryTickCount+0x347
f9e73ce8 804ec078 00002000 00000000 00000001 nt!IoSynchronousPageWrite+0x337
f9e73d2c 804e4f1d 817c7298 80561640 817c9020 nt!KeQueryTickCount+0x18e
f9e73d74 804e426b 817c7298 00000000 817c9020 nt!KeReadStateTimer+0x124
f9e73dac 8057d0f1 817c7298 00000000 00000000 nt!ExQueueWorkItem+0x104
f9e73ddc 804f827a 804e4196 00000000 00000000 nt!PsCreateSystemThread+0x70
00000000 00000000 00000000 00000000 00000000 nt!KeInitializeTimer+0x107
STACK_COMMAND: kb
FOLLOWUP_IP:
nt!KeDeregisterBugCheckReasonCallback+6c7
80532f5e e8b7fdfdff call nt!KeI386AllocateGdtSelectors+0x8c
(80512d1a)
SYMBOL_STACK_INDEX: 1
SYMBOL_NAME: nt!KeDeregisterBugCheckReasonCallback+6c7
FOLLOWUP_NAME: MachineOwner
IMAGE_NAME: ntoskrnl.exe
BUCKET_ID: WRONG_SYMBOLS
Followup: MachineOwner
---------
--
Regards
KBJ