From 934484ea3e18f10779dc02afde5a019a5529f5d9 Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Sun, 5 May 2019 07:26:57 +0200 Subject: [PATCH] [NTOS:PNP] When traversing the device tree, keep a reference to the current device. CORE-15874 --- ntoskrnl/io/pnpmgr/pnpmgr.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ntoskrnl/io/pnpmgr/pnpmgr.c b/ntoskrnl/io/pnpmgr/pnpmgr.c index f2048782af0..56b3561fefe 100644 --- a/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -1518,33 +1518,50 @@ IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context) { PDEVICE_NODE ParentDeviceNode; PDEVICE_NODE ChildDeviceNode; + PDEVICE_NODE NextDeviceNode; NTSTATUS Status; /* Copy context data so we don't overwrite it in subsequent calls to this function */ ParentDeviceNode = Context->DeviceNode; + /* HACK: Keep a reference to the PDO so we can keep traversing the tree + * if the device is deleted. In a perfect world, children would have to be + * deleted before their parents, and we'd restart the traversal after + * deleting a device node. */ + ObReferenceObject(ParentDeviceNode->PhysicalDeviceObject); + /* Call the action routine */ Status = (Context->Action)(ParentDeviceNode, Context->Context); if (!NT_SUCCESS(Status)) { + ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject); return Status; } /* Traversal of all children nodes */ for (ChildDeviceNode = ParentDeviceNode->Child; ChildDeviceNode != NULL; - ChildDeviceNode = ChildDeviceNode->Sibling) + ChildDeviceNode = NextDeviceNode) { + /* HACK: We need this reference to ensure we can get Sibling below. */ + ObReferenceObject(ChildDeviceNode->PhysicalDeviceObject); + /* Pass the current device node to the action routine */ Context->DeviceNode = ChildDeviceNode; Status = IopTraverseDeviceTreeNode(Context); if (!NT_SUCCESS(Status)) { + ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject); + ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject); return Status; } + + NextDeviceNode = ChildDeviceNode->Sibling; + ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject); } + ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject); return Status; }