From ca03401ccf1c22966619d2c54176c78a647f9ce0 Mon Sep 17 00:00:00 2001 From: "R. Elliott Childre" Date: Mon, 18 May 2026 00:53:24 -0400 Subject: [PATCH] identification: Fix double-free when cloning empty IDs The clone() method was missing a branch when there is an encoded chunk of length 0 that still needed to be cloned. Otherwise, the destruction of the clone frees the same pointer that the original owns. This double free was found with an improved `fuzz_ids` fuzz harness and a two byte input to create an identification from "@#" or [0x40, 0x23]. It can also be triggered with `:#` e.g. `dns:#`. One of the problematic constructors is used to parse EAP-Identities, which are cloned before storing them in the auth-cfg. So this can be triggered by an unauthenticated attacker. Note that while the length check was already added with 418dbd624363 ("cloning %any ID without zero-byte memleak") and identities that trigger this can be created since 86ab5636c2c9 ("support for @#hex ID_KEY_ID identification_t"), it was the referenced commit that made the length check problematic. Fixes: 2147da40a5d7 ("simplified identification_t.clone() using memcpy") Fixes: CVE-2026-47895 --- .../tests/suites/test_identification.c | 23 +++++++++++++++++++ src/libstrongswan/utils/identification.c | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c index e7a4d4493e70..bb756399958e 100644 --- a/src/libstrongswan/tests/suites/test_identification.c +++ b/src/libstrongswan/tests/suites/test_identification.c @@ -1608,6 +1608,28 @@ START_TEST(test_clone) } END_TEST +START_TEST(test_clone_empty) +{ + identification_t *a, *b; + chunk_t a_enc, b_enc; + + /* this produces an empty but non-NULL encoding, which previously caused a + * double-free when destroying a clone */ + a = identification_create_from_string("@#"); + ck_assert(a != NULL); + a_enc = a->get_encoding(a); + + b = a->clone(a); + ck_assert(b != NULL); + ck_assert(a != b); + b_enc = b->get_encoding(b); + ck_assert(a_enc.ptr != b_enc.ptr); + + b->destroy(b); + a->destroy(a); +} +END_TEST + Suite *identification_suite_create() { Suite *s; @@ -1670,6 +1692,7 @@ Suite *identification_suite_create() tc = tcase_create("clone"); tcase_add_test(tc, test_clone); + tcase_add_test(tc, test_clone_empty); suite_add_tcase(s, tc); return s; diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 322c2c95ed9a..35837237c6c7 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -1722,7 +1722,7 @@ METHOD(identification_t, clone_, identification_t*, clone->encoded = chunk_from_str(strdup(this->encoded.ptr)); compile_regex(clone); } - else if (this->encoded.len) + else { clone->encoded = chunk_clone(this->encoded); } -- 2.43.0