Files
coturn/fuzzing/FuzzOpenSSLInit.c
Pavel Punsky 8952415609 Seed address-mapping table in fuzz initializer (#1885)
map_addr_from_public_to_private and map_addr_from_private_to_public in
src/client/ns_turn_ioaddr.c walk a static public_addrs[] table of size
mcount. Without an explicit ioa_addr_add_mapping call mcount stays 0 for
the entire fuzz process, so the loop body — including the
addr_eq_no_port call it gates — is dead code in every fuzz iteration.
OSS-Fuzz introspector flags this as 19 unreached callsites under
map_addr_from_public_to_private and 4+4 under addr_eq_no_port.

Extend the existing shared LLVMFuzzerInitialize in FuzzOpenSSLInit.c
(linked into both FuzzStun and FuzzStunClient via FUZZ_COMMON_SOURCES)
to register two synthetic public<->private mapping pairs — one v4
(192.0.2.1 <-> 10.0.0.1) and one v6 (2001:db8::1 <-> fd00::1) — once at
startup. The header comment for ioa_addr_add_mapping requires
single-threaded init before fuzzing begins, which matches exactly when
LLVMFuzzerInitialize runs.

Verified by stand-alone harness: after init,
stun_attr_get_first_addr_str on a XOR-MAPPED-ADDRESS attribute holding
192.0.2.1:443 returns 10.0.0.1:443, and the v6 equivalent returns
[fd00::1]:8080 — confirming addr_eq_no_port is now called inside the
loop body in both helpers.
2026-04-27 21:29:23 -07:00

62 lines
1.9 KiB
C

/*
* SPDX-License-Identifier: BSD-3-Clause
*
* https://opensource.org/license/bsd-3-clause
*
* Shared one-shot init for libFuzzer targets. Linked into every fuzzer
* via FUZZ_COMMON_SOURCES so a single LLVMFuzzerInitialize covers all
* binaries.
*
* Responsibilities:
* 1. Deterministic OpenSSL setup (skips environment-dependent config
* loading that trips MSan in unsanitized libcrypto).
* 2. Seed the public<->private address mapping table with synthetic
* pairs. Without this mcount stays 0 forever in the fuzz process,
* which makes the loop body in map_addr_from_public_to_private /
* map_addr_from_private_to_public (and the addr_eq_no_port call
* it gates) unreachable. OSS-Fuzz introspector flags those as
* blockers; seeding two pairs (one v4, one v6) makes the loop
* body live for every fuzz iteration that decodes an address.
*/
#include <stddef.h>
#include <stdint.h>
#include <openssl/crypto.h>
#include "ns_turn_ioaddr.h"
static void seed_addr_mappings(void) {
ioa_addr pub4 = {0};
ioa_addr priv4 = {0};
ioa_addr pub6 = {0};
ioa_addr priv6 = {0};
if (make_ioa_addr((const uint8_t *)"192.0.2.1", 0, &pub4) == 0 &&
make_ioa_addr((const uint8_t *)"10.0.0.1", 0, &priv4) == 0) {
ioa_addr_add_mapping(&pub4, &priv4);
}
if (make_ioa_addr((const uint8_t *)"2001:db8::1", 0, &pub6) == 0 &&
make_ioa_addr((const uint8_t *)"fd00::1", 0, &priv6) == 0) {
ioa_addr_add_mapping(&pub6, &priv6);
}
}
int LLVMFuzzerInitialize(int *argc, char ***argv) {
(void)argc;
(void)argv;
#if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && !defined(LIBRESSL_VERSION_NUMBER)
/*
* Keep fuzzing deterministic and avoid MSan reports from OpenSSL's
* environment-dependent config file loading in unsanitized libcrypto.
*/
OPENSSL_init_crypto(OPENSSL_INIT_NO_LOAD_CONFIG, NULL);
#endif
seed_addr_mappings();
return 0;
}