From 91dea1fc189439a4c2b7b86fc2d62003ba4a42a3 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 22 Oct 2026 13:41:21 -0700 Subject: [PATCH 1/8] F-2846 - https://fenrir.wolfssl.com/finding/2846 - Test that route insert rejects a route with no direction flag --- tests/unittests.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/unittests.c b/tests/unittests.c index 7a75686..5ce2c3f 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -2832,6 +2832,78 @@ static int test_static_routes(void) { WOLFSENTRY_RETURN_OK; } +static int test_route_insert_requires_direction(WOLFSENTRY_CONTEXT_ARGS_IN) { + struct { + struct wolfsentry_sockaddr sa; + byte addr_buf[4]; + } remote, local; + wolfsentry_action_res_t action_results; + wolfsentry_ent_id_t id; + wolfsentry_route_flags_t flags = WOLFSENTRY_ROUTE_FLAG_TCPLIKE_PORT_NUMBERS; + + memset(&remote, 0, sizeof remote); + memset(&local, 0, sizeof local); + remote.sa.sa_family = local.sa.sa_family = AF_INET; + remote.sa.sa_proto = local.sa.sa_proto = IPPROTO_TCP; + remote.sa.sa_port = 4001; + local.sa.sa_port = 4002; + remote.sa.addr_len = local.sa.addr_len = sizeof remote.addr_buf * BITS_PER_BYTE; + memcpy(remote.sa.addr, "\x0a\x0b\x0c\x0d", sizeof remote.addr_buf); + memcpy(local.sa.addr, "\x0a\x0b\x0c\x0e", sizeof local.addr_buf); + + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_insert( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &remote.sa, &local.sa, flags, + NULL /* event_label */, 0 /* event_label_len */, + &id, &action_results)); + + /* the same route is accepted once it has a direction. */ + WOLFSENTRY_SET_BITS(flags, WOLFSENTRY_ROUTE_FLAG_DIRECTION_OUT); + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_insert( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &remote.sa, &local.sa, flags, + NULL /* event_label */, 0 /* event_label_len */, + &id, &action_results)); + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_delete_by_id( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + id, + NULL /* event_label */, 0 /* event_label_len */, + &action_results)); + + return 0; +} + +static int test_static_routes_guards(void) { + struct wolfsentry_context *wolfsentry; + static const struct wolfsentry_eventconfig config = { 0 }; + + WOLFSENTRY_THREAD_HEADER_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE); + + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_init_ex( + wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(WOLFSENTRY_TEST_HPI), + &config, + &wolfsentry, + WOLFSENTRY_INIT_FLAG_NONE)); + + WOLFSENTRY_EXIT_ON_FALSE(test_route_insert_requires_direction(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); + + WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); + + WOLFSENTRY_RETURN_OK; +} + #endif /* TEST_STATIC_ROUTES */ #ifdef TEST_DYNAMIC_RULES @@ -5743,6 +5815,14 @@ int main(int argc, char* argv[]) { } #endif +#ifdef TEST_STATIC_ROUTES + ret = test_static_routes_guards(); + if (! WOLFSENTRY_ERROR_CODE_IS(ret, OK)) { + (void)fprintf(stderr, "test_static_routes_guards failed, " WOLFSENTRY_ERROR_FMT "\n", WOLFSENTRY_ERROR_FMT_ARGS(ret)); + err = 1; + } +#endif + #ifdef TEST_DYNAMIC_RULES ret = test_dynamic_rules(); if (! WOLFSENTRY_ERROR_CODE_IS(ret, OK)) { From 26ec3d50a1f50c9516d6de6d30079b1b943b8499 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 22 Oct 2026 13:41:56 -0700 Subject: [PATCH 2/8] F-2848 - https://fenrir.wolfssl.com/finding/2848 - Test that route insert by exports rejects a route with no direction flag --- tests/unittests.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/unittests.c b/tests/unittests.c index 5ce2c3f..b271f22 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -2881,6 +2881,54 @@ static int test_route_insert_requires_direction(WOLFSENTRY_CONTEXT_ARGS_IN) { return 0; } +static int test_route_insert_by_exports_requires_direction(WOLFSENTRY_CONTEXT_ARGS_IN) { + struct wolfsentry_route_exports exp_route; + byte exp_remote_addr[4]; + wolfsentry_action_res_t action_results; + wolfsentry_ent_id_t id; + + memset(&exp_route, 0, sizeof exp_route); + exp_route.sa_family = AF_INET; + exp_route.sa_proto = IPPROTO_TCP; + exp_route.flags = WOLFSENTRY_ROUTE_FLAG_TCPLIKE_PORT_NUMBERS + | WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_ADDR_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_PORT_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_PORT_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_LOCAL_INTERFACE_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_REMOTE_INTERFACE_WILDCARD; + memcpy(exp_remote_addr, "\x0a\x0b\x0c\x0d", sizeof exp_remote_addr); + exp_route.remote_address = exp_remote_addr; + exp_route.remote.addr_len = sizeof exp_remote_addr * BITS_PER_BYTE; + exp_route.local.addr_len = 0; + + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_insert_by_exports( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &exp_route, + &id, &action_results)); + + /* the same route is accepted once it has a direction. */ + WOLFSENTRY_SET_BITS(exp_route.flags, WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN); + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_insert_by_exports( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &exp_route, + &id, &action_results)); + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_delete_by_id( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + id, + NULL /* event_label */, 0 /* event_label_len */, + &action_results)); + + return 0; +} + static int test_static_routes_guards(void) { struct wolfsentry_context *wolfsentry; static const struct wolfsentry_eventconfig config = { 0 }; @@ -2897,6 +2945,8 @@ static int test_static_routes_guards(void) { WOLFSENTRY_EXIT_ON_FALSE(test_route_insert_requires_direction(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FALSE(test_route_insert_by_exports_requires_direction(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); From 3d47d24e9d39fef604d5744e1a94e9254862abe1 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 22 Oct 2026 13:44:00 -0700 Subject: [PATCH 3/8] F-3440 - https://fenrir.wolfssl.com/finding/3440 - Test that route flag validation rejects inconsistent wildcard combinations --- tests/unittests.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/unittests.c b/tests/unittests.c index b271f22..f921eae 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -2929,6 +2929,86 @@ static int test_route_insert_by_exports_requires_direction(WOLFSENTRY_CONTEXT_AR return 0; } +static int test_route_flags_sensical_validation(WOLFSENTRY_CONTEXT_ARGS_IN) { + struct { + struct wolfsentry_sockaddr sa; + byte addr_buf[4]; + } remote, local; + wolfsentry_action_res_t action_results; + wolfsentry_ent_id_t id; + wolfsentry_route_flags_t proto_flags, all_flags; + unsigned int i; + static const wolfsentry_route_flags_t family_deps[] = { + WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_ADDR_WILDCARD, + WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_ADDR_WILDCARD, + WOLFSENTRY_ROUTE_FLAG_SA_PROTO_WILDCARD + }; + static const wolfsentry_route_flags_t proto_deps[] = { + WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_PORT_WILDCARD, + WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_PORT_WILDCARD + }; + + proto_flags = WOLFSENTRY_ROUTE_FLAG_SA_PROTO_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_PORT_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_PORT_WILDCARD; + all_flags = proto_flags + | WOLFSENTRY_ROUTE_FLAG_SA_FAMILY_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_ADDR_WILDCARD + | WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_ADDR_WILDCARD; + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_check_flags_sensical(WOLFSENTRY_ROUTE_FLAG_NONE)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_check_flags_sensical(proto_flags)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_check_flags_sensical(all_flags)); + + /* a family wildcard needs both address wildcards and the protocol wildcard. */ + for (i = 0; i < sizeof family_deps / sizeof family_deps[0]; ++i) { + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_check_flags_sensical(all_flags & ~family_deps[i])); + } + + /* a protocol wildcard needs both port wildcards. */ + for (i = 0; i < sizeof proto_deps / sizeof proto_deps[0]; ++i) { + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_check_flags_sensical(proto_flags & ~proto_deps[i])); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_check_flags_sensical(all_flags & ~proto_deps[i])); + } + + /* the validation also applies on the insert path. */ + memset(&remote, 0, sizeof remote); + memset(&local, 0, sizeof local); + remote.sa.sa_family = local.sa.sa_family = AF_INET; + remote.sa.sa_proto = local.sa.sa_proto = IPPROTO_TCP; + remote.sa.addr_len = local.sa.addr_len = sizeof remote.addr_buf * BITS_PER_BYTE; + memcpy(remote.sa.addr, "\x0a\x0b\x0c\x0f", sizeof remote.addr_buf); + memcpy(local.sa.addr, "\x0a\x0b\x0c\x10", sizeof local.addr_buf); + + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_insert( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &remote.sa, &local.sa, + WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN | WOLFSENTRY_ROUTE_FLAG_SA_PROTO_WILDCARD | WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_PORT_WILDCARD, + NULL /* event_label */, 0 /* event_label_len */, + &id, &action_results)); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_insert( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &remote.sa, &local.sa, + WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN | WOLFSENTRY_ROUTE_FLAG_SA_FAMILY_WILDCARD | WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_ADDR_WILDCARD | proto_flags, + NULL /* event_label */, 0 /* event_label_len */, + &id, &action_results)); + + return 0; +} + static int test_static_routes_guards(void) { struct wolfsentry_context *wolfsentry; static const struct wolfsentry_eventconfig config = { 0 }; @@ -2947,6 +3027,8 @@ static int test_static_routes_guards(void) { WOLFSENTRY_EXIT_ON_FALSE(test_route_insert_by_exports_requires_direction(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FALSE(test_route_flags_sensical_validation(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); From 6bf4bdb12f061ed45148e544f6566300174e698f Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 22 Oct 2026 13:44:40 -0700 Subject: [PATCH 4/8] F-2842 - https://fenrir.wolfssl.com/finding/2842 - Test that route flag update rejects setting both penaltybox and greenlist --- tests/unittests.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/tests/unittests.c b/tests/unittests.c index f921eae..a9e798b 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -3009,6 +3009,82 @@ static int test_route_flags_sensical_validation(WOLFSENTRY_CONTEXT_ARGS_IN) { return 0; } +static int insert_route_for_update_flags(WOLFSENTRY_CONTEXT_ARGS_IN, struct wolfsentry_route **route_out, wolfsentry_ent_id_t *id_out) { + struct { + struct wolfsentry_sockaddr sa; + byte addr_buf[4]; + } remote, local; + wolfsentry_action_res_t action_results; + wolfsentry_ent_id_t id; + + memset(&remote, 0, sizeof remote); + memset(&local, 0, sizeof local); + remote.sa.sa_family = local.sa.sa_family = AF_INET; + remote.sa.sa_proto = local.sa.sa_proto = IPPROTO_TCP; + remote.sa.sa_port = 4003; + local.sa.sa_port = 4004; + remote.sa.addr_len = local.sa.addr_len = sizeof remote.addr_buf * BITS_PER_BYTE; + memcpy(remote.sa.addr, "\x0a\x0b\x0c\x11", sizeof remote.addr_buf); + memcpy(local.sa.addr, "\x0a\x0b\x0c\x12", sizeof local.addr_buf); + + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_insert( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &remote.sa, &local.sa, + WOLFSENTRY_ROUTE_FLAG_TCPLIKE_PORT_NUMBERS | WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, + NULL /* event_label */, 0 /* event_label_len */, + &id, &action_results)); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_lock_shared(WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_table_ent_get_by_id(WOLFSENTRY_CONTEXT_ARGS_OUT, id, (struct wolfsentry_table_ent_header **)route_out)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_unlock(WOLFSENTRY_CONTEXT_ARGS_OUT)); + *id_out = id; + + return 0; +} + +static int test_route_update_flags_rejects_penaltybox_and_greenlist(WOLFSENTRY_CONTEXT_ARGS_IN) { + struct wolfsentry_route *route; + wolfsentry_ent_id_t id; + wolfsentry_route_flags_t flags_before, flags_after; + wolfsentry_action_res_t action_results; + + WOLFSENTRY_EXIT_ON_FALSE(insert_route_for_update_flags(WOLFSENTRY_CONTEXT_ARGS_OUT, &route, &id) == 0); + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + INVALID_ARG, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_PENALTYBOXED | WOLFSENTRY_ROUTE_FLAG_GREENLISTED, + WOLFSENTRY_ROUTE_FLAG_NONE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_ON_TRUE(WOLFSENTRY_ATOMIC_LOAD(route->flags) & (WOLFSENTRY_ROUTE_FLAG_PENALTYBOXED | WOLFSENTRY_ROUTE_FLAG_GREENLISTED)); + + /* either flag alone is accepted. */ + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_GREENLISTED, + WOLFSENTRY_ROUTE_FLAG_NONE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_ON_FALSE(WOLFSENTRY_ATOMIC_LOAD(route->flags) & WOLFSENTRY_ROUTE_FLAG_GREENLISTED); + + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_delete_by_id( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + id, + NULL /* event_label */, 0 /* event_label_len */, + &action_results)); + + return 0; +} + static int test_static_routes_guards(void) { struct wolfsentry_context *wolfsentry; static const struct wolfsentry_eventconfig config = { 0 }; @@ -3029,6 +3105,8 @@ static int test_static_routes_guards(void) { WOLFSENTRY_EXIT_ON_FALSE(test_route_flags_sensical_validation(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FALSE(test_route_update_flags_rejects_penaltybox_and_greenlist(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); From 2c8a8eef99cbed71605cbb63d877f6ea7cb2da2b Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 22 Oct 2026 13:45:09 -0700 Subject: [PATCH 5/8] F-2844 - https://fenrir.wolfssl.com/finding/2844 - Test that route flag update rejects changes to immutable flags on an inserted route --- tests/unittests.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/unittests.c b/tests/unittests.c index a9e798b..ab085b3 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -3085,6 +3085,64 @@ static int test_route_update_flags_rejects_penaltybox_and_greenlist(WOLFSENTRY_C return 0; } +static int test_route_update_flags_protects_immutable_flags(WOLFSENTRY_CONTEXT_ARGS_IN) { + struct wolfsentry_route *route; + wolfsentry_ent_id_t id; + wolfsentry_route_flags_t flags_before, flags_after, flags_at_entry; + wolfsentry_action_res_t action_results; + + WOLFSENTRY_EXIT_ON_FALSE(insert_route_for_update_flags(WOLFSENTRY_CONTEXT_ARGS_OUT, &route, &id) == 0); + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + flags_at_entry = WOLFSENTRY_ATOMIC_LOAD(route->flags); + WOLFSENTRY_EXIT_ON_FALSE(flags_at_entry & WOLFSENTRY_ROUTE_FLAG_IN_TABLE); + + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + NOT_PERMITTED, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_DIRECTION_OUT, + WOLFSENTRY_ROUTE_FLAG_NONE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + NOT_PERMITTED, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_NONE, + WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + NOT_PERMITTED, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_ADDR_WILDCARD, + WOLFSENTRY_ROUTE_FLAG_NONE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_ON_FALSE(WOLFSENTRY_ATOMIC_LOAD(route->flags) == flags_at_entry); + + /* mutable flags can still be changed. */ + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_GREENLISTED, + WOLFSENTRY_ROUTE_FLAG_NONE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_ON_FALSE(flags_after == (flags_at_entry | WOLFSENTRY_ROUTE_FLAG_GREENLISTED)); + + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_delete_by_id( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + id, + NULL /* event_label */, 0 /* event_label_len */, + &action_results)); + + return 0; +} + static int test_static_routes_guards(void) { struct wolfsentry_context *wolfsentry; static const struct wolfsentry_eventconfig config = { 0 }; @@ -3107,6 +3165,8 @@ static int test_static_routes_guards(void) { WOLFSENTRY_EXIT_ON_FALSE(test_route_update_flags_rejects_penaltybox_and_greenlist(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FALSE(test_route_update_flags_protects_immutable_flags(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); From 41545733017306576ca6b33f55cb2b225048845b Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 22 Oct 2026 13:45:39 -0700 Subject: [PATCH 6/8] F-2847 - https://fenrir.wolfssl.com/finding/2847 - Test that route flag update rejects changes to internal table flags --- tests/unittests.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/unittests.c b/tests/unittests.c index ab085b3..f8614b2 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -3143,6 +3143,63 @@ static int test_route_update_flags_protects_immutable_flags(WOLFSENTRY_CONTEXT_A return 0; } +static int test_route_update_flags_protects_internal_flags(WOLFSENTRY_CONTEXT_ARGS_IN) { + struct wolfsentry_route *route; + wolfsentry_ent_id_t id; + wolfsentry_route_flags_t flags_before, flags_after, flags_at_entry; + wolfsentry_action_res_t action_results; + + WOLFSENTRY_EXIT_ON_FALSE(insert_route_for_update_flags(WOLFSENTRY_CONTEXT_ARGS_OUT, &route, &id) == 0); + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + flags_at_entry = WOLFSENTRY_ATOMIC_LOAD(route->flags); + WOLFSENTRY_EXIT_ON_FALSE(flags_at_entry & WOLFSENTRY_ROUTE_FLAG_IN_TABLE); + WOLFSENTRY_EXIT_ON_TRUE(flags_at_entry & WOLFSENTRY_ROUTE_FLAG_PENDING_DELETE); + + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + NOT_PERMITTED, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_PENDING_DELETE, + WOLFSENTRY_ROUTE_FLAG_NONE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + NOT_PERMITTED, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_IN_TABLE, + WOLFSENTRY_ROUTE_FLAG_NONE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + NOT_PERMITTED, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_NONE, + WOLFSENTRY_ROUTE_FLAG_IN_TABLE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_UNLESS_EXPECTED_FAILURE( + NOT_PERMITTED, + wolfsentry_route_update_flags( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + WOLFSENTRY_ROUTE_FLAG_NONE, + WOLFSENTRY_ROUTE_FLAG_PENDING_DELETE, + &flags_before, &flags_after, &action_results)); + WOLFSENTRY_EXIT_ON_FALSE(WOLFSENTRY_ATOMIC_LOAD(route->flags) == flags_at_entry); + + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_delete_by_id( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + id, + NULL /* event_label */, 0 /* event_label_len */, + &action_results)); + + return 0; +} + static int test_static_routes_guards(void) { struct wolfsentry_context *wolfsentry; static const struct wolfsentry_eventconfig config = { 0 }; @@ -3167,6 +3224,8 @@ static int test_static_routes_guards(void) { WOLFSENTRY_EXIT_ON_FALSE(test_route_update_flags_protects_immutable_flags(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FALSE(test_route_update_flags_protects_internal_flags(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); From 2da7574a1a998a4858e7e43794527eb3d3c60180 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 22 Oct 2026 13:47:26 -0700 Subject: [PATCH 7/8] F-4563 - https://fenrir.wolfssl.com/finding/4563 - Test that lowering the purgeable route limit purges excess stale routes --- tests/unittests.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/unittests.c b/tests/unittests.c index f8614b2..8c7d608 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -3200,6 +3200,73 @@ static int test_route_update_flags_protects_internal_flags(WOLFSENTRY_CONTEXT_AR return 0; } +static int test_route_table_max_purgeable_routes_shrink(WOLFSENTRY_CONTEXT_ARGS_IN) { + struct { + struct wolfsentry_sockaddr sa; + byte addr_buf[4]; + } remote, local; + struct wolfsentry_route_table *main_routes; + struct wolfsentry_route *route; + wolfsentry_action_res_t action_results; + wolfsentry_hitcount_t max_purgeable_routes; + wolfsentry_ent_id_t ids[3]; + unsigned int i; + + memset(&remote, 0, sizeof remote); + memset(&local, 0, sizeof local); + remote.sa.sa_family = local.sa.sa_family = AF_INET; + remote.sa.sa_proto = local.sa.sa_proto = IPPROTO_TCP; + remote.sa.sa_port = 4005; + local.sa.sa_port = 4006; + remote.sa.addr_len = local.sa.addr_len = sizeof remote.addr_buf * BITS_PER_BYTE; + memcpy(local.sa.addr, "\x0a\x0b\x0c\x14", sizeof local.addr_buf); + + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_lock_shared(WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_get_main_table(WOLFSENTRY_CONTEXT_ARGS_OUT, &main_routes)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_unlock(WOLFSENTRY_CONTEXT_ARGS_OUT)); + + /* three routes with no connections, all already due for purging. */ + for (i = 0; i < sizeof ids / sizeof ids[0]; ++i) { + memcpy(remote.sa.addr, "\x0a\x0b\x0c\x00", sizeof remote.addr_buf); + remote.sa.addr[3] = (byte)(0x20 + i); + WOLFSENTRY_EXIT_ON_FAILURE( + wolfsentry_route_insert( + WOLFSENTRY_CONTEXT_ARGS_OUT, + NULL /* caller_arg */, + &remote.sa, &local.sa, + WOLFSENTRY_ROUTE_FLAG_TCPLIKE_PORT_NUMBERS | WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, + NULL /* event_label */, 0 /* event_label_len */, + &ids[i], &action_results)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_lock_mutex(WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_table_ent_get_by_id(WOLFSENTRY_CONTEXT_ARGS_OUT, ids[i], (struct wolfsentry_table_ent_header **)&route)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_purge_time_set(WOLFSENTRY_CONTEXT_ARGS_OUT, route, 1)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_unlock(WOLFSENTRY_CONTEXT_ARGS_OUT)); + } + WOLFSENTRY_EXIT_ON_FALSE(main_routes->purge_list.len == 3); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_lock_mutex(WOLFSENTRY_CONTEXT_ARGS_OUT)); + + /* raising the limit, or lowering it to exactly the current count, purges nothing. */ + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_max_purgeable_routes_set(WOLFSENTRY_CONTEXT_ARGS_OUT, main_routes, 5)); + WOLFSENTRY_EXIT_ON_FALSE(main_routes->purge_list.len == 3); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_max_purgeable_routes_set(WOLFSENTRY_CONTEXT_ARGS_OUT, main_routes, 3)); + WOLFSENTRY_EXIT_ON_FALSE(main_routes->purge_list.len == 3); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_max_purgeable_routes_set(WOLFSENTRY_CONTEXT_ARGS_OUT, main_routes, 10)); + WOLFSENTRY_EXIT_ON_FALSE(main_routes->purge_list.len == 3); + + /* lowering the limit below the current count purges immediately. */ + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_max_purgeable_routes_set(WOLFSENTRY_CONTEXT_ARGS_OUT, main_routes, 2)); + WOLFSENTRY_EXIT_ON_FALSE(main_routes->purge_list.len <= 2); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_max_purgeable_routes_get(WOLFSENTRY_CONTEXT_ARGS_OUT, main_routes, &max_purgeable_routes)); + WOLFSENTRY_EXIT_ON_FALSE(max_purgeable_routes == 2); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_max_purgeable_routes_set(WOLFSENTRY_CONTEXT_ARGS_OUT, main_routes, 0)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_unlock(WOLFSENTRY_CONTEXT_ARGS_OUT)); + + return 0; +} + static int test_static_routes_guards(void) { struct wolfsentry_context *wolfsentry; static const struct wolfsentry_eventconfig config = { 0 }; @@ -3226,6 +3293,8 @@ static int test_static_routes_guards(void) { WOLFSENTRY_EXIT_ON_FALSE(test_route_update_flags_protects_internal_flags(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FALSE(test_route_table_max_purgeable_routes_shrink(WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); From 5f4f23af4d9ef549dd3be6144e36e0ee37191bdb Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 23 Oct 2026 13:46:29 -0700 Subject: [PATCH 8/8] F-4563 - https://fenrir.wolfssl.com/finding/4563 - Set purge limit test addresses through a full-width buffer for C89 builds --- tests/unittests.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unittests.c b/tests/unittests.c index 8c7d608..1294a34 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -3211,6 +3211,7 @@ static int test_route_table_max_purgeable_routes_shrink(WOLFSENTRY_CONTEXT_ARGS_ wolfsentry_hitcount_t max_purgeable_routes; wolfsentry_ent_id_t ids[3]; unsigned int i; + byte addr[4] = { 0x0a, 0x0b, 0x0c, 0x00 }; memset(&remote, 0, sizeof remote); memset(&local, 0, sizeof local); @@ -3228,8 +3229,8 @@ static int test_route_table_max_purgeable_routes_shrink(WOLFSENTRY_CONTEXT_ARGS_ /* three routes with no connections, all already due for purging. */ for (i = 0; i < sizeof ids / sizeof ids[0]; ++i) { - memcpy(remote.sa.addr, "\x0a\x0b\x0c\x00", sizeof remote.addr_buf); - remote.sa.addr[3] = (byte)(0x20 + i); + addr[3] = (byte)(0x20 + i); + memcpy(remote.sa.addr, addr, sizeof addr); WOLFSENTRY_EXIT_ON_FAILURE( wolfsentry_route_insert( WOLFSENTRY_CONTEXT_ARGS_OUT,