Skip to content
Snippets Groups Projects
Commit 95f2d6d1 authored by Anjan Chanda's avatar Anjan Chanda
Browse files

tests: fuzz: verify 'rxcmdu' with fuzzed 1905 cmdus

parent a8f98ec5
Branches
No related tags found
No related merge requests found
...@@ -3,6 +3,14 @@ CFLAGS+=-I. -D_GNU_SOURCE ...@@ -3,6 +3,14 @@ CFLAGS+=-I. -D_GNU_SOURCE
CFLAGS+= -ggdb3 -Wall -Werror CFLAGS+= -ggdb3 -Wall -Werror
CFLAGS += -I/usr/include/libnl3 CFLAGS += -I/usr/include/libnl3
ifeq ($(CC),clang)
CFLAGS += -Wno-gnu-variable-sized-type-not-at-end
ifdef FUZZ_TEST
CFLAGS += -fsanitize=fuzzer -DFUZZ_TEST
LDFLAGS += -fsanitize=fuzzer
endif
endif
header-files=cmdu.h cmdu_ackq.h 1905_tlvs.h i1905_wsc.h bufutil.h \ header-files=cmdu.h cmdu_ackq.h 1905_tlvs.h i1905_wsc.h bufutil.h \
timer_impl.h i1905_extension.h timer_impl.h i1905_extension.h
...@@ -21,7 +29,6 @@ OBJS = cmdu_input.o \ ...@@ -21,7 +29,6 @@ OBJS = cmdu_input.o \
i1905_extension.o \ i1905_extension.o \
i1905_ubus.o \ i1905_ubus.o \
i1905_netlink.o \ i1905_netlink.o \
main.o \
debug.o \ debug.o \
util.o \ util.o \
cmduqueue.o \ cmduqueue.o \
...@@ -33,6 +40,12 @@ ifneq (,$(findstring HAS_WIFI,$(CFLAGS))) ...@@ -33,6 +40,12 @@ ifneq (,$(findstring HAS_WIFI,$(CFLAGS)))
OBJS += i1905_wifi.o OBJS += i1905_wifi.o
endif endif
ifdef FUZZ_TEST
OBJS += test_rxcmdu.o fuzz_main.o
else
OBJS += main.o
endif
LIBOBJS = cmdu.o \ LIBOBJS = cmdu.o \
cmdu_ackq.o \ cmdu_ackq.o \
timer.o \ timer.o \
......
const char *PROG_NAME = "ieee1905d";
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <json-c/json.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <libubox/uloop.h>
#include <libubox/ustream.h>
#include <libubox/utils.h>
#include <libubus.h>
#include <easy/easy.h>
#include "debug.h"
#include "util.h"
#include "timer.h"
#include "config.h"
#include "cmdu.h"
#include "1905_tlvs.h"
#include "cmdu_ackq.h"
#include "cmdufrag.h"
#include "i1905_dm.h"
#include "i1905.h"
#include "i1905_extension.h"
struct i1905_fuzzer {
void *i1905; /* i1905 private context */
atimer_t fuzztimer;
void *testdata;
size_t testdatalen;
};
struct i1905_fuzzer fuzzer;
static int i1905_init_once;
struct tlv_policy pol[] = {
[0] = { .type = TLV_TYPE_DEVICE_INFORMATION_TYPE, .present = TLV_PRESENT_ONE },
[1] = { .type = TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES, .present = TLV_PRESENT_MORE },
[2] = { .type = TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST, .present = TLV_PRESENT_MORE },
[3] = { .type = TLV_TYPE_NEIGHBOR_DEVICE_LIST, .present = TLV_PRESENT_MORE },
[4] = { .type = TLV_TYPE_POWER_OFF_INTERFACE, .present = TLV_PRESENT_MORE},
[5] = { .type = TLV_TYPE_L2_NEIGHBOR_DEVICE, .present = TLV_PRESENT_MORE },
};
struct tlv *tv[6][16];
int num_pol = 6;
char *ifname = "eth0";
uint8_t ifmacaddr[] = "\x02\x42\xC0\xA8\x00\x02"; // TODO: get macaddress of eth0
uint8_t origin[] = "\x00\x10\x20\xbb\xbb\xbb";
uint16_t cmdutype = CMDU_TYPE_TOPOLOGY_RESPONSE;
uint16_t mid = 0; // TODO: random based on seed
int cmdu_parse_tlvs_raw(const uint8_t *data, size_t datalen, struct tlv *tv[][16],
struct tlv_policy *policy, int policy_len)
{
int idx[policy_len];
struct tlv *t;
int len;
int i;
if (!data || !datalen)
return -1;
for (i = 0; i < policy_len; i++) {
memset(tv[i], 0, 16 * sizeof(struct tlv *));
idx[i] = 0;
}
len = datalen;
cmdu_for_each_tlv(t, data, len) {
for (i = 0; i < policy_len; i++) {
if (policy[i].type != t->type)
continue;
if (policy[i].len && tlv_length(t) != policy[i].len)
return -1;
if (policy[i].minlen > 0 &&
tlv_length(t) < policy[i].minlen)
continue;
if (policy[i].maxlen > 0 &&
tlv_length(t) > policy[i].maxlen)
continue;
//if (tlv_length(t) < tlv_minsize(t)) //TODO: tlv_minsize()
// continue;
if (tv[i][0]) {
if (policy[i].present == TLV_PRESENT_ONE ||
policy[i].present == TLV_PRESENT_OPTIONAL_ONE)
return -1;
}
tv[i][idx[i]++] = t;
}
}
/* malformed cmdu if data remaining; only allow zero padding */
if (len) {
int k = 0;
while (k < len) {
if (data[datalen - len + k++] != 0)
return -1;
}
}
/* strictly check against tlv policies */
for (i = 0; i < policy_len; i++) {
if ((policy[i].present == TLV_PRESENT_ONE ||
policy[i].present == TLV_PRESENT_MORE) && !tv[i][0])
return -1;
}
return 0;
}
int i1905_process_cmdu_fuzzed(void *context, char *ifname, uint8_t *ifmacaddr,
uint8_t *origin, uint16_t cmdutype,
uint16_t mid, const uint8_t *data, size_t len)
{
struct cmdu_buff *rxf = NULL;
int ret;
if (!ifname || !ifmacaddr || !origin)
return -EINVAL;
rxf = cmdu_alloc_default();
if (!rxf) {
err("%s: -ENOMEM\n", __func__);
return -ENOMEM;
}
memcpy(rxf->dev_macaddr, ifmacaddr, 6);
strncpy(rxf->dev_ifname, ifname, 15);
memcpy(rxf->origin, origin, 6);
rxf->cdata = (struct cmdu_linear *)(rxf->head + 14);
rxf->data = (uint8_t *)(rxf->cdata + 1);
CMDU_SET_LAST_FRAGMENT(rxf->cdata);
cmdu_set_type(rxf, cmdutype);
cmdu_set_mid(rxf, mid);
if (data && len) {
memcpy(rxf->data, data, len);
rxf->datalen = len;
}
rxf->tail = rxf->data + rxf->datalen;
ret = i1905_process_cmdu(context, rxf);
cmdu_free(rxf);
return ret;
}
int i1905_main_entry(void **context)
{
struct i1905_useropts opts = {
.ubus_sockpath = NULL,
.pidfile = IEEE1905_PIDFILE,
.objname = IEEE1905_OBJECT,
.daemonize = false,
.conffile = IEEE1905_CONFFILE,
.confpath = IEEE1905_CONFFILE_PATH,
.debug_level = 2,
.syslogging = false,
.logfile = NULL,
.logfile_isfifo = false,
};
void *i1905_handle;
int ret;
if (opts.daemonize)
do_daemonize(opts.pidfile);
start_logging(&opts);
ret = i1905_init(&i1905_handle, &opts);
if (ret) {
fprintf(stderr, "%s : Failed to init.\n", IEEE1905_OBJECT);
return -1;
}
*context = i1905_handle;
return 0;
}
void i1905_main_exit(void *context)
{
i1905_exit(context);
stop_logging();
}
void i1905_fuzzer_run(atimer_t *t)
{
struct i1905_fuzzer *f = container_of(t, struct i1905_fuzzer, fuzztimer);
i1905_process_cmdu_fuzzed(f->i1905, ifname, ifmacaddr,
origin, cmdutype, mid,
f->testdata, f->testdatalen);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
int ret = 0;
#if 0
fprintf(stderr, "\n\n%s: size = %zu --->\n", __func__, size);
for (int i = 0; i < size; i++)
fprintf(stderr, "%02x ", data[i] & 0xff);
fprintf(stderr, "\n-----------------\n");
#endif
if (!i1905_init_once) {
i1905_init_once = 1;
ret = i1905_main_entry(&fuzzer.i1905);
}
if (ret) {
err("Failed to start i1905 in fuzz-test mode\n");
return 0;
}
ret = cmdu_parse_tlvs_raw(data, size, tv, pol, num_pol);
if (!ret) {
/* got syntactically valid payload; feed into i1905 stack */
fuzzer.testdata = (void *)data;
fuzzer.testdatalen = size;
timer_init(&fuzzer.fuzztimer, i1905_fuzzer_run);
timer_set(&fuzzer.fuzztimer, 100);
i1905_run(&fuzzer.i1905);
i1905_main_exit(&fuzzer.i1905);
}
return 0;
}
static void fill_random_bytes(uint8_t *buf, size_t len, unsigned int seed)
{
int i;
srandom(seed);
for (i = 0; i < len; i++)
buf[i] = random() & 0xff;
}
uint8_t *write_tlv(uint16_t tlv_type, uint8_t *buf, size_t len, unsigned int seed)
{
if (len < 0)
len = 0;
buf[0] = tlv_type;
buf_put_be16(&buf[1], len);
fill_random_bytes(&buf[3], len, seed);
return &buf[3 + len - 1];
}
size_t mutate_payload(uint8_t *data, size_t size, size_t maxsize, unsigned int seed)
{
//uint16_t cmdutype = seed % 0x12;
int num_tlvs = 4;
size_t total_len;
size_t len;
if (size < 3) {
len = 3;
} else if (size < 1492) {
len = size;
} else {
len = 1492;
}
total_len = num_tlvs * (len + 3);
if (total_len > maxsize)
return 0;
do {
uint8_t dummy_tlv[total_len];
int mutation = seed % 4;
uint8_t *ptr;
fprintf(stderr, "mutation %d\n", mutation);
switch (mutation) {
case 0:
ptr = write_tlv(TLV_TYPE_DEVICE_INFORMATION_TYPE, &dummy_tlv[0], len, seed);
ptr = write_tlv(TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
break;
case 1:
ptr = write_tlv(TLV_TYPE_DEVICE_INFORMATION_TYPE, &dummy_tlv[0], len, seed);
ptr = write_tlv(TLV_TYPE_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
break;
case 2:
ptr = write_tlv(TLV_TYPE_DEVICE_INFORMATION_TYPE, &dummy_tlv[0], len, seed);
ptr = write_tlv(TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES, ptr + 1, len, seed);
break;
case 3:
ptr = write_tlv(TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES, &dummy_tlv[0], len, seed);
ptr = write_tlv(TLV_TYPE_NEIGHBOR_DEVICE_LIST, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_DEVICE_INFORMATION_TYPE, ptr + 1, len, seed);
ptr = write_tlv(TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES, ptr + 1, len, seed);
break;
}
memcpy(data, dummy_tlv, total_len);
} while (0);
return total_len;
}
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
unsigned int seed)
{
size_t newsize;
int ret;
ret = cmdu_parse_tlvs_raw(data, size, tv, pol, num_pol);
if (ret) {
//fprintf(stderr, "%s: size = %zu seed = %u\n", __func__, size, seed);
return mutate_payload(data, size, maxsize, seed);
}
//fprintf(stderr, "%s: - success - size = %zu\n", __func__, size);
newsize = LLVMFuzzerMutate(data, size, 1492);
ret = cmdu_parse_tlvs_raw(data, size, tv, pol, num_pol);
if (ret)
return 0;
fprintf(stderr, "%s: - new valid mutation - newsize = %zu\n", __func__, newsize);
return newsize;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment