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 `<type>:#` 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 418dbd6243
("cloning %any ID without zero-byte memleak") and identities that trigger
this can be created since 86ab5636c2 ("support for @#hex ID_KEY_ID
identification_t"), it was the referenced commit that made the length
check problematic.

Fixes: 2147da40a5 ("simplified identification_t.clone() using memcpy")
Fixes: CVE-2026-47895
This commit is contained in:
R. Elliott Childre
2026-06-05 17:35:06 +02:00
committed by Tobias Brunner
parent 5fc403702b
commit 075323d895
3 changed files with 50 additions and 3 deletions
@@ -1608,6 +1608,29 @@ 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.len && !b_enc.len);
ck_assert(a_enc.ptr != b_enc.ptr || (!a_enc.ptr && !b_enc.ptr));
b->destroy(b);
a->destroy(a);
}
END_TEST
Suite *identification_suite_create()
{
Suite *s;
@@ -1670,6 +1693,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;
+1 -1
View File
@@ -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);
}