1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <inttypes.h>
#include "jansson.h"
static int enable_diags;
#define FUZZ_DEBUG(FMT, ...) \
if (enable_diags) \
{ \
fprintf(stderr, FMT, ##__VA_ARGS__); \
fprintf(stderr, "\n"); \
}
static int json_dump_counter(const char *buffer, size_t size, void *data)
{
uint64_t *counter = reinterpret_cast<uint64_t *>(data);
*counter += size;
return 0;
}
#define NUM_COMMAND_BYTES (sizeof(size_t) + sizeof(size_t) + 1)
#define FUZZ_DUMP_CALLBACK 0x00
#define FUZZ_DUMP_STRING 0x01
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
json_error_t error;
unsigned char dump_mode;
// Enable or disable diagnostics based on the FUZZ_VERBOSE environment flag.
enable_diags = (getenv("FUZZ_VERBOSE") != NULL);
FUZZ_DEBUG("Input data length: %zd", size);
if (size < NUM_COMMAND_BYTES)
{
return 0;
}
// Use the first sizeof(size_t) bytes as load flags.
size_t load_flags = *(const size_t*)data;
data += sizeof(size_t);
FUZZ_DEBUG("load_flags: 0x%zx\n"
"& JSON_REJECT_DUPLICATES = 0x%zx\n"
"& JSON_DECODE_ANY = 0x%zx\n"
"& JSON_DISABLE_EOF_CHECK = 0x%zx\n"
"& JSON_DECODE_INT_AS_REAL = 0x%zx\n"
"& JSON_ALLOW_NUL = 0x%zx\n",
load_flags,
load_flags & JSON_REJECT_DUPLICATES,
load_flags & JSON_DECODE_ANY,
load_flags & JSON_DISABLE_EOF_CHECK,
load_flags & JSON_DECODE_INT_AS_REAL,
load_flags & JSON_ALLOW_NUL);
// Use the next sizeof(size_t) bytes as dump flags.
size_t dump_flags = *(const size_t*)data;
data += sizeof(size_t);
FUZZ_DEBUG("dump_flags: 0x%zx\n"
"& JSON_MAX_INDENT = 0x%zx\n"
"& JSON_COMPACT = 0x%zx\n"
"& JSON_ENSURE_ASCII = 0x%zx\n"
"& JSON_SORT_KEYS = 0x%zx\n"
"& JSON_PRESERVE_ORDER = 0x%zx\n"
"& JSON_ENCODE_ANY = 0x%zx\n"
"& JSON_ESCAPE_SLASH = 0x%zx\n"
"& JSON_REAL_PRECISION = 0x%zx\n"
"& JSON_EMBED = 0x%zx\n",
dump_flags,
dump_flags & JSON_MAX_INDENT,
dump_flags & JSON_COMPACT,
dump_flags & JSON_ENSURE_ASCII,
dump_flags & JSON_SORT_KEYS,
dump_flags & JSON_PRESERVE_ORDER,
dump_flags & JSON_ENCODE_ANY,
dump_flags & JSON_ESCAPE_SLASH,
((dump_flags >> 11) & 0x1F) << 11,
dump_flags & JSON_EMBED);
// Use the next byte as the dump mode.
dump_mode = data[0];
data++;
FUZZ_DEBUG("dump_mode: 0x%x", (unsigned int)dump_mode);
// Remove the command bytes from the size total.
size -= NUM_COMMAND_BYTES;
// Attempt to load the remainder of the data with the given load flags.
const char* text = reinterpret_cast<const char *>(data);
json_t* jobj = json_loadb(text, size, load_flags, &error);
if (jobj == NULL)
{
return 0;
}
if (dump_mode & FUZZ_DUMP_STRING)
{
// Dump as a string. Remove indents so that we don't run out of memory.
char *out = json_dumps(jobj, dump_flags & ~JSON_MAX_INDENT);
if (out != NULL)
{
free(out);
}
}
else
{
// Default is callback mode.
//
// Attempt to dump the loaded json object with the given dump flags.
uint64_t counter = 0;
json_dump_callback(jobj, json_dump_counter, &counter, dump_flags);
FUZZ_DEBUG("Counter function counted %" PRIu64 " bytes.", counter);
}
if (jobj)
{
json_decref(jobj);
}
return 0;
}
|