The generated code does not contain code of a complete function.
reach token limitation
contain grammatical errors such as mismatched brackets which corrupts the function code
...
// ERROR: incomplete function
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size == 0) {
return 0;
}
isc_buffer_t source_buffer;
isc_buffer_t target_buffer;
dns_decompress_t dctx;
dns_name_t name;
isc_result_t result;
// Initialize source buffer with the input data
isc_buffer_init(&source_buffer, Data, Size);
isc_buffer_add(&source_buffer, Size);
The generated code violates the basic programming language rules.
variable redefinition
parentheses mismatch
incomplete expression
define function inside a function in C language
missing break statement in a loop or switch statement
initializer element is not a compile-time constant
...
// ERROR: definition of output_callback in a function is not allowed
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size == 0 || Data == NULL)
return 0;
// Ensure the input is a null-terminated string
uint8_t *null_terminated_data = (uint8_t *)malloc(Size + 1);
if (null_terminated_data == NULL)
return 0;
memcpy(null_terminated_data, Data, Size);
null_terminated_data[Size] = '\0';
// Define the callback function
void output_callback(const MD_CHAR *output, MD_SIZE output_size, void *userdata) {
(void)userdata; // Unused
fwrite(output, 1, output_size, stdout);
}
// Call the md_html function with the fuzzed input
int result = md_html((const MD_CHAR *)null_terminated_data, Size, output_callback, NULL, 0, 0);
// Clean up
free(null_terminated_data);
return result;
}
The generated code refers non-existing entities such as variables, macros, types, functions, header files, etc.
use of undeclared identifier
no member named xxx in struct yyy
unknown type name
field designator xxx does not refer to any field in type yyy
referred header file not found
// ERROR: use of undeclared identifier 'MAX_INPUT_SIZE'
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// Initialize necessary structures for fuzzing
lou_init();
// Limit the input size to prevent potential DoS attacks
if (Size > MAX_INPUT_SIZE) {
return 0;
}
// Ensure the input is null-terminated
uint8_t *NullTerminatedData = malloc(Size + 1);
if (!NullTerminatedData) {
return 0;
}
memcpy(NullTerminatedData, Data, Size);
NullTerminatedData[Size] = '\0';
// Call the target function with the fuzzed data
int Result = lou_compileString((const char *)NullTerminatedData);
// Cleanup
free(NullTerminatedData);
lou_free();
// Return the result
return Result;
}
The generated code made grammatical errors due to the unsupported usage on certain types.
mismatch on the number of function arguments
incompatible type conversion
assigning to type A from incompatible type B
misuse of "->" and "." when referencing members of a structure
operations such as offsetof of incomplete defined structure
...
// ERROR: too few arguments to function call "lou_compileString", expected 2, have 1
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size == 0 || Data == NULL)
return 0;
// Ensure null-termination of input string
uint8_t *null_terminated_data = (uint8_t *)malloc(Size + 1);
if (null_terminated_data == NULL)
return 0;
memcpy(null_terminated_data, Data, Size);
null_terminated_data[Size] = '\0';
// Call the function to be fuzzed
int result = lou_compileString((const char *)null_terminated_data);
// Free allocated memory
free(null_terminated_data);
return 0;
}
The generated code either misses the necessary input size check or applies an incorrect condition.
absense of the necessary input size check
incorrect checks on input data
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// First, we need to make sure the size of the input data is at least the size of a stun_buffer
// ERROR: the condition is incorrect, correct one should be >, this incorrect condition results in the fuzzing coverage never increase since the sizeof(stun_buffer) is a quite large value.
if (Size < sizeof(stun_buffer)) {
return 0;
}
// Allocate memory for the stun_buffer struct
stun_buffer* buf = (stun_buffer*) malloc(sizeof(stun_buffer));
// Copy the input data into the stun_buffer struct
memcpy(buf, Data, sizeof(stun_buffer));
// Call the stun_is_binding_response function with the fuzzed input data
int result = stun_is_binding_response(buf);
// Free the allocated memory
free(buf);
return 0;
}
The generated code incorrectly initializes (no grammar error) the arguments required for an API used in the driver. This includes passing incorrect literal values to the arguments working as options, using wrong sets of APIs to initialize an argument, etc.
passing an argument with incorrect inner status (missing APIs or using wrong APIs to initialize the argument)
passing arguments with wrong enumeration literal
incorrect initialization of a struct
The generated code:
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
isc_result_t result;
isc_buffer_t buffer;
isc_mem_t *mctx;
dns_name_t top, origin;
dns_rdatacallbacks_t callbacks;
dns_rdataclass_t zclass = dns_rdataclass_in;
unsigned int options = 0;
// Initialize memory context
isc_mem_create(&mctx);
// Initialize buffer with input data
isc_buffer_init(&buffer, Data, Size);
isc_buffer_add(&buffer, Size);
// Initialize top and origin names
dns_name_init(&top, NULL);
dns_name_init(&origin, NULL);
// Initialize callbacks
dns_rdatacallbacks_init(&callbacks);
// Call dns_master_loadbuffer with the fuzzed data
result = dns_master_loadbuffer(&buffer, &top, &origin, zclass, options, &callbacks, mctx);
// Cleanup
dns_name_invalidate(&top);
dns_name_invalidate(&origin);
isc_mem_destroy(&mctx);
return 0; // Non-zero return values are reserved for future use
}
The simplified runtime crash stack:
#4 in raise
#5 in abort
#6 in isc_assertion_failed /src/bind9/lib/isc/assertions.c:50:2
#7 in mem_create /src/bind9/lib/isc/mem.c:473:2
#8 in isc__mem_create /src/bind9/lib/isc/mem.c:1763:2
#9 in LLVMFuzzerTestOneInput
The error line:
isc_mem_t *mctx;
...
isc_mem_create(&mctx);
Root cause:
The mctx should be initialized as NULL value.
The generated code does not properly implement the control dependencies of an used API function. This includes incomplete implementation of the control dependencies and incorrect implementation.
missing control flow dependencies such as missing NULL value check before passing an argument
missing API calls for setting up execution context such as libxxx_init()
the conditions inside the control flow are inaccurate/incomplete
The following is one driver generated by the model. The code itself can run correctly however it misses the necessary APIs to setup a standby server to test the whole workflow. Besides, to effectively test the parsing logic, the Data should be passed from the standby server thread.
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size < 4) {
return 0;
}
modbus_t *ctx = NULL;
uint16_t addr = (Data[0] << 8) | Data[1];
uint16_t nb = (Data[2] << 8) | Data[3];
// Cap the number of bits to read to avoid excessive memory allocation.
if (nb > 1024) {
nb = 1024;
}
uint8_t *dest = (uint8_t *)malloc(nb * sizeof(uint8_t));
if (!dest) {
return 0;
}
ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1);
if (!ctx) {
free(dest);
return 0;
}
// Connect to the slave device.
if (modbus_connect(ctx) == -1) {
modbus_free(ctx);
free(dest);
return 0;
}
// Fuzz modbus_read_bits with the input data.
modbus_read_bits(ctx, addr, nb, dest);
// Cleanup.
modbus_close(ctx);
modbus_free(ctx);
free(dest);
return 0;
}
The generated code does not properly clean the resources it allocated.
missing cleaning of the allocated resources such as malloced variables
erroneous cleaning code such as calling free without checking NULL value or double free, etc
// ERROR: the following code missing the call of "dwarf_finish", resulting in memory leak
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int dw_fd = 0;
unsigned int dw_groupnumber = 0;
Dwarf_Handler dw_errhand = 0;
Dwarf_Ptr dw_errarg = 0;
Dwarf_Debug dw_dbg = 0;
Dwarf_Error dw_error = 0;
// Create temporary file for fuzzing
char tmp_file_name[] = "/tmp/fuzzed_dwarf_XXXXXX";
dw_fd = mkstemp(tmp_file_name);
if (dw_fd == -1) {
perror("Error creating temporary file");
return 0;
}
// Write fuzz data to the temporary file
if (write(dw_fd, Data, Size) != Size) {
perror("Error writing to temporary file");
close(dw_fd);
unlink(tmp_file_name);
return 0;
}
// Seek to the beginning of the file
lseek(dw_fd, 0, SEEK_SET);
// Call the target function
int result = dwarf_init_b(dw_fd, dw_groupnumber, dw_errhand, dw_errarg, &dw_dbg, &dw_error);
// Clean up and close the temporary file
close(dw_fd);
unlink(tmp_file_name);
// Check if the function call was successful
if (result == DW_DLV_OK) {
// Perform any necessary operations here, e.g.:
// dwarf_finish(dw_dbg, &dw_error);
// Return non-zero to indicate success
return 1;
} else {
// Return zero to indicate failure
return 0;
}
}
The generated code failed on code related with common practices such as the usage on functions from standard libraries.
overflow or underflow offset when accessing buffer
messing up memory operations such as memcpy
incorrect usage on file operations such as passing read-only buffer to mkstemp
...
// ERROR: the driver will meet heap-buffer-overflow since it directly access the first four bytes of Data in the code. However, the size of Data buffer can be less than 4 bytes.
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size == 0) {
return 0;
}
const char *data = (const char *)Data;
LYD_FORMAT format;
uint32_t parse_options;
uint32_t validate_options;
struct lyd_node *tree = NULL;
struct ly_ctx *ctx;
// Initialize the context
if (ly_ctx_new(NULL, 0, &ctx) != LY_SUCCESS) {
return 0;
}
// Choose a format based on the first byte of the input data
switch (data[0] % 3) {
case 0:
format = LYD_XML;
break;
case 1:
format = LYD_JSON;
break;
case 2:
default:
format = LYD_LYB;
break;
}
// Set parse and validate options based on the input data
// ERROR LINE, the size of data buffer can be less than 4 bytes
parse_options = ((uint32_t)data[1]) << 24 | ((uint32_t)data[2]) << 16 | ((uint32_t)data[3]) << 8 | (uint32_t)data[4];
validate_options = ((uint32_t)data[5]) << 24 | ((uint32_t)data[6]) << 16 | ((uint32_t)data[7]) << 8 | (uint32_t)data[8];
// Call the function to be fuzzed
lyd_parse_data_mem(ctx, data, format, parse_options, validate_options, &tree);
// Clean up resources
lyd_free_tree(tree);
ly_ctx_destroy(ctx);
return 0;
}