DnsFuzzer: Added fuzzer test for exercising lwip/dns receiving DNS responses

This commit is contained in:
David Cermak 2018-05-18 15:54:08 +02:00
parent 5ecf717e40
commit bb25d0a348
35 changed files with 262 additions and 16 deletions

View file

@ -5,14 +5,21 @@ INC_DIRS=-I . -I $(COMPONENTS_DIR)/lwip/include/lwip -I $(COMPONENTS_DIR)/lwip/i
TEST_NAME=test
FUZZ=afl-fuzz
LD=$(CC)
ifeq ($(MODE),client)
DHCP_C_DEPENDENCY_INJECTION=-include dhcp_di.h
OBJECTS=dhcp.o network_mock.o test_client.o
SAMPLE_PACKETS=in_client
else
DHCP_C_DEPENDENCY_INJECTION=-include dhcpserver_di.h
OBJECTS=dhcpserver.o test_server.o network_mock.o
SAMPLE_PACKETS=in_server
ifeq ($(MODE),dhcp_client)
DEPENDENCY_INJECTION=-include dhcp_di.h
OBJECTS=dhcp.o network_mock.o test_dhcp_client.o
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
$(error Please specify MODE: dhcp_server, dhcp_client, dns)
endif
ifeq ($(INSTR),off)
@ -27,13 +34,17 @@ CFLAGS+=$(INC_DIRS)
all: $(TEST_NAME)
dns.o: ../core/dns.c
@echo "[CC] $<"
@$(CC) $(CFLAGS) $(DEPENDENCY_INJECTION) -c $< -o $@
dhcp.o: ../core/ipv4/dhcp.c
@echo "[CC] $<"
@$(CC) $(CFLAGS) $(DHCP_C_DEPENDENCY_INJECTION) -c $< -o $@
@$(CC) $(CFLAGS) $(DEPENDENCY_INJECTION) -c $< -o $@
dhcpserver.o: ../apps/dhcpserver.c
@echo "[CC] $<"
@$(CC) $(CFLAGS) $(DHCP_C_DEPENDENCY_INJECTION) -c $< -o $@
@$(CC) $(CFLAGS) $(DEPENDENCY_INJECTION) -c $< -o $@
%.o: %.c
@echo "[CC] $<"

View 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
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -9,23 +9,84 @@
const ip_addr_t ip_addr_any;
const ip_addr_t ip_addr_broadcast;
const ip_addr_t ip_addr_any_type;
struct ip_globals ip_data;
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)
{
return 0;
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
}
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)
{
return ESP_OK;
return ESP_OK;
}
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
@ -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)
{
}
#endif
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)
@ -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)
{
return 0;
return lwip_htonl(x);
}
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;
}
/* 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)
{
return ESP_OK;

View 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;
}