mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 01:59:26 +00:00
Fuzz testing the qp-trie
Ensure dns_qpkey_fromname() and dns_qpkey_toname() are inverses. Excercise a single-threaded dns_qp_t with a fixed set of random keys and a small chunk size. Use the table of names to ensure that the trie is behaving as expected. This is (in effect) randomized testing like the `qpmulti` unit test, but making use of coverage-guided fuzzing and (in principle) test case minimization.
This commit is contained in:
parent
fbdb8b502a
commit
b06f6ef75a
2
fuzz/.gitignore
vendored
2
fuzz/.gitignore
vendored
@ -5,6 +5,8 @@
|
||||
/dns_message_parse
|
||||
/dns_name_fromtext_target
|
||||
/dns_name_fromwire
|
||||
/dns_qp
|
||||
/dns_qpkey_name
|
||||
/dns_rdata_fromtext
|
||||
/dns_rdata_fromwire_text
|
||||
/isc_lex_getmastertoken
|
||||
|
@ -13,8 +13,8 @@ AM_LDFLAGS += \
|
||||
|
||||
LDADD += \
|
||||
libfuzzmain.la \
|
||||
$(LIBISC_LIBS) \
|
||||
$(LIBDNS_LIBS)
|
||||
$(LIBDNS_LIBS) \
|
||||
$(LIBISC_LIBS)
|
||||
|
||||
check_LTLIBRARIES = libfuzzmain.la
|
||||
libfuzzmain_la_SOURCES = \
|
||||
@ -38,6 +38,8 @@ EXTRA_DIST = \
|
||||
dns_message_parse.in \
|
||||
dns_name_fromtext_target.in \
|
||||
dns_name_fromwire.in \
|
||||
dns_qp.in \
|
||||
dns_qpkey_name.in \
|
||||
dns_rdata_fromtext.in \
|
||||
dns_rdata_fromwire_text.in \
|
||||
isc_lex_getmastertoken.in \
|
||||
@ -48,6 +50,24 @@ dns_name_fromwire_SOURCES = \
|
||||
old.c \
|
||||
old.h
|
||||
|
||||
if HAVE_CMOCKA
|
||||
|
||||
check_PROGRAMS += \
|
||||
dns_qp \
|
||||
dns_qpkey_name
|
||||
|
||||
AM_CPPFLAGS += \
|
||||
-I$(top_srcdir)/lib/dns \
|
||||
-I$(top_srcdir)/lib/isc \
|
||||
-I$(top_srcdir)/tests/include
|
||||
|
||||
# libisc needs to appear after libtest
|
||||
LDADD += \
|
||||
$(top_builddir)/tests/libtest/libtest.la \
|
||||
$(LIBISC_LIBS)
|
||||
|
||||
endif HAVE_CMOCKA
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
if HAVE_FUZZ_LOG_COMPILER
|
||||
|
221
fuzz/dns_qp.c
Normal file
221
fuzz/dns_qp.c
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/qp.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#include "fuzz.h"
|
||||
#include "qp_p.h"
|
||||
|
||||
#include <tests/qp.h>
|
||||
|
||||
bool debug = false;
|
||||
|
||||
#if 0
|
||||
#define TRACE(...) warnx(__VA_ARGS__)
|
||||
#else
|
||||
#define TRACE(...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define ASSERT(p) \
|
||||
do { \
|
||||
warnx("%s:%d: %s (%s)", __func__, __LINE__, #p, \
|
||||
(p) ? "OK" : "FAIL"); \
|
||||
ok = ok && (p); \
|
||||
} while (0)
|
||||
#else
|
||||
#define ASSERT(p) assert(p)
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
uint32_t refcount;
|
||||
bool exists;
|
||||
uint8_t len;
|
||||
dns_qpkey_t key;
|
||||
dns_qpkey_t ascii;
|
||||
} item[256 * 256 / 4];
|
||||
|
||||
static void
|
||||
fuzz_attach(void *ctx, void *pval, uint32_t ival) {
|
||||
assert(ctx == NULL);
|
||||
assert(pval == &item[ival]);
|
||||
item[ival].refcount++;
|
||||
}
|
||||
|
||||
static void
|
||||
fuzz_detach(void *ctx, void *pval, uint32_t ival) {
|
||||
assert(ctx == NULL);
|
||||
assert(pval == &item[ival]);
|
||||
item[ival].refcount--;
|
||||
}
|
||||
|
||||
static size_t
|
||||
fuzz_makekey(dns_qpkey_t key, void *ctx, void *pval, uint32_t ival) {
|
||||
assert(ctx == NULL);
|
||||
assert(pval == &item[ival]);
|
||||
memmove(key, item[ival].key, item[ival].len);
|
||||
return (item[ival].len);
|
||||
}
|
||||
|
||||
static void
|
||||
fuzz_triename(void *ctx, char *buf, size_t size) {
|
||||
assert(ctx == NULL);
|
||||
strlcpy(buf, "fuzz", size);
|
||||
}
|
||||
|
||||
const struct dns_qpmethods fuzz_methods = {
|
||||
fuzz_attach,
|
||||
fuzz_detach,
|
||||
fuzz_makekey,
|
||||
fuzz_triename,
|
||||
};
|
||||
|
||||
static uint8_t
|
||||
random_byte(void) {
|
||||
return (isc_random_uniform(SHIFT_OFFSET - SHIFT_NOBYTE) + SHIFT_NOBYTE);
|
||||
}
|
||||
|
||||
int
|
||||
LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(item); i++) {
|
||||
size_t len = isc_random_uniform(100) + 16;
|
||||
item[i].len = len;
|
||||
for (size_t off = 0; off < len; off++) {
|
||||
item[i].key[off] = random_byte();
|
||||
}
|
||||
memmove(item[i].ascii, item[i].key, len);
|
||||
qp_test_keytoascii(item[i].ascii, len);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
isc_result_t result;
|
||||
|
||||
TRACE("------------------------------------------------");
|
||||
|
||||
isc_mem_t *mctx = NULL;
|
||||
isc_mem_create(&mctx);
|
||||
isc_mem_setdestroycheck(mctx, true);
|
||||
|
||||
dns_qp_t *qp = NULL;
|
||||
dns_qp_create(mctx, &fuzz_methods, NULL, &qp);
|
||||
|
||||
/* avoid overrun */
|
||||
size = size & ~1;
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
for (size_t in = 0; in < size; in += 2) {
|
||||
size_t what = data[in] + data[in + 1] * 256;
|
||||
size_t i = (what / 4) % (count * 2 + 2);
|
||||
bool exists = item[i].exists;
|
||||
uint32_t refcount = item[i].refcount;
|
||||
bool ok = true;
|
||||
if (what & 2) {
|
||||
void *pval = NULL;
|
||||
uint32_t ival = ~0U;
|
||||
result = dns_qp_getkey(qp, item[i].key, item[i].len,
|
||||
&pval, &ival);
|
||||
TRACE("count %zu get %s %zu >%s<", count,
|
||||
isc_result_toid(result), i, item[i].ascii);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
ASSERT(pval == &item[i]);
|
||||
ASSERT(ival == i);
|
||||
ASSERT(item[i].refcount == 1);
|
||||
ASSERT(item[i].exists == true);
|
||||
} else if (result == ISC_R_NOTFOUND) {
|
||||
ASSERT(pval == NULL);
|
||||
ASSERT(ival == ~0U);
|
||||
ASSERT(item[i].refcount == 0);
|
||||
ASSERT(item[i].exists == false);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else if (what & 1) {
|
||||
result = dns_qp_insert(qp, &item[i], i);
|
||||
TRACE("count %zu ins %s %zu >%s<", count,
|
||||
isc_result_toid(result), i, item[i].ascii);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
item[i].exists = true;
|
||||
ASSERT(exists == false);
|
||||
ASSERT(refcount == 0);
|
||||
ASSERT(item[i].refcount == 1);
|
||||
count += 1;
|
||||
ASSERT(qp->leaf_count == count);
|
||||
} else if (result == ISC_R_EXISTS) {
|
||||
ASSERT(exists == true);
|
||||
ASSERT(refcount == 1);
|
||||
ASSERT(item[i].refcount == 1);
|
||||
ASSERT(qp->leaf_count == count);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
result = dns_qp_deletekey(qp, item[i].key, item[i].len);
|
||||
TRACE("count %zu del %s %zu >%s<", count,
|
||||
isc_result_toid(result), i, item[i].ascii);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
item[i].exists = false;
|
||||
ASSERT(exists == true);
|
||||
ASSERT(refcount == 1);
|
||||
ASSERT(item[i].refcount == 0);
|
||||
count -= 1;
|
||||
ASSERT(qp->leaf_count == count);
|
||||
} else if (result == ISC_R_NOTFOUND) {
|
||||
ASSERT(exists == false);
|
||||
ASSERT(refcount == 0);
|
||||
ASSERT(item[i].refcount == 0);
|
||||
ASSERT(qp->leaf_count == count);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
qp_test_dumpqp(qp);
|
||||
qp_test_dumptrie(qp);
|
||||
}
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(item); i++) {
|
||||
assert(item[i].exists == (item[i].refcount != 0));
|
||||
}
|
||||
|
||||
dns_qp_destroy(&qp);
|
||||
isc_mem_destroy(&mctx);
|
||||
isc_mem_checkdestroyed(stderr);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(item); i++) {
|
||||
item[i].exists = false;
|
||||
assert(item[i].refcount == 0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
BIN
fuzz/dns_qp.in/bytecodes
Normal file
BIN
fuzz/dns_qp.in/bytecodes
Normal file
Binary file not shown.
77
fuzz/dns_qpkey_name.c
Normal file
77
fuzz/dns_qpkey_name.c
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/compress.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/qp.h>
|
||||
|
||||
#include "fuzz.h"
|
||||
|
||||
#include <tests/qp.h>
|
||||
|
||||
bool debug = false;
|
||||
|
||||
int
|
||||
LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
dns_fixedname_t fixedin, fixedout, fixedcmp;
|
||||
dns_name_t *namein, *nameout, *namecmp;
|
||||
isc_buffer_t buf;
|
||||
dns_qpkey_t key, cmp;
|
||||
|
||||
namein = dns_fixedname_initname(&fixedin);
|
||||
nameout = dns_fixedname_initname(&fixedout);
|
||||
namecmp = dns_fixedname_initname(&fixedcmp);
|
||||
|
||||
isc_buffer_constinit(&buf, data, size);
|
||||
isc_buffer_add(&buf, size);
|
||||
isc_buffer_setactive(&buf, size);
|
||||
|
||||
CHECK(dns_name_fromwire(namein, &buf, DNS_DECOMPRESS_NEVER, NULL));
|
||||
|
||||
/* verify round-trip conversion of first name */
|
||||
size_t keylen = dns_qpkey_fromname(key, namein);
|
||||
qp_test_keytoname(key, nameout);
|
||||
|
||||
assert(dns_name_equal(namein, nameout));
|
||||
|
||||
/* is there a second name? */
|
||||
CHECK(dns_name_fromwire(namecmp, &buf, DNS_DECOMPRESS_NEVER, NULL));
|
||||
|
||||
size_t cmplen = dns_qpkey_fromname(cmp, namecmp);
|
||||
size_t len = ISC_MIN(keylen, cmplen);
|
||||
|
||||
int namerel = dns_name_compare(namein, namecmp);
|
||||
int keyrel = memcmp(key, cmp, len + 1);
|
||||
|
||||
assert((namerel < 0) == (keyrel < 0));
|
||||
assert((namerel == 0) == (keyrel == 0));
|
||||
assert((namerel > 0) == (keyrel > 0));
|
||||
|
||||
return (0);
|
||||
}
|
BIN
fuzz/dns_qpkey_name.in/021976d644b75207ffa3389e7ab30f5555f74dda
Normal file
BIN
fuzz/dns_qpkey_name.in/021976d644b75207ffa3389e7ab30f5555f74dda
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/13a8fb7162940fd0eeeb7597e47d6a95041f3396
Normal file
BIN
fuzz/dns_qpkey_name.in/13a8fb7162940fd0eeeb7597e47d6a95041f3396
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
<EFBFBD>
|
BIN
fuzz/dns_qpkey_name.in/30a5288c64e9c856005fceb8b9155f8854d7368e
Normal file
BIN
fuzz/dns_qpkey_name.in/30a5288c64e9c856005fceb8b9155f8854d7368e
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/404a051635872ce8de8846ad112a96cb72e13fe5
Normal file
BIN
fuzz/dns_qpkey_name.in/404a051635872ce8de8846ad112a96cb72e13fe5
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/562a1a46610aa93786f3e04cf2cd8044eff2a2b4
Normal file
BIN
fuzz/dns_qpkey_name.in/562a1a46610aa93786f3e04cf2cd8044eff2a2b4
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/62f2b90d4c70b3427355e6fed351855e89a1a97f
Normal file
BIN
fuzz/dns_qpkey_name.in/62f2b90d4c70b3427355e6fed351855e89a1a97f
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/70ea4ca2c2211b2b2ee3400c09eac2302031475e
Normal file
BIN
fuzz/dns_qpkey_name.in/70ea4ca2c2211b2b2ee3400c09eac2302031475e
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/824cbc20333bbac1dafb93a3605cea366bb24b2d
Normal file
BIN
fuzz/dns_qpkey_name.in/824cbc20333bbac1dafb93a3605cea366bb24b2d
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/9100388c033912183ac53ea771286103eda8c296
Normal file
BIN
fuzz/dns_qpkey_name.in/9100388c033912183ac53ea771286103eda8c296
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
<01>
|
BIN
fuzz/dns_qpkey_name.in/b06bf7d26ac11fde5ab24e77786bd28f89cf661d
Normal file
BIN
fuzz/dns_qpkey_name.in/b06bf7d26ac11fde5ab24e77786bd28f89cf661d
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/c2580a278455cfa2234b87d19aab87082b1fa5f3
Normal file
BIN
fuzz/dns_qpkey_name.in/c2580a278455cfa2234b87d19aab87082b1fa5f3
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/d0f27368167150098f7e6afee11facff57d39c94
Normal file
BIN
fuzz/dns_qpkey_name.in/d0f27368167150098f7e6afee11facff57d39c94
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/e09c3be9a268cf1f3a2118e9c07dac830904ea4f
Normal file
BIN
fuzz/dns_qpkey_name.in/e09c3be9a268cf1f3a2118e9c07dac830904ea4f
Normal file
Binary file not shown.
BIN
fuzz/dns_qpkey_name.in/f22d3ec38bf6cd6cc2776e376e3ec4ceca9fee39
Normal file
BIN
fuzz/dns_qpkey_name.in/f22d3ec38bf6cd6cc2776e376e3ec4ceca9fee39
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user