mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-05 12:25:03 +02:00
DnsFuzzer: Added fuzzer test for exercising lwip/dns receiving DNS responses
This commit is contained in:
@@ -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] $<"
|
||||
|
||||
@@ -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.
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user