Files
R. Elliott Childre 075323d895 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
2026-06-05 17:35:06 +02:00

58 lines
1.5 KiB
C

/*
* Copyright (C) 2018 Tobias Brunner
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <library.h>
#include <utils/debug.h>
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
{
identification_t *id, *clone;
enumerator_t *part_enum;
chunk_t chunk, data;
id_part_t part;
char str_buf[BUF_LEN], min_buf[3];
dbg_default_set_level(-1);
library_init(NULL, "fuzz_ids");
chunk = chunk_create((u_char*)buf, len);
id = identification_create_from_data(chunk);
if (id)
{
id->hash(id, 0U);
id->equals(id, id);
id->matches(id, id);
id->contains_wildcards(id);
part_enum = id->create_part_enumerator(id);
if (part_enum)
{
while (part_enum->enumerate(part_enum, &part, &data));
part_enum->destroy(part_enum);
}
clone = id->clone(id);
clone->destroy(clone);
}
snprintf(str_buf, sizeof(str_buf), "%Y", id);
snprintf(min_buf, sizeof(min_buf), "%Y", id);
DESTROY_IF(id);
library_deinit();
return 0;
}