Skip to content

Commit e8f570d

Browse files
committed
Avoid double-insert and other corruption in BpfPrograms
The primary cause was the fact that the transition to OpenRunning state involves inserting the OPEN_INSTANCE's BpfProgram into the list without checking for whether it had already been inserted. The BIOCSETF handler was inserting it at OpenAttached, which could lead to double-insertion. This addresses #831. Additional checks for corruption have been added to protect against regressions.
1 parent 12011c1 commit e8f570d

3 files changed

Lines changed: 50 additions & 36 deletions

File tree

packetWin7/npf/npf/Openclos.c

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -562,45 +562,44 @@ _Use_decl_annotations_
562562
VOID
563563
NPF_RegisterBpf(
564564
PNPCAP_FILTER_MODULE pFiltMod,
565-
PNPCAP_BPF_PROGRAM pBpfProgram,
566-
PNPCAP_BPF_PROGRAM pOldBpfProgram)
565+
PNPCAP_BPF_PROGRAM pBpfProgram)
567566
{
568567
// Assert/verify pBpfProgram fields are set
569568
LOCK_STATE_EX lockState;
570569

571570
NT_ASSERT(pBpfProgram->pOpen != NULL);
572-
NT_ASSERT(pBpfProgram->BpfProgramsEntry.Flink == NULL
573-
&& pBpfProgram->BpfProgramsEntry.Blink == NULL);
571+
NT_ASSERT(pBpfProgram->pOpen->pFiltMod == pFiltMod);
574572

575-
// Lock the BpfPrograms list
576-
NdisAcquireRWLockWrite(pFiltMod->BpfProgramsLock, &lockState, 0);
577-
// Insert/update the bpf for this open instance
578-
if (pOldBpfProgram != NULL)
579-
{
580-
// This Open has a program in the list already.
581-
NT_ASSERT(pOldBpfProgram != pBpfProgram);
582-
NT_ASSERT(pBpfProgram->pOpen == pOldBpfProgram->pOpen);
583-
PLIST_ENTRY pOldEntry = &pOldBpfProgram->BpfProgramsEntry;
584-
PLIST_ENTRY pNewEntry = &pBpfProgram->BpfProgramsEntry;
585-
586-
// Link the new program to the rest of the list
587-
pNewEntry->Flink = pOldEntry->Flink;
588-
pNewEntry->Blink = pOldEntry->Blink;
589-
// Link the next and previous entries to the new program
590-
pOldEntry->Flink->Blink = pNewEntry;
591-
pOldEntry->Blink->Flink = pNewEntry;
592-
// Make the old program invalid
593-
// Freeing the program is the caller's responsibility.
594-
pOldEntry->Flink = NULL;
595-
pOldEntry->Blink = NULL;
596-
}
597-
else
573+
PLIST_ENTRY pNewEntry = &pBpfProgram->BpfProgramsEntry;
574+
// If the program is already in the list, nothing more to do
575+
if (pNewEntry->Flink != NULL && NT_VERIFY(pNewEntry->Blink != NULL))
598576
{
599-
InsertTailList(&pFiltMod->BpfPrograms, &pBpfProgram->BpfProgramsEntry);
577+
// In debug mode we can take the time to verify
578+
#if defined(_DBG)
579+
for (PLIST_ENTRY Curr = pFiltMod->BpfPrograms.Flink;
580+
Curr != &pFiltMod->BpfPrograms;
581+
Curr = Curr->Flink)
582+
{
583+
if (Curr == pNewEntry)
584+
{
585+
return;
586+
}
587+
}
588+
NT_ASSERT(FALSE);
589+
#endif
590+
return;
600591
}
592+
593+
NT_ASSERT(pNewEntry->Flink == NULL && pNewEntry->Blink == NULL);
594+
595+
// Lock the BpfPrograms list
596+
NdisAcquireRWLockWrite(pFiltMod->BpfProgramsLock, &lockState, 0);
597+
// Insert the bpf for this open instance
598+
InsertTailList(&pFiltMod->BpfPrograms, pNewEntry);
601599
// Unlock the list
602600
NdisReleaseRWLock(pFiltMod->BpfProgramsLock, &lockState);
603601
}
602+
604603
_Use_decl_annotations_
605604
VOID
606605
NPF_UnregisterBpf(
@@ -617,6 +616,21 @@ NPF_UnregisterBpf(
617616
NT_ASSERT(pBpfProgram->BpfProgramsEntry.Blink != NULL);
618617
// Lock the BpfPrograms list
619618
NdisAcquireRWLockWrite(pFiltMod->BpfProgramsLock, &lockState, 0);
619+
// In debug mode we can take the time to verify
620+
#if defined(_DBG)
621+
BOOLEAN bFound = FALSE;
622+
for (PLIST_ENTRY Curr = pFiltMod->BpfPrograms.Flink;
623+
Curr != &pFiltMod->BpfPrograms;
624+
Curr = Curr->Flink)
625+
{
626+
if (Curr == &pBpfProgram->BpfProgramsEntry)
627+
{
628+
bFound = TRUE;
629+
break;
630+
}
631+
}
632+
NT_ASSERT(bFound);
633+
#endif
620634
// remove the bpf for this open instance
621635
RemoveEntryList(&pBpfProgram->BpfProgramsEntry);
622636
// Unlock the list
@@ -700,7 +714,7 @@ NPF_StartUsingOpenInstance(
700714
NPF_UpdateTimestampModeCounts(pOpen->pFiltMod, pOpen->TimestampMode, TIMESTAMPMODE_UNSET);
701715

702716
// Insert a null filter (accept all)
703-
NPF_RegisterBpf(pOpen->pFiltMod, pOpen->BpfProgram, NULL);
717+
NPF_RegisterBpf(pOpen->pFiltMod, pOpen->BpfProgram);
704718
pOpen->OpenStatus = OpenRunning;
705719
}
706720
else
@@ -2265,7 +2279,7 @@ NPF_AttachAdapter(
22652279
if (pOpen->ReattachStatus < OpenAttached)
22662280
{
22672281
NPF_UpdateTimestampModeCounts(pFiltMod, pOpen->TimestampMode, TIMESTAMPMODE_UNSET);
2268-
NPF_RegisterBpf(pOpen->pFiltMod, pOpen->BpfProgram, NULL);
2282+
NPF_RegisterBpf(pOpen->pFiltMod, pOpen->BpfProgram);
22692283
}
22702284
pOpen->OpenStatus = pOpen->ReattachStatus;
22712285
Curr = PopEntryList(&ReattachOpens);

packetWin7/npf/npf/Packet.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,11 +1187,12 @@ static NTSTATUS funcBIOCSETF(_In_ POPEN_INSTANCE pOpen,
11871187
TmpBPFProgram->pOpen = pOpen;
11881188

11891189
PVOID pOld = InterlockedExchangePointer(&pOpen->BpfProgram, TmpBPFProgram);
1190+
NPF_UnregisterBpf(pOpen->pFiltMod, pOld);
11901191

1191-
// Register the new BPF program if the Open is Attached
1192-
if (NPF_StartUsingOpenInstance(pOpen, OpenAttached, NPF_IRQL_UNKNOWN)) {
1193-
NPF_RegisterBpf(pOpen->pFiltMod, TmpBPFProgram, pOld);
1194-
NPF_StopUsingOpenInstance(pOpen, OpenAttached, NPF_IRQL_UNKNOWN);
1192+
// Register the new BPF program if the Open is Running
1193+
if (NPF_StartUsingOpenInstance(pOpen, OpenRunning, NPF_IRQL_UNKNOWN)) {
1194+
NPF_RegisterBpf(pOpen->pFiltMod, TmpBPFProgram);
1195+
NPF_StopUsingOpenInstance(pOpen, OpenRunning, NPF_IRQL_UNKNOWN);
11951196
}
11961197
else {
11971198
// After InterlockedExchangePointer above, the memory at TmpBPFProgram

packetWin7/npf/npf/Packet.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,7 @@ NPCAP_BPF_PROGRAM, *PNPCAP_BPF_PROGRAM;
398398
VOID
399399
NPF_RegisterBpf(
400400
_In_ PNPCAP_FILTER_MODULE pFiltMod,
401-
_In_ __drv_aliasesMem PNPCAP_BPF_PROGRAM pBpfProgram,
402-
_In_opt_ PNPCAP_BPF_PROGRAM pOldBpfProgram);
401+
_In_ __drv_aliasesMem PNPCAP_BPF_PROGRAM pBpfProgram);
403402
VOID
404403
NPF_UnregisterBpf(
405404
_In_ PNPCAP_FILTER_MODULE pFiltMod,

0 commit comments

Comments
 (0)