DnsFuzzer: Added fuzzer test for exercising lwip/dns receiving DNS responses
This commit is contained in:
parent
5ecf717e40
commit
bb25d0a348
35 changed files with 262 additions and 16 deletions
|
@ -5,14 +5,21 @@ INC_DIRS=-I . -I $(COMPONENTS_DIR)/lwip/include/lwip -I $(COMPONENTS_DIR)/lwip/i
|
||||||
TEST_NAME=test
|
TEST_NAME=test
|
||||||
FUZZ=afl-fuzz
|
FUZZ=afl-fuzz
|
||||||
LD=$(CC)
|
LD=$(CC)
|
||||||
ifeq ($(MODE),client)
|
ifeq ($(MODE),dhcp_client)
|
||||||
DHCP_C_DEPENDENCY_INJECTION=-include dhcp_di.h
|
DEPENDENCY_INJECTION=-include dhcp_di.h
|
||||||
OBJECTS=dhcp.o network_mock.o test_client.o
|
OBJECTS=dhcp.o network_mock.o test_dhcp_client.o
|
||||||
SAMPLE_PACKETS=in_client
|
SAMPLE_PACKETS=in_dhcp_client
|
||||||
|
else ifeq ($(MODE),dhcp_server)
|
||||||
|
DEPENDENCY_INJECTION=-include dhcpserver_di.h
|
||||||
|
OBJECTS=dhcpserver.o test_dhcp_server.o network_mock.o
|
||||||
|
SAMPLE_PACKETS=in_dhcp_server
|
||||||
|
else ifeq ($(MODE),dns)
|
||||||
|
CFLAGS+=-DNOT_MOCK_DNS
|
||||||
|
DEPENDENCY_INJECTION=-include dns_di.h
|
||||||
|
OBJECTS=dns.o test_dns.o network_mock.o
|
||||||
|
SAMPLE_PACKETS=in_dns
|
||||||
else
|
else
|
||||||
DHCP_C_DEPENDENCY_INJECTION=-include dhcpserver_di.h
|
$(error Please specify MODE: dhcp_server, dhcp_client, dns)
|
||||||
OBJECTS=dhcpserver.o test_server.o network_mock.o
|
|
||||||
SAMPLE_PACKETS=in_server
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(INSTR),off)
|
ifeq ($(INSTR),off)
|
||||||
|
@ -27,13 +34,17 @@ CFLAGS+=$(INC_DIRS)
|
||||||
|
|
||||||
all: $(TEST_NAME)
|
all: $(TEST_NAME)
|
||||||
|
|
||||||
|
dns.o: ../core/dns.c
|
||||||
|
@echo "[CC] $<"
|
||||||
|
@$(CC) $(CFLAGS) $(DEPENDENCY_INJECTION) -c $< -o $@
|
||||||
|
|
||||||
dhcp.o: ../core/ipv4/dhcp.c
|
dhcp.o: ../core/ipv4/dhcp.c
|
||||||
@echo "[CC] $<"
|
@echo "[CC] $<"
|
||||||
@$(CC) $(CFLAGS) $(DHCP_C_DEPENDENCY_INJECTION) -c $< -o $@
|
@$(CC) $(CFLAGS) $(DEPENDENCY_INJECTION) -c $< -o $@
|
||||||
|
|
||||||
dhcpserver.o: ../apps/dhcpserver.c
|
dhcpserver.o: ../apps/dhcpserver.c
|
||||||
@echo "[CC] $<"
|
@echo "[CC] $<"
|
||||||
@$(CC) $(CFLAGS) $(DHCP_C_DEPENDENCY_INJECTION) -c $< -o $@
|
@$(CC) $(CFLAGS) $(DEPENDENCY_INJECTION) -c $< -o $@
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
@echo "[CC] $<"
|
@echo "[CC] $<"
|
||||||
|
|
59
components/lwip/test_afl_host/dns_di.h
Normal file
59
components/lwip/test_afl_host/dns_di.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* dns.c dependecy injection -- preincluded to inject interface test functions into static variables
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "no_warn_host.h"
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
|
||||||
|
#define ipaddr_aton(cp, addr) ip4addr_aton(cp, addr)
|
||||||
|
|
||||||
|
extern uint32_t g_random_numbers[8];
|
||||||
|
extern uint32_t g_random_numbers_cnt;
|
||||||
|
|
||||||
|
void __assert_func(const char *file, int line, const char *func, const char *expr)
|
||||||
|
{
|
||||||
|
printf("Assert failed in %s, %s:%d (%s)", func, file, line, expr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ip4addr_aton(const char *cp, ip4_addr_t *addr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg, u8_t dns_addrtype);
|
||||||
|
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
|
||||||
|
|
||||||
|
void (*dns_test_static_dns_recv)(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) = NULL;
|
||||||
|
err_t (*dns_test_static_dns_enqueue)(const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg, u8_t dns_addrtype) = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
void dns_test_init_di()
|
||||||
|
{
|
||||||
|
dns_test_static_dns_recv = dns_recv;
|
||||||
|
dns_test_static_dns_enqueue = dns_enqueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t dns_test_dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg, u8_t dns_addrtype)
|
||||||
|
{
|
||||||
|
return dns_test_static_dns_enqueue(name, hostnamelen, found, callback_arg, dns_addrtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_test_dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
dns_test_static_dns_recv(s, pcb, p, addr, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_test_inject_port_and_txid(int port, int txid)
|
||||||
|
{
|
||||||
|
// inject random numbers
|
||||||
|
g_random_numbers[0] = port; //for port
|
||||||
|
g_random_numbers[1] = txid; //for txid
|
||||||
|
g_random_numbers_cnt = 0; // let's start with the port
|
||||||
|
}
|
BIN
components/lwip/test_afl_host/in_dns/out0.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out0.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out10.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out10.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out28.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out28.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out29.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out29.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out30.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out30.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out31.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out31.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out32.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out32.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out33.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out33.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out34.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out34.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out35.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out35.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out36.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out36.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out37.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out37.bin
Normal file
Binary file not shown.
BIN
components/lwip/test_afl_host/in_dns/out38.bin
Normal file
BIN
components/lwip/test_afl_host/in_dns/out38.bin
Normal file
Binary file not shown.
|
@ -9,18 +9,79 @@
|
||||||
|
|
||||||
const ip_addr_t ip_addr_any;
|
const ip_addr_t ip_addr_any;
|
||||||
const ip_addr_t ip_addr_broadcast;
|
const ip_addr_t ip_addr_broadcast;
|
||||||
|
const ip_addr_t ip_addr_any_type;
|
||||||
struct ip_globals ip_data;
|
struct ip_globals ip_data;
|
||||||
struct netif *netif_list;
|
struct netif *netif_list;
|
||||||
|
struct udp_pcb mock_pcb;
|
||||||
|
uint32_t g_random_numbers[8] = {0};
|
||||||
|
uint32_t g_random_numbers_cnt = 0;
|
||||||
|
|
||||||
|
|
||||||
|
struct pbuf* pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset)
|
||||||
|
{
|
||||||
|
u16_t offset_left = in_offset;
|
||||||
|
struct pbuf* q = in;
|
||||||
|
|
||||||
|
/* get the correct pbuf */
|
||||||
|
while ((q != NULL) && (q->len <= offset_left)) {
|
||||||
|
offset_left -= q->len;
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
if (out_offset != NULL) {
|
||||||
|
*out_offset = offset_left;
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data)
|
||||||
|
{
|
||||||
|
u16_t q_idx;
|
||||||
|
struct pbuf* q = pbuf_skip(p, offset, &q_idx);
|
||||||
|
|
||||||
|
/* write requested data if pbuf is OK */
|
||||||
|
if ((q != NULL) && (q->len > q_idx)) {
|
||||||
|
((u8_t*)q->payload)[q_idx] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8_t pbuf_get_at(struct pbuf* p, u16_t offset)
|
||||||
|
{
|
||||||
|
u16_t q_idx;
|
||||||
|
struct pbuf* q = pbuf_skip(p, offset, &q_idx);
|
||||||
|
|
||||||
|
/* return requested data if pbuf is OK */
|
||||||
|
if ((q != NULL) && (q->len > q_idx)) {
|
||||||
|
return ((u8_t*)q->payload)[q_idx];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
|
||||||
|
{
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset)
|
||||||
|
{
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct udp_pcb * udp_new_ip_type(u8_t type)
|
||||||
|
{
|
||||||
|
return &mock_pcb;
|
||||||
|
}
|
||||||
|
|
||||||
u16_t lwip_htons(u16_t n)
|
u16_t lwip_htons(u16_t n)
|
||||||
{
|
{
|
||||||
return 0;
|
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32_t lwip_htonl(u32_t n)
|
u32_t lwip_htonl(u32_t n)
|
||||||
{
|
{
|
||||||
return 0;
|
return ((n & 0xff) << 24) |
|
||||||
|
((n & 0xff00) << 8) |
|
||||||
|
((n & 0xff0000UL) >> 8) |
|
||||||
|
((n & 0xff000000UL) >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t tcpip_adapter_get_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info)
|
esp_err_t tcpip_adapter_get_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info)
|
||||||
|
@ -84,13 +145,16 @@ void udp_disconnect(struct udp_pcb *pcb)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NOT_MOCK_DNS
|
||||||
void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
|
void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t esp_random(void)
|
uint32_t esp_random(void)
|
||||||
{
|
{
|
||||||
return 0;
|
// Preparation for injecting favorable random numbers
|
||||||
|
return g_random_numbers[g_random_numbers_cnt++ % 8];
|
||||||
}
|
}
|
||||||
|
|
||||||
err_t etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
|
err_t etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
|
||||||
|
@ -100,7 +164,7 @@ err_t etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q
|
||||||
|
|
||||||
u32_t lwip_ntohl(u32_t x)
|
u32_t lwip_ntohl(u32_t x)
|
||||||
{
|
{
|
||||||
return 0;
|
return lwip_htonl(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask,
|
void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask,
|
||||||
|
@ -120,10 +184,43 @@ void pbuf_realloc(struct pbuf *p, u16_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset)
|
u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||||
{
|
{
|
||||||
|
struct pbuf *p;
|
||||||
|
u16_t left;
|
||||||
|
u16_t buf_copy_len;
|
||||||
|
u16_t copied_total = 0;
|
||||||
|
|
||||||
|
LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
|
||||||
|
LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
|
||||||
|
|
||||||
|
left = 0;
|
||||||
|
|
||||||
|
if ((buf == NULL) || (dataptr == NULL)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
|
||||||
|
for (p = buf; len != 0 && p != NULL; p = p->next) {
|
||||||
|
if ((offset != 0) && (offset >= p->len)) {
|
||||||
|
/* don't copy from this buffer -> on to the next */
|
||||||
|
offset -= p->len;
|
||||||
|
} else {
|
||||||
|
/* copy from this buffer. maybe only partially. */
|
||||||
|
buf_copy_len = p->len - offset;
|
||||||
|
if (buf_copy_len > len)
|
||||||
|
buf_copy_len = len;
|
||||||
|
/* copy the necessary parts of the buffer */
|
||||||
|
MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
|
||||||
|
copied_total += buf_copy_len;
|
||||||
|
left += buf_copy_len;
|
||||||
|
len -= buf_copy_len;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copied_total;
|
||||||
|
}
|
||||||
|
|
||||||
err_t udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
|
err_t udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
|
||||||
{
|
{
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
79
components/lwip/test_afl_host/test_dns.c
Normal file
79
components/lwip/test_afl_host/test_dns.c
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#include "no_warn_host.h"
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
const ip_addr_t ip_addr_any;
|
||||||
|
const ip_addr_t ip_addr_broadcast;
|
||||||
|
struct ip_globals ip_data;
|
||||||
|
struct netif *netif_list;
|
||||||
|
struct netif mynetif;
|
||||||
|
ip4_addr_t server_ip;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Dependency injected test functions
|
||||||
|
void dns_test_dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
|
||||||
|
void dns_test_inject_port_and_txid(int port, int txid);
|
||||||
|
|
||||||
|
void dns_test_init_di();
|
||||||
|
err_t dns_test_dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg, u8_t dns_addrtype);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Test starts here
|
||||||
|
//
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
uint8_t *buf;
|
||||||
|
struct pbuf *p;
|
||||||
|
FILE *file;
|
||||||
|
size_t len = 1460;
|
||||||
|
|
||||||
|
dns_test_init_di();
|
||||||
|
|
||||||
|
#ifdef INSTR_IS_OFF
|
||||||
|
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||||
|
buf = p->payload;
|
||||||
|
memset(buf, 0, 1460);
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
printf("Non-instrumentation mode: please supply a file name created by AFL to reproduce crash\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Note: parameter1 is a file (mangled packet) which caused the crash
|
||||||
|
file = fopen(argv[1], "r");
|
||||||
|
if (file) {
|
||||||
|
len = fread(buf, 1, 1460, file);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
int i;
|
||||||
|
for (i=0; i<1; i++) {
|
||||||
|
#else
|
||||||
|
while (__AFL_LOOP(1000)) {
|
||||||
|
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||||
|
buf = p->payload;
|
||||||
|
memset(buf, 0, 1460);
|
||||||
|
size_t len = read(0, buf, 1460);
|
||||||
|
#endif
|
||||||
|
p->len = len;
|
||||||
|
p->tot_len = len;
|
||||||
|
p->next = NULL;
|
||||||
|
|
||||||
|
// Pretend that the response is from our pending querries
|
||||||
|
dns_test_inject_port_and_txid(1024, (buf[0]<<8) + buf[1]);
|
||||||
|
dns_test_dns_enqueue("test", 4, NULL, NULL, 0);
|
||||||
|
|
||||||
|
// Process the packet
|
||||||
|
dns_test_dns_recv(NULL, NULL, p, &ip_addr_any, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue