diff --git a/CHANGELOG b/CHANGELOG index bab7d43..bb7a27a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -312,3 +312,9 @@ WinDivert 2.2.0 - Implement new packet parser that correctly handles IP fragments. - Add a new "fragment" filter field that matches IP fragments. - (Un)Loading the WinDivert driver will cause a system event to be logged. +WinDivert 2.2.1 + - Fix potential driver deadlock on user-mode program crash. + - Fix filter language simplification bug. + - Fix Flow.EndpointId containing junk data. +WinDivert 2.2.2 + - Fix potential WinDivertClose() BSOD for WINDIVERT_LAYER_FLOW handles. diff --git a/README b/README index 5dcbc58..14e9055 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ WinDivert 2.2: Windows Packet Divert --------------- Windows Packet Divert (WinDivert) is a user-mode packet interception library -for Windows 7, Windows 8 and Windows 10. +for Windows 10, Windows 11, and Windows Server. WinDivert enables user-mode capturing/modifying/dropping of network packets sent to/from the Windows network stack. In summary, WinDivert can: diff --git a/VERSION b/VERSION index ccbccc3..b1b25a5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.0 +2.2.2 diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index a725f2e..c69a0fb 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -1,6 +1,6 @@ /* * windivert_helper.c - * (C) 2019, all rights reserved, + * (C) 2021, all rights reserved, * * This file is part of WinDivert. * @@ -1133,7 +1133,10 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error) } return (PEXPR)(vars + mid); } - *error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0); + if (error != NULL) + { + *error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0); + } return NULL; } @@ -1163,6 +1166,15 @@ static PEXPR WinDivertMakeZero(void) return (PEXPR)&zero; } +/* + * Construct one. + */ +static PEXPR WinDivertMakeOne(void) +{ + static const EXPR one = {{{1, 0, 0, 0}}, TOKEN_NUMBER}; + return (PEXPR)&one; +} + /* * Construct a number. */ @@ -1555,16 +1567,17 @@ static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i, INT depth, } /* - * Statically evaluate a test if possible. + * Simplify a test if possible. */ -static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) +static void WinDivertSimplifyTest(PEXPR test) { PEXPR var = test->arg[0]; PEXPR val = test->arg[1]; BOOL neg_lb = FALSE, neg_ub = FALSE, neg; UINT32 lb[4] = {0}, ub[4] = {0}; int result_lb, result_ub; - BOOL eq = FALSE; + BOOL eq = FALSE, result = FALSE; + KIND type = TOKEN_TRUE; switch (var->kind) { @@ -1587,6 +1600,20 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_EVENT: lb[0] = 0; ub[0] = WINDIVERT_EVENT_MAX; break; + case TOKEN_IP_DF: + case TOKEN_IP_MF: + type = TOKEN_IP; + lb[0] = 0; ub[0] = 1; + break; + case TOKEN_TCP_URG: + case TOKEN_TCP_ACK: + case TOKEN_TCP_PSH: + case TOKEN_TCP_RST: + case TOKEN_TCP_SYN: + case TOKEN_TCP_FIN: + type = TOKEN_TCP; + lb[0] = 0; ub[0] = 1; + break; case TOKEN_INBOUND: case TOKEN_OUTBOUND: case TOKEN_FRAGMENT: @@ -1596,37 +1623,52 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_ICMPV6: case TOKEN_TCP: case TOKEN_UDP: - case TOKEN_IP_DF: - case TOKEN_IP_MF: - case TOKEN_TCP_URG: - case TOKEN_TCP_ACK: - case TOKEN_TCP_PSH: - case TOKEN_TCP_RST: - case TOKEN_TCP_SYN: - case TOKEN_TCP_FIN: lb[0] = 0; ub[0] = 1; break; case TOKEN_IP_HDR_LENGTH: + type = TOKEN_IP; + lb[0] = 0; ub[0] = 0x0F; + break; case TOKEN_TCP_HDR_LENGTH: + type = TOKEN_TCP; lb[0] = 0; ub[0] = 0x0F; break; case TOKEN_IP_TTL: case TOKEN_IP_PROTOCOL: + type = TOKEN_IP; + lb[0] = 0; ub[0] = 0xFF; + break; case TOKEN_IPV6_TRAFFIC_CLASS: case TOKEN_IPV6_NEXT_HDR: case TOKEN_IPV6_HOP_LIMIT: + type = TOKEN_IPV6; + lb[0] = 0; ub[0] = 0xFF; + break; case TOKEN_ICMP_TYPE: case TOKEN_ICMP_CODE: + type = TOKEN_ICMP; + lb[0] = 0; ub[0] = 0xFF; + break; case TOKEN_ICMPV6_TYPE: case TOKEN_ICMPV6_CODE: + type = TOKEN_ICMPV6; + lb[0] = 0; ub[0] = 0xFF; + break; + case TOKEN_TCP_PAYLOAD: + type = TOKEN_TCP; + lb[0] = 0; ub[0] = 0xFF; + break; + case TOKEN_UDP_PAYLOAD: + type = TOKEN_UDP; + lb[0] = 0; ub[0] = 0xFF; + break; case TOKEN_PROTOCOL: case TOKEN_PACKET: - case TOKEN_TCP_PAYLOAD: - case TOKEN_UDP_PAYLOAD: case TOKEN_RANDOM8: lb[0] = 0; ub[0] = 0xFF; break; case TOKEN_IP_FRAG_OFF: + type = TOKEN_IP; lb[0] = 0; ub[0] = 0x1FFF; break; case TOKEN_ETH_TYPE: @@ -1634,25 +1676,43 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_IP_LENGTH: case TOKEN_IP_ID: case TOKEN_IP_CHECKSUM: + type = TOKEN_IP; + lb[0] = 0; ub[0] = 0xFFFF; + break; case TOKEN_IPV6_LENGTH: + type = TOKEN_IPV6; + lb[0] = 0; ub[0] = 0xFFFF; + break; case TOKEN_ICMP_CHECKSUM: + type = TOKEN_ICMP; + lb[0] = 0; ub[0] = 0xFFFF; + break; case TOKEN_ICMPV6_CHECKSUM: + type = TOKEN_ICMPV6; + lb[0] = 0; ub[0] = 0xFFFF; + break; case TOKEN_TCP_SRC_PORT: case TOKEN_TCP_DST_PORT: case TOKEN_TCP_WINDOW: case TOKEN_TCP_CHECKSUM: case TOKEN_TCP_URG_PTR: case TOKEN_TCP_PAYLOAD_LENGTH: + case TOKEN_TCP_PAYLOAD16: + type = TOKEN_TCP; + lb[0] = 0; ub[0] = 0xFFFF; + break; case TOKEN_UDP_SRC_PORT: case TOKEN_UDP_DST_PORT: case TOKEN_UDP_LENGTH: case TOKEN_UDP_CHECKSUM: case TOKEN_UDP_PAYLOAD_LENGTH: + case TOKEN_UDP_PAYLOAD16: + type = TOKEN_UDP; + lb[0] = 0; ub[0] = 0xFFFF; + break; case TOKEN_LOCAL_PORT: case TOKEN_REMOTE_PORT: case TOKEN_PACKET16: - case TOKEN_TCP_PAYLOAD16: - case TOKEN_UDP_PAYLOAD16: case TOKEN_RANDOM16: lb[0] = 0; ub[0] = 0xFFFF; break; @@ -1660,10 +1720,12 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) lb[0] = sizeof(WINDIVERT_IPHDR); ub[0] = WINDIVERT_MTU_MAX; break; case TOKEN_IPV6_FLOW_LABEL: + type = TOKEN_IPV6; lb[0] = 0; ub[0] = 0x000FFFFF; break; case TOKEN_IP_SRC_ADDR: case TOKEN_IP_DST_ADDR: + type = TOKEN_IP; lb[0] = 0; lb[1] = 0xFFFF; ub[0] = 0xFFFFFFFF; @@ -1671,6 +1733,8 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) break; case TOKEN_IPV6_SRC_ADDR: case TOKEN_IPV6_DST_ADDR: + type = TOKEN_IPV6; + // Fallthrough case TOKEN_LOCAL_ADDR: case TOKEN_REMOTE_ADDR: lb[0] = lb[1] = lb[2] = lb[3] = 0; @@ -1688,6 +1752,19 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) lb[0] = lb[1] = 0; ub[0] = 0xFFFFFFFF; ub[1] = 0xFFFF; + case TOKEN_TCP_PAYLOAD32: + type = TOKEN_TCP; + lb[0] = 0; ub[0] = 0xFFFFFFFF; + break; + case TOKEN_UDP_PAYLOAD32: + type = TOKEN_UDP; + lb[0] = 0; ub[0] = 0xFFFFFFFF; + break; + case TOKEN_IF_IDX: + case TOKEN_SUB_IF_IDX: + case TOKEN_RANDOM32: + case TOKEN_PROCESS_ID: + lb[0] = 0; ub[0] = 0xFFFFFFFF; break; case TOKEN_ENDPOINT_ID: case TOKEN_PARENT_ENDPOINT_ID: @@ -1695,8 +1772,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) ub[0] = ub[1] = 0xFFFFFFFF; break; default: - lb[0] = 0; ub[0] = 0xFFFFFFFF; - break; + return; } neg = (val->neg? TRUE: FALSE); result_lb = WinDivertCompare128(neg, val->val, neg_lb, lb, /*big=*/TRUE); @@ -1706,78 +1782,81 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_EQ: if (result_lb < 0 || result_ub > 0) { - *res = FALSE; - return TRUE; + result = FALSE; + break; } if (eq && result_lb == 0) { - *res = TRUE; - return TRUE; + result = TRUE; + break; } - return FALSE; + return; case TOKEN_NEQ: if (result_lb < 0 || result_ub > 0) { - *res = TRUE; - return TRUE; + result = TRUE; + break; } if (eq && result_lb == 0) { - *res = FALSE; - return TRUE; + result = FALSE; + break; } - return FALSE; + return; case TOKEN_LT: if (result_ub > 0) { - *res = TRUE; - return TRUE; + result = TRUE; + break; } if (result_lb <= 0) { - *res = FALSE; - return TRUE; + result = FALSE; + break; } - return FALSE; + return; case TOKEN_LEQ: if (result_ub >= 0) { - *res = TRUE; - return TRUE; + result = TRUE; + break; } if (result_lb < 0) { - *res = FALSE; - return TRUE; + result = FALSE; + break; } - return FALSE; + return; case TOKEN_GT: if (result_ub >= 0) { - *res = FALSE; - return TRUE; + result = FALSE; + break; } if (result_lb < 0) { - *res = TRUE; - return TRUE; + result = TRUE; + break; } - return FALSE; + return; case TOKEN_GEQ: if (result_ub > 0) { - *res = FALSE; - return TRUE; + result = FALSE; + break; } if (result_lb <= 0) { - *res = TRUE; - return TRUE; + result = TRUE; + break; } - return FALSE; + return; default: - return FALSE; + return; } + test->arg[0] = WinDivertMakeVar(type, NULL); + test->arg[1] = (result? WinDivertMakeOne(): WinDivertMakeZero()); + test->kind = TOKEN_EQ; } /* @@ -1787,7 +1866,6 @@ static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ, INT16 fail, PEXPR *stack) { INT16 succ1, fail1; - BOOL res; if (succ < 0 || fail < 0) { return -1; @@ -1811,9 +1889,11 @@ static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ, stack); return succ; default: - if (WinDivertEvalTest(expr, &res)) + WinDivertSimplifyTest(expr); + if (expr->kind == TOKEN_EQ && + expr->arg[0]->kind == TOKEN_TRUE) { - return (res? succ: fail); + return (expr->arg[1]->val[0] != 0? succ: fail); } if (*label >= WINDIVERT_FILTER_MAXLEN) { diff --git a/doc/windivert.html b/doc/windivert.html index bc375ab..06ca083 100644 --- a/doc/windivert.html +++ b/doc/windivert.html @@ -75,7 +75,7 @@
WinDivert is a powerful user-mode capture/sniffing/modification/blocking/re-injection package for -Windows 8 and Windows 10, as well as Windows Server 2012/2016/2019. +Windows 10, Windows 11, and Windows Server. WinDivert can be used to implement user-mode packet filters, packet sniffers, firewalls, NAT, VPNs, tunneling applications, etc., without the need to write kernel-mode code. diff --git a/inf/windivert32.inf b/inf/windivert32.inf index 30da774..031e7df 100644 --- a/inf/windivert32.inf +++ b/inf/windivert32.inf @@ -4,7 +4,7 @@ Class = WFPCALLOUTS ClassGuid = {57465043-616C-6C6F-7574-5F636C617373} Provider = %Basil% CatalogFile = WinDivert32.Cat -DriverVer = 08/08/2019,2.2.0 +DriverVer = 01/09/2022,2.2.2 [SourceDisksNames] 1 = %DiskName% diff --git a/inf/windivert64.inf b/inf/windivert64.inf index c5e2cdb..014ef36 100644 --- a/inf/windivert64.inf +++ b/inf/windivert64.inf @@ -4,7 +4,7 @@ Class = WFPCALLOUTS ClassGuid = {57465043-616C-6C6F-7574-5F636C617373} Provider = %Basil% CatalogFile = WinDivert64.Cat -DriverVer = 08/08/2019,2.2.0 +DriverVer = 01/09/2022,2.2.2 [SourceDisksNames] 1 = %DiskName% diff --git a/sys/windivert.c b/sys/windivert.c index 2c323ee..b3acef5 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -1,6 +1,6 @@ /* * windivert.c - * (C) 2019, all rights reserved, + * (C) 2022, all rights reserved, * * This file is part of WinDivert. * @@ -123,7 +123,6 @@ typedef enum WINDIVERT_CONTEXT_STATE_OPEN = 0xB1, // Context is open. WINDIVERT_CONTEXT_STATE_CLOSING = 0xC2, // Context is closing. WINDIVERT_CONTEXT_STATE_CLOSED = 0xD3, // Context is closed. - WINDIVERT_CONTEXT_STATE_INVALID = 0xE4 // Context is invalid. } context_state_t; struct context_s { @@ -275,8 +274,6 @@ struct flow_s UINT64 flow_id; // WFP flow ID. UINT32 callout_id; // WFP callout ID. UINT16 layer_id; // WFP layout ID. - BOOL inserted:1; // Flow inserted into context? - BOOL deleted:1; // Flow deleted from context? BOOL outbound:1; // Flow is outound? BOOL loopback:1; // Flow is loopback? BOOL ipv6:1; // Flow is ipv6? @@ -336,6 +333,7 @@ extern VOID windivert_worker(IN WDFWORKITEM item); static void windivert_read_service(context_t context); extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request, IN WDFFILEOBJECT object); +static NTSTATUS windivert_install_provider(void); static NTSTATUS windivert_install_sublayer(layer_t layer); static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer, UINT64 flags); @@ -515,6 +513,15 @@ extern void windivert_reflect_worker(IN WDFWORKITEM item); static void windivert_log_event(PEPROCESS process, PDRIVER_OBJECT driver, const wchar_t *msg_str); +/* + * WinDivert provider GUIDs + */ +DEFINE_GUID(WINDIVERT_PROVIDER_GUID, + 0x450EC398, 0x1EAF, 0x49F5, + 0x85, 0xE0, 0x22, 0x8F, 0x0D, 0x29, 0x39, 0x21); +#define WINDIVERT_PROVIDER_NAME WINDIVERT_DEVICE_NAME +#define WINDIVERT_PROVIDER_DESC WINDIVERT_DEVICE_NAME L" provider" + /* * WinDivert sublayer GUIDs */ @@ -736,7 +743,7 @@ static const struct layer_s windivert_layer_resource_assignment_ipv4 = &WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID, windivert_resource_assignment_v4_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4 \ (&windivert_layer_resource_assignment_ipv4) @@ -753,7 +760,7 @@ static const struct layer_s windivert_layer_resource_assignment_ipv6 = &WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID, windivert_resource_assignment_v6_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6 \ (&windivert_layer_resource_assignment_ipv6) @@ -770,7 +777,7 @@ static const struct layer_s windivert_layer_resource_release_ipv4 = &WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV4_GUID, windivert_resource_release_v4_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_RESOURCE_RELEASE_IPV4 \ (&windivert_layer_resource_release_ipv4) @@ -787,7 +794,7 @@ static const struct layer_s windivert_layer_resource_release_ipv6 = &WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV6_GUID, windivert_resource_release_v6_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_RESOURCE_RELEASE_IPV6 \ (&windivert_layer_resource_release_ipv6) @@ -804,7 +811,7 @@ static const struct layer_s windivert_layer_auth_connect_ipv4 = &WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID, windivert_auth_connect_v4_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_AUTH_CONNECT_IPV4 \ (&windivert_layer_auth_connect_ipv4) @@ -821,7 +828,7 @@ static const struct layer_s windivert_layer_auth_connect_ipv6 = &WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID, windivert_auth_connect_v6_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_AUTH_CONNECT_IPV6 \ (&windivert_layer_auth_connect_ipv6) @@ -838,7 +845,7 @@ static const struct layer_s windivert_layer_endpoint_closure_ipv4 = &WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV4_GUID, windivert_endpoint_closure_v4_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV4 \ (&windivert_layer_endpoint_closure_ipv4) @@ -855,7 +862,7 @@ static const struct layer_s windivert_layer_endpoint_closure_ipv6 = &WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV6_GUID, windivert_endpoint_closure_v6_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV6 \ (&windivert_layer_endpoint_closure_ipv6) @@ -872,7 +879,7 @@ static const struct layer_s windivert_layer_auth_listen_ipv4 = &WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID, windivert_auth_listen_v4_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_AUTH_LISTEN_IPV4 \ (&windivert_layer_auth_listen_ipv4) @@ -889,7 +896,7 @@ static const struct layer_s windivert_layer_auth_listen_ipv6 = &WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID, windivert_auth_listen_v6_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_AUTH_LISTEN_IPV6 \ (&windivert_layer_auth_listen_ipv6) @@ -906,7 +913,7 @@ static const struct layer_s windivert_layer_auth_recv_accept_ipv4 = &WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID, windivert_auth_recv_accept_v4_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4 \ (&windivert_layer_auth_recv_accept_ipv4) @@ -923,7 +930,7 @@ static const struct layer_s windivert_layer_auth_recv_accept_ipv6 = &WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID, windivert_auth_recv_accept_v6_classify, NULL, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6 \ (&windivert_layer_auth_recv_accept_ipv6) @@ -940,7 +947,7 @@ static const struct layer_s windivert_layer_flow_established_ipv4 = &WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID, windivert_flow_established_v4_classify, windivert_flow_delete_notify, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4 \ (&windivert_layer_flow_established_ipv4) @@ -957,7 +964,7 @@ static const struct layer_s windivert_layer_flow_established_ipv6 = &WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID, windivert_flow_established_v6_classify, windivert_flow_delete_notify, - 0 + UINT16_MAX }; #define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6 \ (&windivert_layer_flow_established_ipv6) @@ -1229,6 +1236,13 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj, FwpmTransactionAbort0(engine_handle); goto driver_entry_exit; } + status = windivert_install_provider(); + if (!NT_SUCCESS(status)) + { + DEBUG_ERROR("failed to install provider", status); + FwpmTransactionAbort0(engine_handle); + goto driver_entry_exit; + } status = windivert_install_sublayer( WINDIVERT_LAYER_INBOUND_MAC_FRAME_ETHERNET); if (!NT_SUCCESS(status)) @@ -1435,6 +1449,7 @@ static void windivert_driver_unload(void) if (!NT_SUCCESS(status)) { DEBUG_ERROR("failed to begin WFP transaction", status); + FwpmTransactionAbort0(engine_handle); FwpmEngineClose0(engine_handle); return; } @@ -1482,6 +1497,10 @@ static void windivert_driver_unload(void) WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4->sublayer_guid); FwpmSubLayerDeleteByKey0(engine_handle, WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6->sublayer_guid); + + FwpmProviderDeleteByKey0(engine_handle, + &WINDIVERT_PROVIDER_GUID); + status = FwpmTransactionCommit0(engine_handle); if (!NT_SUCCESS(status)) { @@ -1492,6 +1511,25 @@ static void windivert_driver_unload(void) } } +/* + * Register provider. + */ +static NTSTATUS windivert_install_provider() +{ + FWPM_PROVIDER0 provider; + NTSTATUS status; + + RtlZeroMemory(&provider, sizeof(provider)); + provider.providerKey = WINDIVERT_PROVIDER_GUID; + provider.displayData.name = WINDIVERT_PROVIDER_NAME; + provider.displayData.description = WINDIVERT_PROVIDER_DESC; + + // We don't care about the install result as this provider + // is only for passing HLK test. + FwpmProviderAdd0(engine_handle, &provider, NULL); + return STATUS_SUCCESS; +} + /* * Register a sub-layer. */ @@ -1627,7 +1665,7 @@ windivert_create_exit: // Clean-up on error: if (!NT_SUCCESS(status)) { - context->state = WINDIVERT_CONTEXT_STATE_INVALID; + context->state = WINDIVERT_CONTEXT_STATE_CLOSED; if (context->read_queue != NULL) { WdfObjectDelete(context->read_queue); @@ -1636,14 +1674,7 @@ windivert_create_exit: { WdfObjectDelete(context->worker); } - if (context->process != NULL) - { - ObDereferenceObject(context->process); - } - if (context->engine_handle != NULL) - { - FwpmEngineClose0(context->engine_handle); - } + // process/engine_handle handled by windivert_destroy() } WdfRequestComplete(request, status); @@ -1973,6 +2004,7 @@ windivert_uninstall_callouts_error: // RPC handle was closed first. So, this path is "normal" if // the user's app crashed or never closed the WinDivert handle. DEBUG_ERROR("failed to begin WFP transaction", status); + FwpmTransactionAbort0(engine); goto windivert_uninstall_callouts_unregister; } for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++) @@ -2017,6 +2049,7 @@ windivert_uninstall_callouts_error: if (!NT_SUCCESS(status)) { DEBUG_ERROR("failed to commit WFP transaction", status); + FwpmTransactionAbort0(engine); // continue } @@ -2079,17 +2112,20 @@ windivert_cleanup_error: context->state = WINDIVERT_CONTEXT_STATE_CLOSING; sniff_mode = ((context->flags & WINDIVERT_FLAG_SNIFF) != 0); forward = (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD); - while (!IsListEmpty(&context->flow_set)) + entry = context->flow_set.Flink; + if (entry != &context->flow_set) { - entry = RemoveHeadList(&context->flow_set); - flow = CONTAINING_RECORD(entry, struct flow_s, entry); - flow->deleted = TRUE; KeReleaseInStackQueuedSpinLock(&lock_handle); - status = FwpsFlowRemoveContext0(flow->flow_id, flow->layer_id, - flow->callout_id); - if (!NT_SUCCESS(status)) + for (; entry != &context->flow_set; entry = entry->Flink) { - windivert_free(flow); + flow = CONTAINING_RECORD(entry, struct flow_s, entry); + status = FwpsFlowRemoveContext0(flow->flow_id, flow->layer_id, + flow->callout_id); + if (!NT_SUCCESS(status) && status != STATUS_UNSUCCESSFUL) + { + // For STATUS_UNSUCCESSFUL, flow_delete() is still called. + WdfObjectDereference((WDFOBJECT)object); + } } KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle); } @@ -2184,6 +2220,8 @@ extern VOID windivert_destroy(IN WDFOBJECT object) KLOCK_QUEUE_HANDLE lock_handle; context_t context = windivert_context_get((WDFFILEOBJECT)object); const WINDIVERT_FILTER *filter; + PLIST_ENTRY entry; + flow_t flow; NTSTATUS status; DEBUG("DESTROY: destroying WinDivert context (context=%p)", context); @@ -2199,9 +2237,21 @@ extern VOID windivert_destroy(IN WDFOBJECT object) filter = context->filter; KeReleaseInStackQueuedSpinLock(&lock_handle); windivert_uninstall_callouts(context, WINDIVERT_CONTEXT_STATE_CLOSED); - FwpmEngineClose0(context->engine_handle); + if (context->engine_handle != NULL) + { + FwpmEngineClose0(context->engine_handle); + } windivert_free((PVOID)filter); - ObDereferenceObject(context->process); + while (!IsListEmpty(&context->flow_set)) + { + entry = RemoveHeadList(&context->flow_set); + flow = CONTAINING_RECORD(entry, struct flow_s, entry); + windivert_free(flow); + } + if (context->process != NULL) + { + ObDereferenceObject(context->process); + } } /* @@ -4355,7 +4405,7 @@ static void windivert_flow_established_v6_classify( UNREFERENCED_PARAMETER(data); UNREFERENCED_PARAMETER(flow_context); - flow_data.ProcessId = (UINT32)meta_vals->processId; + flow_data.EndpointId = meta_vals->transportEndpointHandle; flow_data.ParentEndpointId = meta_vals->parentEndpointHandle; flow_data.ProcessId = (UINT32)meta_vals->processId; windivert_get_ipv6_addr(fixed_vals, @@ -4470,22 +4520,11 @@ static void windivert_flow_established_classify(context_t context, flow->flow_id = flow_id; flow->callout_id = callout_id; flow->layer_id = layer_id; - flow->inserted = FALSE; - flow->deleted = FALSE; flow->outbound = outbound; flow->loopback = loopback; flow->ipv6 = !ipv4; RtlCopyMemory(&flow->data, flow_data, sizeof(flow->data)); - status = FwpsFlowAssociateContext0(flow_id, layer_id, callout_id, - (UINT64)flow); - if (!NT_SUCCESS(status)) - { - windivert_free(flow); - WdfObjectDereference(object); - return; - } - KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle); if (context->state != WINDIVERT_CONTEXT_STATE_OPEN || context->shutdown_recv) @@ -4495,19 +4534,16 @@ static void windivert_flow_established_classify(context_t context, WdfObjectDereference(object); return; } - if (!flow->deleted) + status = FwpsFlowAssociateContext0(flow_id, layer_id, callout_id, + (UINT64)flow); + if (!NT_SUCCESS(status)) { - InsertTailList(&context->flow_set, &flow->entry); - flow->inserted = TRUE; - } - else - { - // Flow was deleted before insertion; we are responsible for cleanup. KeReleaseInStackQueuedSpinLock(&lock_handle); windivert_free(flow); WdfObjectDereference(object); return; } + InsertTailList(&context->flow_set, &flow->entry); KeReleaseInStackQueuedSpinLock(&lock_handle); } @@ -4534,18 +4570,16 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id, { return; } - timestamp = KeQueryPerformanceCounter(NULL).QuadPart; context = flow->context; KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle); object = (WDFOBJECT)context->object; // referenced in flow_established. - if (flow->inserted && !flow->deleted) + cleanup = (context->state == WINDIVERT_CONTEXT_STATE_OPEN); + if (cleanup) { RemoveEntryList(&flow->entry); } - flow->deleted = TRUE; - cleanup = flow->inserted; if (context->state != WINDIVERT_CONTEXT_STATE_OPEN || context->shutdown_recv) { @@ -4570,12 +4604,12 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id, } windivert_flow_delete_notify_exit: - if (cleanup) { + // If context->state != OPEN, then destroy() will free the flow. windivert_free(flow); - WdfObjectDereference(object); } + WdfObjectDereference(object); } /* diff --git a/sys/windivert.rc b/sys/windivert.rc index 11a4e97..775f97b 100644 --- a/sys/windivert.rc +++ b/sys/windivert.rc @@ -1,6 +1,6 @@ /* * windivert.rc - * (C) 2019, all rights reserved, + * (C) 2022, all rights reserved, * * This file is part of WinDivert. * @@ -48,7 +48,7 @@ #define VER_PRODUCTVERSION 2.2 #define VER_PRODUCTVERSION_STR "2.2" #define VER_COMPANYNAME_STR "Basil" -#define VER_LEGALCOPYRIGHT_YEARS "2011-2019" +#define VER_LEGALCOPYRIGHT_YEARS "2011-2022" #define VER_LEGALCOPYRIGHT_STR \ "Copyright \251 " VER_COMPANYNAME_STR " " VER_LEGALCOPYRIGHT_YEARS #define VER_FILEVERSION VER_PRODUCTVERSION diff --git a/test/test.c b/test/test.c index f8aabac..02bbf4a 100644 --- a/test/test.c +++ b/test/test.c @@ -1,6 +1,6 @@ /* * test.c - * (C) 2019, all rights reserved, + * (C) 2021, all rights reserved, * * This file is part of WinDivert. * @@ -632,6 +632,7 @@ static const struct test tests[] = {"localAddr == 10.0.0.1 && remoteAddr == 8.8.4.4 && " "localPort == 57413 && remotePort == 53 && protocol == 17", &pkt_dns_request, TRUE}, + {"ipv6.DstAddr >= ::", &pkt_dns_request, FALSE}, {"ipv6", &pkt_ipv6_tcp_syn, TRUE}, {"ip", &pkt_ipv6_tcp_syn, FALSE}, {"tcp.Syn", &pkt_ipv6_tcp_syn, TRUE}, @@ -815,6 +816,7 @@ static const struct test tests[] = {"ipv6.SrcAddr != abcd::1", &pkt_ipv6_exthdrs_udp, TRUE}, {"ipv6.SrcAddr >= abcd::1", &pkt_ipv6_exthdrs_udp, FALSE}, {"ipv6.SrcAddr > abcd::1", &pkt_ipv6_exthdrs_udp, FALSE}, + {"ipv6.DstAddr >= ::", &pkt_ipv6_exthdrs_udp, TRUE}, {"timestamp > -1", &pkt_ipv6_exthdrs_udp, TRUE}, {"udp.SrcPort == 4660 and udp.DstPort == 43690", &pkt_ipv6_exthdrs_udp, TRUE},