mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-27 00:00:07 -06:00
Split networking code into its own target (#2091)
This commit is contained in:
141
src/net/libslirp/fuzzing/slirp_fuzz_tcp_data.c
vendored
Normal file
141
src/net/libslirp/fuzzing/slirp_fuzz_tcp_data.c
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/libslirp.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;
|
||||
uint32_t ipsource;
|
||||
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 + 16) {
|
||||
ipsource = * (uint32_t*) (ip_data + 12);
|
||||
|
||||
// This an answer, which we will produce, so don't mutate
|
||||
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude packets that are not TCP from the mutation strategy
|
||||
if (ip_data[9] != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
// Allocate a bit more than needed, this is useful for
|
||||
// checksum calculation.
|
||||
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
|
||||
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||
|
||||
// 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 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_tcp = ip_data + ip_hl_in_bytes;
|
||||
uint8_t tcp_header_size = 4 * (*(start_of_tcp + 12) >> 4);
|
||||
uint8_t *start_of_data = ip_data + ip_hl_in_bytes + tcp_header_size;
|
||||
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
|
||||
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
|
||||
uint16_t tcp_data_size = (tcp_size - (uint16_t)tcp_header_size);
|
||||
|
||||
// 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 tcp_size inside the fuzzing code, maybe use the
|
||||
// rec->incl_len and manually calculate the size.
|
||||
if (tcp_data_size > MaxSize || tcp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - tcp_header_size)
|
||||
return 0;
|
||||
|
||||
// Copy interesting data to the `Data_to_mutate` array
|
||||
// here we want to fuzz everything in the tcp packet
|
||||
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
|
||||
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||
|
||||
// Call to libfuzzer's mutation function.
|
||||
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||
// so the packet isn't rejected.
|
||||
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||
// Fixme: allow to change the size of the TCP packet, this will require
|
||||
// to fix the size before calculating the new checksum and change
|
||||
// how the Data_ptr is advanced.
|
||||
// Most offsets bellow should be good for when the switch will be
|
||||
// done to avoid overwriting new/mutated data.
|
||||
LLVMFuzzerMutate(Data_to_mutate + tcp_header_size, tcp_data_size, tcp_data_size);
|
||||
|
||||
// Set the `checksum` field to 0 to calculate the new checksum
|
||||
|
||||
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)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 + tcp_size, ip_data + 12, 4*2);
|
||||
|
||||
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
|
||||
|
||||
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
|
||||
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
|
||||
|
||||
uint16_t new_checksum =
|
||||
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
|
||||
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||
|
||||
// Copy the mutated data back to the `Data` array
|
||||
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated)
|
||||
return 0;
|
||||
|
||||
return Size;
|
||||
}
|
||||
#endif // CUSTOM_MUTATOR
|
Reference in New Issue
Block a user