In the case of low memory it is possible that an uninitialized variable of type KEVENT will be passed to KeSetEvent.
tdi_fw.c:
...
status = ot_init();
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: ot_init: 0x%x\n", status));
goto done;
}
status = filter_init();
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: filter_init: 0x%x\n", status));
goto done;
}
status = conn_state_init();
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: conn_state_init: 0x%x\n", status));
goto done;
}
...
If either ot_init() or filter_init() return value is other than STATUS_SUCCESS, conn_state_init() (where KeInitializeEvent(&g_conn_new_to_del ...) is located) is not called. In this case, an unloading routine is called
tdi_fw.c:
...
done:
if (status != STATUS_SUCCESS) {
// cleanup
OnUnload(theDriverObject);
}
...
OnUnload(IN PDRIVER_OBJECT DriverObject)
{
...
conn_state_free(); // call after ot_free()
...
conn_state.c:
...
conn_state_free(void)
{
...
KeSetEvent(&g_conn_new_to_del, 0, FALSE);
...
So far, KeSetEvent then triggers a bugcheck:
FAULTING_IP:
nt!KeSetEvent+b0
fffff800`0103abd0 cmp byte ptr [rax+2Ah],1 ; rax = 0
Seems like it's not easy to patch this and similar bugs in tdi_fw, since the whole logic of events initialization is buggy here, as far as I see.
The bug has been found trivially with Driver Verifier. This NPD is hardly exploitable by an unpriviledged user.