mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-06-28 01:49:42 -06:00
135 lines
4.8 KiB
C
135 lines
4.8 KiB
C
#include <glib.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "../src/libslirp.h"
|
|
#include "../src/ip6.h"
|
|
#include "helper.h"
|
|
#include "slirp_base_fuzz.h"
|
|
|
|
#ifdef CUSTOM_MUTATOR
|
|
extern 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);
|
|
|
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
|
size_t MaxSize, unsigned int Seed)
|
|
{
|
|
size_t current_size = Size;
|
|
uint8_t *Data_ptr = Data;
|
|
uint8_t *ip_data;
|
|
bool mutated = false;
|
|
|
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
|
pcaprec_hdr_t *rec = NULL;
|
|
|
|
if (current_size < sizeof(pcap_hdr_t)) {
|
|
return 0;
|
|
}
|
|
|
|
Data_ptr += sizeof(*hdr);
|
|
current_size -= sizeof(*hdr);
|
|
|
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
|
g_debug("FIXME: byteswap fields");
|
|
return 0;
|
|
} /* else assume native pcap file */
|
|
if (hdr->network != 1) {
|
|
return 0;
|
|
}
|
|
|
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
|
rec = (void *)Data_ptr;
|
|
Data_ptr += sizeof(*rec);
|
|
current_size -= sizeof(*rec);
|
|
|
|
if (rec->incl_len != rec->orig_len) {
|
|
return 0;
|
|
}
|
|
if (rec->incl_len > current_size) {
|
|
return 0;
|
|
}
|
|
if (rec->incl_len < 14 + 1) {
|
|
return 0;
|
|
}
|
|
|
|
ip_data = Data_ptr + 14;
|
|
|
|
if (rec->incl_len >= 14 + 24) {
|
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
|
|
|
// This an answer, which we will produce, so don't receive
|
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
|
continue;
|
|
}
|
|
|
|
// Exclude packets that are not ICMP from the mutation strategy
|
|
if (ip_data[6] != IPPROTO_ICMPV6)
|
|
continue;
|
|
|
|
// Allocate a bit more than needed, this is useful for
|
|
// checksum calculation.
|
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
|
|
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
|
// rec->incl_len and manually calculate the size.
|
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
|
return 0;
|
|
|
|
uint8_t *start_of_icmp = ip_data + ip_hl_in_bytes;
|
|
uint16_t icmp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
|
|
|
// The size inside the packet can't be trusted, if it is too big it can
|
|
// lead to heap overflows in the fuzzing code.
|
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
|
// rec->incl_len and manually calculate the size.
|
|
if (icmp_size > MaxSize || icmp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
|
return 0;
|
|
|
|
// Copy interesting data to the `Data_to_mutate` array
|
|
// here we want to fuzz everything in icmp
|
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
|
memcpy(Data_to_mutate, start_of_icmp, icmp_size);
|
|
|
|
// Call to libfuzzer's mutation function.
|
|
// For now we dont want to change the header size as it would require to
|
|
// resize the `Data` array to include the new bytes inside the whole
|
|
// packet.
|
|
// This should be easy as LibFuzzer probably does it by itself or
|
|
// reserved enough space in Data beforehand, needs some research to
|
|
// confirm.
|
|
// FIXME: allow up to grow header size to 60 bytes,
|
|
// requires to update the `header length` before calculating
|
|
// checksum
|
|
LLVMFuzzerMutate(Data_to_mutate, icmp_size, icmp_size);
|
|
|
|
// Set the `checksum` field to 0 and calculate the new checksum
|
|
*(uint16_t *)(Data_to_mutate + 2) = 0;
|
|
// Copy the source and destination IP addresses, the tcp length and
|
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
|
// the new checksum.
|
|
memcpy(Data_to_mutate + icmp_size, ip_data + 8, 16*2);
|
|
|
|
*(Data_to_mutate + icmp_size + 16*2 + 1) = IPPROTO_ICMPV6;
|
|
|
|
*(Data_to_mutate + icmp_size + 16*2 + 2) = (uint8_t)(icmp_size / 256);
|
|
*(Data_to_mutate + icmp_size + 16*2 + 3) = (uint8_t)(icmp_size % 256);
|
|
|
|
uint16_t new_checksum =
|
|
compute_checksum(Data_to_mutate, icmp_size + PSEUDO_IPV6_SIZE);
|
|
*(uint16_t *)(Data_to_mutate + 2) = htons(new_checksum);
|
|
|
|
// Copy the mutated data back to the `Data` array
|
|
memcpy(start_of_icmp, Data_to_mutate, icmp_size);
|
|
|
|
mutated = true;
|
|
}
|
|
|
|
if (!mutated)
|
|
return 0;
|
|
|
|
return Size;
|
|
}
|
|
#endif // CUSTOM_MUTATOR
|