From e983230be933fb83cebdd1945ba6539a7dc99b28 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 4 May 2018 16:42:54 +0200 Subject: [PATCH 1/2] MDNS-Fuzzer: AFL fuzzer tests for mdsn packet parser --- components/mdns/include/mdns.h | 4 - components/mdns/mdns.c | 318 +----------------- components/mdns/mdns_networking.c | 284 ++++++++++++++++ .../mdns/private_include/mdns_networking.h | 52 +++ components/mdns/test_afl_fuzz_host/Makefile | 22 +- .../mdns/test_afl_fuzz_host/esp32_compat.h | 153 +++++++-- .../mdns/test_afl_fuzz_host/esp32_mock.c | 84 +++++ .../mdns/test_afl_fuzz_host/esp32_mock.h | 45 +++ components/mdns/test_afl_fuzz_host/mdns_di.h | 53 +++ components/mdns/test_afl_fuzz_host/test.c | 209 +++++++++--- 10 files changed, 833 insertions(+), 391 deletions(-) create mode 100644 components/mdns/mdns_networking.c create mode 100644 components/mdns/private_include/mdns_networking.h create mode 100644 components/mdns/test_afl_fuzz_host/esp32_mock.c create mode 100644 components/mdns/test_afl_fuzz_host/esp32_mock.h create mode 100644 components/mdns/test_afl_fuzz_host/mdns_di.h diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index db0e3b522..a5ebb809f 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -18,12 +18,8 @@ extern "C" { #endif -#ifndef MDNS_TEST_MODE #include #include "esp_event.h" -#else -#include "esp32_compat.h" -#endif #define MDNS_TYPE_A 0x0001 #define MDNS_TYPE_PTR 0x000C diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index da00d7e5d..73c5f99c9 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -11,25 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #include "mdns.h" - -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" -#include "lwip/ip_addr.h" -#include "lwip/pbuf.h" -#include "lwip/igmp.h" -#include "lwip/udp.h" -#include "lwip/mld6.h" -#include "lwip/priv/tcpip_priv.h" -#include "esp_wifi.h" -#include "esp_system.h" -#include "esp_timer.h" -#include "esp_event_loop.h" - #include "mdns_private.h" +#include "mdns_networking.h" +#include #ifdef MDNS_ENABLE_DEBUG void mdns_debug_packet(const uint8_t * data, size_t len); @@ -38,7 +24,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len); static const char * MDNS_DEFAULT_DOMAIN = "local"; static const char * MDNS_SUB_STR = "_sub"; -static mdns_server_t * _mdns_server = NULL; +mdns_server_t * _mdns_server = NULL; static volatile TaskHandle_t _mdns_service_task_handle = NULL; static SemaphoreHandle_t _mdns_service_semaphore = NULL; @@ -110,14 +96,7 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char return NULL; } -/* - * MDNS Server Networking - * */ - -/** - * @brief Queue RX packet action - */ -static esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet) +esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet) { mdns_action_t * action = NULL; @@ -135,286 +114,6 @@ static esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet) return ESP_OK; } -/** - * @brief the receive callback of the raw udp api. Packets are received here - * - */ -static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport) -{ - uint8_t i; - while (pb != NULL) { - struct pbuf * this_pb = pb; - pb = pb->next; - this_pb->next = NULL; - - mdns_rx_packet_t * packet = (mdns_rx_packet_t *)malloc(sizeof(mdns_rx_packet_t)); - if (!packet) { - //missed packet - no memory - pbuf_free(this_pb); - continue; - } - - packet->tcpip_if = TCPIP_ADAPTER_IF_MAX; - packet->pb = this_pb; - packet->src_port = rport; - memcpy(&packet->src, raddr, sizeof(ip_addr_t)); - packet->dest.type = packet->src.type; - - if (packet->src.type == IPADDR_TYPE_V4) { - packet->ip_protocol = MDNS_IP_PROTOCOL_V4; - struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN); - packet->dest.u_addr.ip4.addr = iphdr->dest.addr; - } else { - packet->ip_protocol = MDNS_IP_PROTOCOL_V6; - struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN); - memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16); - } - packet->multicast = ip_addr_ismulticast(&(packet->dest)); - - //lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces) - struct netif * netif = NULL; - void * nif = NULL; - struct udp_pcb * pcb = NULL; - for (i=0; iinterfaces[i].pcbs[packet->ip_protocol].pcb; - tcpip_adapter_get_netif (i, &nif); - netif = (struct netif *)nif; - if (pcb && netif && netif == ip_current_input_netif ()) { - if (packet->src.type == IPADDR_TYPE_V4) { - if ((packet->src.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr) != (netif->ip_addr.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr)) { - //packet source is not in the same subnet - pcb = NULL; - break; - } - } - packet->tcpip_if = i; - break; - } - pcb = NULL; - } - - if (!pcb || !_mdns_server || !_mdns_server->action_queue - || _mdns_send_rx_action(packet) != ESP_OK) { - pbuf_free(this_pb); - free(packet); - } - } -} - -/** - * @brief Stop PCB Main code - */ -static void _udp_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) -{ - if (!_mdns_server) { - return; - } - mdns_pcb_t * _pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol]; - if (_pcb->pcb) { - _pcb->state = PCB_OFF; - udp_recv(_pcb->pcb, NULL, NULL); - udp_disconnect(_pcb->pcb); - udp_remove(_pcb->pcb); - free(_pcb->probe_services); - _pcb->pcb = NULL; - _pcb->probe_ip = false; - _pcb->probe_services = NULL; - _pcb->probe_services_len = 0; - _pcb->probe_running = false; - _pcb->failed_probes = 0; - } -} - -/** - * @brief Start PCB V4 - */ -static esp_err_t _udp_pcb_v4_init(tcpip_adapter_if_t tcpip_if) -{ - tcpip_adapter_ip_info_t if_ip_info; - - if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb) { - return ESP_ERR_INVALID_STATE; - } - - if (tcpip_adapter_get_ip_info(tcpip_if, &if_ip_info) || if_ip_info.ip.addr == 0) { - return ESP_ERR_INVALID_ARG; - } - - ip_addr_t interface_addr = IPADDR4_INIT(if_ip_info.ip.addr); - - ip_addr_t multicast_addr; - IP_ADDR4(&multicast_addr, 224, 0, 0, 251); - - if (igmp_joingroup((const struct ip4_addr *)&interface_addr.u_addr.ip4, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) { - return ESP_ERR_INVALID_STATE; - } - - struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V4); - if (!pcb) { - return ESP_ERR_NO_MEM; - } - - if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) { - udp_remove(pcb); - return ESP_ERR_INVALID_STATE; - } - - pcb->mcast_ttl = 1; - pcb->remote_port = MDNS_SERVICE_PORT; - ip_addr_copy(pcb->multicast_ip, interface_addr); - ip_addr_copy(pcb->remote_ip, multicast_addr); - - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb = pcb; - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].failed_probes = 0; - udp_recv(pcb, &_udp_recv, _mdns_server); - - return ESP_OK; -} - -/** - * @brief Start PCB V6 - */ -static esp_err_t _udp_pcb_v6_init(tcpip_adapter_if_t tcpip_if) -{ - ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000); - ip_addr_t interface_addr; - interface_addr.type = IPADDR_TYPE_V6; - - if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb) { - return ESP_ERR_INVALID_STATE; - } - - if (tcpip_adapter_get_ip6_linklocal(tcpip_if, &interface_addr.u_addr.ip6)) { - return ESP_ERR_INVALID_ARG; - } - - if (mld6_joingroup(&(interface_addr.u_addr.ip6), &(multicast_addr.u_addr.ip6))) { - return ESP_ERR_INVALID_STATE; - } - - struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V6); - if (!pcb) { - return ESP_ERR_NO_MEM; - } - - if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) { - udp_remove(pcb); - return ESP_ERR_INVALID_STATE; - } - - pcb->remote_port = MDNS_SERVICE_PORT; - ip_addr_copy(pcb->remote_ip, multicast_addr); - - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb = pcb; - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].failed_probes = 0; - udp_recv(pcb, &_udp_recv, _mdns_server); - - return ESP_OK; -} - -/** - * @brief Start PCB Main code - */ -static esp_err_t _udp_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) -{ - if (ip_protocol == MDNS_IP_PROTOCOL_V4) { - return _udp_pcb_v4_init(tcpip_if); - } else if (ip_protocol == MDNS_IP_PROTOCOL_V6) { - return _udp_pcb_v6_init(tcpip_if); - } - return ESP_ERR_INVALID_ARG; -} - -typedef struct { - struct tcpip_api_call call; - tcpip_adapter_if_t tcpip_if; - mdns_ip_protocol_t ip_protocol; - esp_err_t err; -} mdns_api_call_t; - -/** - * @brief Start PCB from LwIP thread - */ -static err_t _mdns_pcb_init_api(struct tcpip_api_call *api_call_msg) -{ - mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg; - msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol); - return msg->err; -} - -/** - * @brief Start PCB - */ -static esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) -{ - mdns_api_call_t msg = { - .tcpip_if = tcpip_if, - .ip_protocol = ip_protocol - }; - tcpip_api_call(_mdns_pcb_init_api, (struct tcpip_api_call*)&msg); - return msg.err; -} - -/** - * @brief Stop PCB from LwIP thread - */ -static err_t _mdns_pcb_deinit_api(struct tcpip_api_call *api_call_msg) -{ - mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg; - _udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol); - msg->err = ESP_OK; - return ESP_OK; -} - -/** - * @brief Stop PCB - */ -static esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) -{ - mdns_api_call_t msg = { - .tcpip_if = tcpip_if, - .ip_protocol = ip_protocol - }; - tcpip_api_call(_mdns_pcb_deinit_api, (struct tcpip_api_call*)&msg); - return msg.err; -} - - -/** - * @brief send packet over UDP - * - * @param server The server - * @param data byte array containing the packet data - * @param len length of the packet data - * - * @return length of sent packet or 0 on error - */ -static size_t _udp_pcb_write(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len) -{ -#ifndef MDNS_TEST_MODE - struct netif * netif = NULL; - void * nif = NULL; - esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif); - netif = (struct netif *)nif; - if (err) { - return 0; - } - - struct pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (pbt == NULL) { - return 0; - } - memcpy((uint8_t *)pbt->payload, data, len); - - err = udp_sendto_if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb, pbt, ip, port, netif); - pbuf_free(pbt); - if (err) { - return 0; - } -#endif - return len; -} - /** * @brief Get the service name of a service */ @@ -1235,7 +934,7 @@ static void _mdns_dispatch_tx_packet(mdns_tx_packet_t * p) mdns_debug_packet(packet, index); #endif - _udp_pcb_write(p->tcpip_if, p->ip_protocol, &p->dst, p->port, packet, index); + _mdns_udp_pcb_write(p->tcpip_if, p->ip_protocol, &p->dst, p->port, packet, index); } /** @@ -4192,7 +3891,6 @@ static esp_err_t _mdns_stop_timer(){ */ static esp_err_t _mdns_service_task_start() { -#ifndef MDNS_TEST_MODE if (!_mdns_service_semaphore) { _mdns_service_semaphore = xSemaphoreCreateMutex(); if (!_mdns_service_semaphore) { @@ -4212,8 +3910,6 @@ static esp_err_t _mdns_service_task_start() } } MDNS_SERVICE_UNLOCK(); -#endif - return ESP_OK; } @@ -4225,7 +3921,6 @@ static esp_err_t _mdns_service_task_start() */ static esp_err_t _mdns_service_task_stop() { -#ifndef MDNS_TEST_MODE MDNS_SERVICE_LOCK(); _mdns_stop_timer(); if (_mdns_service_task_handle) { @@ -4241,7 +3936,6 @@ static esp_err_t _mdns_service_task_stop() } } MDNS_SERVICE_UNLOCK(); -#endif return ESP_OK; } diff --git a/components/mdns/mdns_networking.c b/components/mdns/mdns_networking.c new file mode 100644 index 000000000..e4ab816de --- /dev/null +++ b/components/mdns/mdns_networking.c @@ -0,0 +1,284 @@ + +/* + * MDNS Server Networking + * + */ +#include +#include "mdns_networking.h" + + +extern mdns_server_t * _mdns_server; + +/* + * MDNS Server Networking + * + */ + +/** + * @brief the receive callback of the raw udp api. Packets are received here + * + */ +static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport) +{ + + uint8_t i; + while (pb != NULL) { + struct pbuf * this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + + mdns_rx_packet_t * packet = (mdns_rx_packet_t *)malloc(sizeof(mdns_rx_packet_t)); + if (!packet) { + //missed packet - no memory + pbuf_free(this_pb); + continue; + } + + packet->tcpip_if = TCPIP_ADAPTER_IF_MAX; + packet->pb = this_pb; + packet->src_port = rport; + memcpy(&packet->src, raddr, sizeof(ip_addr_t)); + packet->dest.type = packet->src.type; + + if (packet->src.type == IPADDR_TYPE_V4) { + packet->ip_protocol = MDNS_IP_PROTOCOL_V4; + struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN); + packet->dest.u_addr.ip4.addr = iphdr->dest.addr; + } else { + packet->ip_protocol = MDNS_IP_PROTOCOL_V6; + struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN); + memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16); + } + packet->multicast = ip_addr_ismulticast(&(packet->dest)); + + //lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces) + struct netif * netif = NULL; + void * nif = NULL; + struct udp_pcb * pcb = NULL; + for (i=0; iinterfaces[i].pcbs[packet->ip_protocol].pcb; + tcpip_adapter_get_netif (i, &nif); + netif = (struct netif *)nif; + if (pcb && netif && netif == ip_current_input_netif ()) { + if (packet->src.type == IPADDR_TYPE_V4) { + if ((packet->src.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr) != (netif->ip_addr.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr)) { + //packet source is not in the same subnet + pcb = NULL; + break; + } + } + packet->tcpip_if = i; + break; + } + pcb = NULL; + } + + if (!pcb || !_mdns_server || !_mdns_server->action_queue + || _mdns_send_rx_action(packet) != ESP_OK) { + pbuf_free(this_pb); + free(packet); + } + } + +} + +/** + * @brief Stop PCB Main code + */ +static void _udp_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + if (!_mdns_server) { + return; + } + mdns_pcb_t * _pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol]; + if (_pcb->pcb) { + _pcb->state = PCB_OFF; + udp_recv(_pcb->pcb, NULL, NULL); + udp_disconnect(_pcb->pcb); + udp_remove(_pcb->pcb); + free(_pcb->probe_services); + _pcb->pcb = NULL; + _pcb->probe_ip = false; + _pcb->probe_services = NULL; + _pcb->probe_services_len = 0; + _pcb->probe_running = false; + _pcb->failed_probes = 0; + } +} + +/** + * @brief Start PCB V4 + */ +static esp_err_t _udp_pcb_v4_init(tcpip_adapter_if_t tcpip_if) +{ + tcpip_adapter_ip_info_t if_ip_info; + + if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb) { + return ESP_ERR_INVALID_STATE; + } + + if (tcpip_adapter_get_ip_info(tcpip_if, &if_ip_info) || if_ip_info.ip.addr == 0) { + return ESP_ERR_INVALID_ARG; + } + + ip_addr_t interface_addr = IPADDR4_INIT(if_ip_info.ip.addr); + + ip_addr_t multicast_addr; + IP_ADDR4(&multicast_addr, 224, 0, 0, 251); + + if (igmp_joingroup((const struct ip4_addr *)&interface_addr.u_addr.ip4, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) { + return ESP_ERR_INVALID_STATE; + } + + struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V4); + if (!pcb) { + return ESP_ERR_NO_MEM; + } + + if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) { + udp_remove(pcb); + return ESP_ERR_INVALID_STATE; + } + + pcb->mcast_ttl = 1; + pcb->remote_port = MDNS_SERVICE_PORT; + ip_addr_copy(pcb->multicast_ip, interface_addr); + ip_addr_copy(pcb->remote_ip, multicast_addr); + + _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb = pcb; + _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].failed_probes = 0; + udp_recv(pcb, &_udp_recv, _mdns_server); + + return ESP_OK; +} + +/** + * @brief Start PCB V6 + */ +static esp_err_t _udp_pcb_v6_init(tcpip_adapter_if_t tcpip_if) +{ + ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000); + ip_addr_t interface_addr; + interface_addr.type = IPADDR_TYPE_V6; + + if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb) { + return ESP_ERR_INVALID_STATE; + } + + if (tcpip_adapter_get_ip6_linklocal(tcpip_if, &interface_addr.u_addr.ip6)) { + return ESP_ERR_INVALID_ARG; + } + + if (mld6_joingroup(&(interface_addr.u_addr.ip6), &(multicast_addr.u_addr.ip6))) { + return ESP_ERR_INVALID_STATE; + } + + struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V6); + if (!pcb) { + return ESP_ERR_NO_MEM; + } + + if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) { + udp_remove(pcb); + return ESP_ERR_INVALID_STATE; + } + + pcb->remote_port = MDNS_SERVICE_PORT; + ip_addr_copy(pcb->remote_ip, multicast_addr); + + _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb = pcb; + _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].failed_probes = 0; + udp_recv(pcb, &_udp_recv, _mdns_server); + + return ESP_OK; +} + +/** + * @brief Start PCB Main code + */ +static esp_err_t _udp_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + if (ip_protocol == MDNS_IP_PROTOCOL_V4) { + return _udp_pcb_v4_init(tcpip_if); + } else if (ip_protocol == MDNS_IP_PROTOCOL_V6) { + return _udp_pcb_v6_init(tcpip_if); + } + return ESP_ERR_INVALID_ARG; +} + +typedef struct { + struct tcpip_api_call call; + tcpip_adapter_if_t tcpip_if; + mdns_ip_protocol_t ip_protocol; + esp_err_t err; +} mdns_api_call_t; + +/** + * @brief Start PCB from LwIP thread + */ +static err_t _mdns_pcb_init_api(struct tcpip_api_call *api_call_msg) +{ + mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg; + msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol); + return msg->err; +} + +/** + * @brief Stop PCB from LwIP thread + */ +static err_t _mdns_pcb_deinit_api(struct tcpip_api_call *api_call_msg) +{ + mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg; + _udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol); + msg->err = ESP_OK; + return ESP_OK; +} + +/* + * Non-static functions below are + * - _mdns prefixed + * - commented in mdns_networking.h header + */ +esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_api_call_t msg = { + .tcpip_if = tcpip_if, + .ip_protocol = ip_protocol + }; + tcpip_api_call(_mdns_pcb_init_api, (struct tcpip_api_call*)&msg); + return msg.err; +} + +esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_api_call_t msg = { + .tcpip_if = tcpip_if, + .ip_protocol = ip_protocol + }; + tcpip_api_call(_mdns_pcb_deinit_api, (struct tcpip_api_call*)&msg); + return msg.err; +} + +size_t _mdns_udp_pcb_write(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len) +{ + struct netif * netif = NULL; + void * nif = NULL; + esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif); + netif = (struct netif *)nif; + if (err) { + return 0; + } + + struct pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pbt == NULL) { + return 0; + } + memcpy((uint8_t *)pbt->payload, data, len); + + err = udp_sendto_if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb, pbt, ip, port, netif); + pbuf_free(pbt); + if (err) { + return 0; + } + return len; +} diff --git a/components/mdns/private_include/mdns_networking.h b/components/mdns/private_include/mdns_networking.h new file mode 100644 index 000000000..5b56f8066 --- /dev/null +++ b/components/mdns/private_include/mdns_networking.h @@ -0,0 +1,52 @@ +#ifndef ESP_MDNS_NETWORKING_H_ +#define ESP_MDNS_NETWORKING_H_ + +/* + * MDNS Server Networking -- private include + * + */ +#include "mdns.h" +#include "mdns_private.h" +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "lwip/ip_addr.h" +#include "lwip/pbuf.h" +#include "lwip/igmp.h" +#include "lwip/udp.h" +#include "lwip/mld6.h" +#include "lwip/priv/tcpip_priv.h" +#include "esp_wifi.h" +#include "esp_system.h" +#include "esp_timer.h" +#include "esp_event_loop.h" + + +/** + * @brief Queue RX packet action + */ +esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet); + +/** + * @brief Start PCB + */ +esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); + +/** + * @brief Stop PCB + */ +esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); + +/** + * @brief send packet over UDP + * + * @param server The server + * @param data byte array containing the packet data + * @param len length of the packet data + * + * @return length of sent packet or 0 on error + */ +size_t _mdns_udp_pcb_write(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len); + +#endif /* ESP_MDNS_NETWORKING_H_ */ diff --git a/components/mdns/test_afl_fuzz_host/Makefile b/components/mdns/test_afl_fuzz_host/Makefile index 65a318ef2..61bedc520 100644 --- a/components/mdns/test_afl_fuzz_host/Makefile +++ b/components/mdns/test_afl_fuzz_host/Makefile @@ -1,17 +1,25 @@ TEST_NAME=test FUZZ=afl-fuzz -CC=afl-clang-fast +COMPONENTS_DIR=../.. +CFLAGS=-g -DMDNS_TEST_MODE -I. -I.. -I../include -I../private_include -I$(COMPONENTS_DIR)/tcpip_adapter/include -I$(COMPONENTS_DIR)/esp32/include -include esp32_compat.h +MDNS_C_DEPENDENCY_INJECTION=-include mdns_di.h +ifeq ($(INSTR),off) + CC=gcc + CFLAGS+=-DINSTR_IS_OFF + TEST_NAME=test_sim +else + CC=afl-clang-fast +endif CPP=$(CC) LD=$(CC) -OBJECTS=mdns.o test.o -CFLAGS=-DMDNS_TEST_MODE -I. -I../include +OBJECTS=mdns.o esp32_mock.o test.o OS := $(shell uname) ifeq ($(OS),Darwin) LDLIBS= else - LDLIBS=-lbsd - CFLAGS+=-DUSE_BSD_STRING + LDLIBS=-lbsd + CFLAGS+=-DUSE_BSD_STRING endif all: $(TEST_NAME) @@ -22,11 +30,11 @@ all: $(TEST_NAME) mdns.o: ../mdns.c @echo "[CC] $<" - @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) $(CFLAGS) $(MDNS_C_DEPENDENCY_INJECTION) -c $< -o $@ $(TEST_NAME): $(OBJECTS) @echo "[LD] $@" - @$(LD) $(LDLIBS) $(OBJECTS) -o $@ + @$(LD) $(OBJECTS) -o $@ $(LDLIBS) fuzz: $(TEST_NAME) @$(FUZZ) -i "in" -o "out" -- ./$(TEST_NAME) diff --git a/components/mdns/test_afl_fuzz_host/esp32_compat.h b/components/mdns/test_afl_fuzz_host/esp32_compat.h index fd21b2365..402807c4f 100644 --- a/components/mdns/test_afl_fuzz_host/esp32_compat.h +++ b/components/mdns/test_afl_fuzz_host/esp32_compat.h @@ -17,6 +17,12 @@ #ifdef MDNS_TEST_MODE +// Not to include +#define ESP_MDNS_NETWORKING_H_ +#define _TCPIP_ADAPTER_H_ +#define __ESP_EVENT_H__ + + #ifdef USE_BSD_STRING #include #endif @@ -28,6 +34,7 @@ #include #include + #define ERR_OK 0 #define ESP_OK 0 #define ESP_FAIL -1 @@ -44,21 +51,26 @@ #define pdTRUE true #define pdFALSE false +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) #define portMAX_DELAY 0xFFFFFFFF #define portTICK_PERIOD_MS 1 #define xSemaphoreTake(s,d) +#define xTaskDelete(a) +#define vTaskDelete(a) free(a) #define xSemaphoreGive(s) +#define _mdns_pcb_init(a,b) true +#define _mdns_pcb_deinit(a,b) true #define xSemaphoreCreateMutex() malloc(1) #define vSemaphoreDelete(s) free(s) -#define xQueueCreate(n,s) malloc((n)*(s)) -#define vQueueDelete(q) free(q) -#define xQueueReceive(q, d, t) (ESP_OK) -#define vTaskDelay(m) usleep((m)*1000) +#define xTaskCreatePinnedToCore(a,b,c,d,e,f,g) *(f) = malloc(1) +#define vTaskDelay(m) usleep((m)*0) #define pbuf_free(p) free(p) - -#define tcpip_adapter_get_ip_info(i,d) +#define esp_random() (rand()%UINT32_MAX) +#define tcpip_adapter_get_ip_info(i,d) true +#define tcpip_adapter_dhcpc_get_status(a, b) TCPIP_ADAPTER_DHCP_STARTED #define tcpip_adapter_get_ip6_linklocal(i,d) (ESP_OK) #define tcpip_adapter_get_hostname(i, n) *(n) = "esp32-0123456789AB" @@ -67,17 +79,31 @@ ((uint32_t)((c) & 0xff) << 16) | \ ((uint32_t)((b) & 0xff) << 8) | \ (uint32_t)((a) & 0xff) +#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6)) +#define ip_2_ip4(ipaddr) (&((ipaddr)->u_addr.ip4)) + +#define IPADDR_TYPE_V4 0U +#define IPADDR_TYPE_V6 6U +#define IPADDR_TYPE_ANY 46U +#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0) +#define IP_ADDR4(ipaddr,a,b,c,d) do { IP4_ADDR(ip_2_ip4(ipaddr),a,b,c,d); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V4); } while(0) +#define IP_ADDR6(ipaddr,i0,i1,i2,i3) do { IP6_ADDR(ip_2_ip6(ipaddr),i0,i1,i2,i3); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V6); } while(0) + +#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } } }, IPADDR_TYPE_V6 } + typedef int32_t esp_err_t; typedef void * xSemaphoreHandle; +typedef void * SemaphoreHandle_t; typedef void * xQueueHandle; +typedef void * QueueHandle_t; +typedef void * TaskHandle_t; +typedef void * esp_timer_handle_t; +typedef uint32_t TickType_t; +typedef uint32_t portTickType; -typedef enum { - TCPIP_ADAPTER_IF_STA = 0, /**< ESP32 station interface */ - TCPIP_ADAPTER_IF_AP, /**< ESP32 soft-AP interface */ - TCPIP_ADAPTER_IF_ETH, /**< ESP32 ethernet interface */ - TCPIP_ADAPTER_IF_MAX -} tcpip_adapter_if_t; typedef enum { WIFI_MODE_NULL = 0, /**< null mode */ @@ -87,6 +113,42 @@ typedef enum { WIFI_MODE_MAX } wifi_mode_t; +/* status of DHCP client or DHCP server */ +typedef enum { + TCPIP_ADAPTER_DHCP_INIT = 0, /**< DHCP client/server in initial state */ + TCPIP_ADAPTER_DHCP_STARTED, /**< DHCP client/server already been started */ + TCPIP_ADAPTER_DHCP_STOPPED, /**< DHCP client/server already been stopped */ + TCPIP_ADAPTER_DHCP_STATUS_MAX +} tcpip_adapter_dhcp_status_t; + +typedef enum { + SYSTEM_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */ + SYSTEM_EVENT_SCAN_DONE, /**< ESP32 finish scanning AP */ + SYSTEM_EVENT_STA_START, /**< ESP32 station start */ + SYSTEM_EVENT_STA_STOP, /**< ESP32 station stop */ + SYSTEM_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */ + SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ + SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */ + SYSTEM_EVENT_STA_GOT_IP, /**< ESP32 station got IP from connected AP */ + SYSTEM_EVENT_STA_LOST_IP, /**< ESP32 station lost IP and the IP is reset to 0 */ + SYSTEM_EVENT_STA_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */ + SYSTEM_EVENT_AP_START, /**< ESP32 soft-AP start */ + SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ + SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */ + SYSTEM_EVENT_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */ + SYSTEM_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */ + SYSTEM_EVENT_GOT_IP6, /**< ESP32 station or ap or ethernet interface v6IP addr is preferred */ + SYSTEM_EVENT_ETH_START, /**< ESP32 ethernet start */ + SYSTEM_EVENT_ETH_STOP, /**< ESP32 ethernet stop */ + SYSTEM_EVENT_ETH_CONNECTED, /**< ESP32 ethernet phy link up */ + SYSTEM_EVENT_ETH_DISCONNECTED, /**< ESP32 ethernet phy link down */ + SYSTEM_EVENT_ETH_GOT_IP, /**< ESP32 ethernet got IP from connected AP */ + SYSTEM_EVENT_MAX +} system_event_id_t; + struct udp_pcb { uint8_t dummy; }; @@ -101,27 +163,76 @@ struct ip6_addr { }; typedef struct ip6_addr ip6_addr_t; +typedef struct _ip_addr { + union { + ip6_addr_t ip6; + ip4_addr_t ip4; + } u_addr; + uint8_t type; +} ip_addr_t; + typedef struct { ip4_addr_t ip; ip4_addr_t netmask; ip4_addr_t gw; } tcpip_adapter_ip_info_t; +// typedef int32_t system_event_id_t; +typedef enum { + TCPIP_ADAPTER_IF_STA = 0, /**< ESP32 station interface */ + TCPIP_ADAPTER_IF_AP, /**< ESP32 soft-AP interface */ + TCPIP_ADAPTER_IF_ETH, /**< ESP32 ethernet interface */ + TCPIP_ADAPTER_IF_MAX +} tcpip_adapter_if_t; + +typedef struct { + ip6_addr_t ip; +} tcpip_adapter_ip6_info_t; +typedef struct { + tcpip_adapter_if_t if_index; + tcpip_adapter_ip6_info_t ip6_info; +} system_event_got_ip6_t; +typedef union { + system_event_got_ip6_t got_ip6; /**< ESP32 station or ap or ethernet ipv6 addr state change to preferred */ +} system_event_info_t; + +typedef struct { + system_event_id_t event_id; /**< event ID */ + system_event_info_t event_info; /**< event information */ +} system_event_t; + inline esp_err_t esp_wifi_get_mode(wifi_mode_t * mode) { *mode = WIFI_MODE_APSTA; return ESP_OK; } -inline uint32_t xTaskGetTickCount() -{ - struct timeval tv; - struct timezone tz; - if (gettimeofday(&tv, &tz) == 0) { - return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); - } - return 0; -} +struct pbuf { + struct pbuf *next; + void *payload; + uint16_t tot_len; + uint16_t len; + uint8_t /*pbuf_type*/ type; + uint8_t flags; + uint16_t ref; +}; + +#define IP_GET_TYPE(ipaddr) ((ipaddr)->type) +#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6) +#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr) +#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3];}while(0) + +#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), *ip_2_ip4(&(src))); }}while(0) + +#include "esp32_mock.h" + +uint32_t xTaskGetTickCount(); + #endif //MDNS_TEST_MODE diff --git a/components/mdns/test_afl_fuzz_host/esp32_mock.c b/components/mdns/test_afl_fuzz_host/esp32_mock.c new file mode 100644 index 000000000..aa9ca7f72 --- /dev/null +++ b/components/mdns/test_afl_fuzz_host/esp32_mock.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include "esp32_compat.h" + +void* g_queue; +int g_queue_send_shall_fail = 0; +int g_size = 0; + +esp_err_t esp_timer_delete(esp_timer_handle_t timer) +{ + return ESP_OK; +} + +esp_err_t esp_timer_stop(esp_timer_handle_t timer) +{ + return ESP_OK; +} + +esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period) +{ + return ESP_OK; +} + +esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args, + esp_timer_handle_t* out_handle) +{ + return ESP_OK; +} + +uint32_t xTaskGetTickCount() +{ + struct timeval tv; + struct timezone tz; + if (gettimeofday(&tv, &tz) == 0) { + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + } + return 0; +} + +/// Queue mock + QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize ) + { + g_size = uxItemSize; + g_queue = malloc((uxQueueLength)*(uxItemSize)); + return g_queue; + } + + +void vQueueDelete( QueueHandle_t xQueue ) +{ + free(xQueue); +} + +uint32_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait) +{ + if (g_queue_send_shall_fail) + { + return pdFALSE; + } + else + { + memcpy(xQueue, pvItemToQueue, g_size); + return pdPASS; + } +} + + +uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) +{ + return pdFALSE; +} + +void GetLastItem(void *pvBuffer) +{ + memcpy(pvBuffer, g_queue, g_size); +} + +void ForceTaskDelete() +{ + g_queue_send_shall_fail = 1; +} diff --git a/components/mdns/test_afl_fuzz_host/esp32_mock.h b/components/mdns/test_afl_fuzz_host/esp32_mock.h new file mode 100644 index 000000000..7246e2968 --- /dev/null +++ b/components/mdns/test_afl_fuzz_host/esp32_mock.h @@ -0,0 +1,45 @@ +#ifndef ESP32_MOCK_H_ +#define ESP32_MOCK_H_ + +typedef void (*esp_timer_cb_t)(void* arg); + +typedef enum +{ + ESP_TIMER_TASK, //!< Callback is called from timer task +} esp_timer_dispatch_t; + +typedef struct +{ + esp_timer_cb_t callback; //!< Function to call when timer expires + void* arg; //!< Argument to pass to the callback + esp_timer_dispatch_t dispatch_method; //!< Call the callback from task or from ISR + const char* name; //!< Timer name, used in esp_timer_dump function +} esp_timer_create_args_t; + +esp_err_t esp_timer_delete(esp_timer_handle_t timer); + +esp_err_t esp_timer_stop(esp_timer_handle_t timer); + +esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period); + +esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args, + esp_timer_handle_t* out_handle); + + +// Queue mock + QueueHandle_t xQueueCreate( uint32_t uxQueueLength, + uint32_t uxItemSize ); + +void vQueueDelete( QueueHandle_t xQueue ); + +uint32_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait); + +uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait); + +void GetLastItem(void *pvBuffer); + +void ForceTaskDelete(); + +#define _mdns_udp_pcb_write(tcpip_if, ip_protocol, ip, port, data, len) len + +#endif /* ESP32_MOCK_H_ */ \ No newline at end of file diff --git a/components/mdns/test_afl_fuzz_host/mdns_di.h b/components/mdns/test_afl_fuzz_host/mdns_di.h new file mode 100644 index 000000000..05aeb8bd5 --- /dev/null +++ b/components/mdns/test_afl_fuzz_host/mdns_di.h @@ -0,0 +1,53 @@ +/* + * MDNS Dependecy injection -- preincluded to inject interface test functions into static variables + * + */ + +#include "mdns.h" +#include "mdns_private.h" + +void (*mdns_test_static_execute_action)(mdns_action_t *) = NULL; +mdns_srv_item_t * (*mdns_test_static_mdns_get_service_item)(const char * service, const char * proto) = NULL; +mdns_search_once_t * (*mdns_test_static_search_init)(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results) = NULL; +esp_err_t (*mdns_test_static_send_search_action)(mdns_action_type_t type, mdns_search_once_t * search) = NULL; +void (*mdns_test_static_search_free)(mdns_search_once_t * search) = NULL; + +static void _mdns_execute_action(mdns_action_t * action); +static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto); +static mdns_search_once_t * _mdns_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results); +static esp_err_t _mdns_send_search_action(mdns_action_type_t type, mdns_search_once_t * search); +static void _mdns_search_free(mdns_search_once_t * search); + +void mdns_test_init_di() +{ + mdns_test_static_execute_action = _mdns_execute_action; + mdns_test_static_mdns_get_service_item = _mdns_get_service_item; + mdns_test_static_search_init = _mdns_search_init; + mdns_test_static_send_search_action = _mdns_send_search_action; + mdns_test_static_search_free = _mdns_search_free; +} + +void mdns_test_execute_action(void * action) +{ + mdns_test_static_execute_action((mdns_action_t *)action); +} + +void mdns_test_search_free(mdns_search_once_t * search) +{ + return mdns_test_static_search_free(search); +} + +esp_err_t mdns_test_send_search_action(mdns_action_type_t type, mdns_search_once_t * search) +{ + return mdns_test_static_send_search_action(type, search); +} + +mdns_search_once_t * mdns_test_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results) +{ + return mdns_test_static_search_init(name, service, proto, type, timeout, max_results); +} + +mdns_srv_item_t * mdns_test_mdns_get_service_item(const char * service, const char * proto) +{ + return mdns_test_static_mdns_get_service_item(service, proto); +} \ No newline at end of file diff --git a/components/mdns/test_afl_fuzz_host/test.c b/components/mdns/test_afl_fuzz_host/test.c index be06ac0bf..8ea72d95c 100644 --- a/components/mdns/test_afl_fuzz_host/test.c +++ b/components/mdns/test_afl_fuzz_host/test.c @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifdef MDNS_TEST_MODE - #include #include #include @@ -21,93 +19,210 @@ #include #include "mdns.h" +#include "mdns_private.h" -void mdns_parse_packet(mdns_server_t * server, const uint8_t * data, size_t len); +// +// Global stuctures containing packet payload, search +mdns_rx_packet_t g_packet; +struct pbuf mypbuf; +mdns_search_once_t * search = NULL; +// +// Dependency injected test functions +void mdns_test_execute_action(void * action); +mdns_srv_item_t * mdns_test_mdns_get_service_item(const char * service, const char * proto); +mdns_search_once_t * mdns_test_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results); +esp_err_t mdns_test_send_search_action(mdns_action_type_t type, mdns_search_once_t * search); +void mdns_test_search_free(mdns_search_once_t * search); +void mdns_test_init_di(); + +// +// mdns function wrappers for mdns setup in test mode +static int mdns_test_hostname_set(const char * mdns_hostname) +{ + int ret = mdns_hostname_set(mdns_hostname); + mdns_action_t * a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + +static int mdns_test_service_instance_name_set(const char * service, const char * proto, const char * instance) +{ + int ret = mdns_service_instance_name_set(service, proto, instance); + mdns_action_t * a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + +static int mdns_test_service_txt_set(const char * service, const char * proto, uint8_t num_items, mdns_txt_item_t txt[]) +{ + int ret = mdns_service_txt_set(service, proto, txt, num_items); + mdns_action_t * a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + +static int mdns_test_service_add(const char * service_name, const char * proto, uint32_t port) +{ + if (mdns_service_add(NULL, service_name, proto, port, NULL, 0)) { + // This is expected failure as the service thread is not running + } + mdns_action_t * a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + + if (mdns_test_mdns_get_service_item(service_name, proto)==NULL) { + return ESP_FAIL; + } + return ESP_OK; +} + +static mdns_result_t* mdns_test_query(const char * service_name, const char * proto) +{ + search = mdns_test_search_init(NULL, service_name, proto, MDNS_TYPE_PTR, 3000, 20); + if (!search) { + abort(); + } + + if (mdns_test_send_search_action(ACTION_SEARCH_ADD, search)) { + mdns_test_search_free(search); + abort(); + } + + mdns_action_t * a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return NULL; +} + +static void mdns_test_query_free() +{ + mdns_test_search_free(search); +} + +// +// function "under test" where afl-mangled packets passed +// +void mdns_parse_packet(mdns_rx_packet_t * packet); + +// +// Test starts here +// int main(int argc, char** argv) { + int i; const char * mdns_hostname = "minifritz"; const char * mdns_instance = "Hristo's Time Capsule"; - const char * arduTxtData[4] = { - "board=esp32", - "tcp_check=no", - "ssh_upload=no", - "auth_upload=no" + mdns_txt_item_t arduTxtData[4] = { + {"board","esp32"}, + {"tcp_check","no"}, + {"ssh_upload","no"}, + {"auth_upload","no"} }; + const uint8_t mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x32}; - mdns_server_t * mdns = NULL; uint8_t buf[1460]; char winstance[21+strlen(mdns_hostname)]; sprintf(winstance, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", mdns_hostname, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - if (mdns_init(TCPIP_ADAPTER_IF_ETH, &mdns)) { + // Init depencency injected methods + mdns_test_init_di(); + + if (mdns_init()) { abort(); } - if (mdns_set_hostname(mdns, mdns_hostname)) { + if (mdns_test_hostname_set(mdns_hostname)) { abort(); } - if (mdns_set_instance(mdns, mdns_instance)) { + if (mdns_test_service_add("_workstation", "_tcp", 9)) { + abort(); + } + if (mdns_test_service_instance_name_set("_workstation", "_tcp", winstance)) { abort(); } - if (mdns_service_add(mdns, "_workstation", "_tcp", 9)) { + if (mdns_test_service_add("_arduino", "_tcp", 3232)) { abort(); } - if (mdns_service_instance_set(mdns, "_workstation", "_tcp", winstance)) { + if (mdns_test_service_txt_set("_arduino", "_tcp", 4, arduTxtData)) { abort(); } - if (mdns_service_add(mdns, "_arduino", "_tcp", 3232)) { + if (mdns_test_service_add("_http", "_tcp", 80)) { abort(); } - if (mdns_service_txt_set(mdns, "_arduino", "_tcp", 4, arduTxtData)) { - abort(); - } - - if (mdns_service_add(mdns, "_http", "_tcp", 80)) { - abort(); - } - - if (mdns_service_instance_set(mdns, "_http", "_tcp", "ESP WebServer")) { + if (mdns_test_service_instance_name_set("_http", "_tcp", "ESP WebServer")) { abort(); } if ( - mdns_service_add(mdns, "_afpovertcp", "_tcp", 548) - || mdns_service_add(mdns, "_rfb", "_tcp", 885) - || mdns_service_add(mdns, "_smb", "_tcp", 885) - || mdns_service_add(mdns, "_adisk", "_tcp", 885) - || mdns_service_add(mdns, "_airport", "_tcp", 885) - || mdns_service_add(mdns, "_printer", "_tcp", 885) - || mdns_service_add(mdns, "_airplay", "_tcp", 885) - || mdns_service_add(mdns, "_raop", "_tcp", 885) - || mdns_service_add(mdns, "_uscan", "_tcp", 885) - || mdns_service_add(mdns, "_uscans", "_tcp", 885) - || mdns_service_add(mdns, "_ippusb", "_tcp", 885) - || mdns_service_add(mdns, "_scanner", "_tcp", 885) - || mdns_service_add(mdns, "_ipp", "_tcp", 885) - || mdns_service_add(mdns, "_ipps", "_tcp", 885) - || mdns_service_add(mdns, "_pdl-datastream", "_tcp", 885) - || mdns_service_add(mdns, "_ptp", "_tcp", 885) - || mdns_service_add(mdns, "_sleep-proxy", "_udp", 885)) + mdns_test_service_add("_afpovertcp", "_tcp", 548) + || mdns_test_service_add("_rfb", "_tcp", 885) + || mdns_test_service_add("_smb", "_tcp", 885) + || mdns_test_service_add("_adisk", "_tcp", 885) + || mdns_test_service_add("_airport", "_tcp", 885) + || mdns_test_service_add("_printer", "_tcp", 885) + || mdns_test_service_add("_airplay", "_tcp", 885) + || mdns_test_service_add("_raop", "_tcp", 885) + || mdns_test_service_add("_uscan", "_tcp", 885) + || mdns_test_service_add("_uscans", "_tcp", 885) + || mdns_test_service_add("_ippusb", "_tcp", 885) + || mdns_test_service_add("_scanner", "_tcp", 885) + || mdns_test_service_add("_ipp", "_tcp", 885) + || mdns_test_service_add("_ipps", "_tcp", 885) + || mdns_test_service_add("_pdl-datastream", "_tcp", 885) + || mdns_test_service_add("_ptp", "_tcp", 885) + || mdns_test_service_add("_sleep-proxy", "_udp", 885)) { - abort(); + abort(); + } + + mdns_result_t * results = NULL; + FILE *file; + size_t nread; + +#ifdef INSTR_IS_OFF + size_t len = 1460; + 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; + } + else + { + // + // 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); } + for (i=0; i<1; i++) { +#else while (__AFL_LOOP(1000)) { memset(buf, 0, 1460); size_t len = read(0, buf, 1460); - mdns_query(mdns, "_afpovertcp", "_tcp", 0); - mdns_parse_packet(mdns, buf, len); - mdns_query_end(mdns); +#endif + mypbuf.payload = buf; + mypbuf.len = len; + g_packet.pb = &mypbuf; + mdns_test_query("_afpovertcp", "_tcp"); + mdns_parse_packet(&g_packet); } + ForceTaskDelete(); + mdns_free(); return 0; } - -#endif From fffbf7b75065b5852e064e04b0c5102dd0fc2244 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 22 May 2018 11:10:27 +0200 Subject: [PATCH 2/2] Fixed nullptr dereference in MDNS.c --- components/mdns/mdns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 73c5f99c9..8ead7c44d 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -2269,7 +2269,7 @@ static bool _mdns_question_matches(mdns_parsed_question_t * question, uint16_t t } } else if (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT) { const char * name = _mdns_get_service_instance_name(service->service); - if (name && !strcasecmp(name, question->host) + if (name && question->host && !strcasecmp(name, question->host) && !strcasecmp(service->service->service, question->service) && !strcasecmp(service->service->proto, question->proto) && !strcasecmp(MDNS_DEFAULT_DOMAIN, question->domain)) {