#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include /* ---------------- Configuration ---------------- */ #define MAX_INPUT_SIZE (64 * 1024) #define MAX_OUTPUT_SIZE (128 * 1024) #define MAX_STEPS 4096 #define MAX_CONVERSIONS 8 /* Chaos control */ #define CHAOS_PROBABILITY 10 /* % of cases entering chaos mode */ /* Musl-relevant encodings */ static const char *encodings[] = { "UTF-8", "UTF-16LE", "UTF-16BE", "UTF-32LE", "UTF-32BE", "ASCII", "ISO-8859-1", "ISO-8859-15", "UTF-7", "SHIFT_JIS", "EUC-JP", "GB18030", }; #define ENC_COUNT (sizeof(encodings) / sizeof(encodings[0])) /* ---------------- Utilities ---------------- */ static inline uint16_t rd16(const uint8_t *p) { return ((uint16_t)p[0] << 8) | p[1]; } static ssize_t read_file(const char *path, uint8_t *buf, size_t max) { int fd = open(path, O_RDONLY); if (fd < 0) { perror("open"); return -1; } ssize_t total = 0; while (total < (ssize_t)max) { ssize_t r = read(fd, buf + total, max - total); if (r <= 0) break; total += r; } close(fd); return total; } /* ---------------- Main Harness ---------------- */ int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } static uint8_t input[MAX_INPUT_SIZE]; static uint8_t output[MAX_OUTPUT_SIZE]; ssize_t len = read_file(argv[1], input, sizeof(input)); if (len <= 8) return 0; const uint8_t *p = input; const uint8_t *end = input + len; uint8_t gflags = p[0]; uint8_t conv_count = (p[1] % MAX_CONVERSIONS) + 1; uint16_t seed = rd16(p + 2); /* Chaos mode is rare and explicit */ int chaos = ((seed % 100) < CHAOS_PROBABILITY); p += 4; for (uint8_t c = 0; c < conv_count && p + 6 < end; c++) { uint8_t flags = p[0]; uint8_t src_sel = p[1] % ENC_COUNT; uint8_t dst_sel = p[2] % ENC_COUNT; uint16_t in_len = rd16(p + 3); p += 5; if (p + in_len > end) in_len = end - p; /* ---------------- Encoding name fuzzing ---------------- */ const char *src = encodings[src_sel]; const char *dst = encodings[dst_sel]; if (chaos && (flags & 0x80) && p + 1 < end) { src = (const char *)p; } if (chaos && (flags & 0x40) && p + 2 < end) { dst = (const char *)(p + 1); } iconv_t cd = iconv_open(dst, src); if (cd == (iconv_t)-1) { p += in_len; continue; } char *in_ptr = (char *)p; size_t in_left = in_len; char *out_base = (char *)output; size_t out_cap = sizeof(output); /* ---------------- Aliasing abuse ---------------- */ if (chaos && (flags & 0x20) && in_left > 8) { out_base = in_ptr; out_cap = in_left; } char *out_ptr = out_base; size_t out_left = out_cap; size_t steps = 0; size_t last_in_left = in_left; /* ---------------- Conversion loop ---------------- */ while (in_left > 0 && (chaos || steps++ < MAX_STEPS)) { size_t chunk; switch (flags & 0x03) { case 0: chunk = 1; break; case 1: chunk = 2; break; case 2: chunk = 4; break; default: chunk = (seed % 8) + 1; break; } if (chunk > in_left) chunk = in_left; char *tin = in_ptr; size_t tin_left = chunk; char *tout = out_ptr; size_t tout_left = out_left; size_t r = iconv(cd, &tin, &tin_left, &tout, &tout_left); size_t consumed = chunk - tin_left; in_ptr += consumed; in_left -= consumed; out_ptr = tout; out_left = tout_left; if (r == (size_t)-1) { if (errno == E2BIG) { if (flags & 0x04) { out_ptr = out_base; out_left = out_cap; } else if (!chaos) { break; } } else if (errno == EILSEQ || errno == EINVAL) { if (flags & 0x08) { char *d = out_ptr; size_t dl = out_left; iconv(cd, NULL, NULL, &d, &dl); out_ptr = d; out_left = dl; } if (in_left > 0) { in_ptr++; in_left--; } if (!chaos) break; } else { break; } } /* ---------------- Progress guard ---------------- */ if (!chaos) { if (in_left >= last_in_left) break; last_in_left = in_left; } if ((flags & 0x10) && (steps & 0x7) == 0) { char *d = out_ptr; size_t dl = out_left; iconv(cd, NULL, NULL, &d, &dl); out_ptr = d; out_left = dl; } if (flags & 0x20) { char *zin = in_ptr; size_t zleft = 0; iconv(cd, &zin, &zleft, &out_ptr, &out_left); } if (out_left == 0) break; } /* ---------------- Final flush ---------------- */ if (flags & 0x40) { char *d = out_ptr; size_t dl = out_left; iconv(cd, NULL, NULL, &d, &dl); } iconv_close(cd); p += in_len; } /* Global misuse */ if (gflags & 0x80) { iconv_t cd = iconv_open("UTF-8", "UTF-8"); if (cd != (iconv_t)-1) { char *d = (char *)output; size_t dl = sizeof(output); iconv(cd, NULL, NULL, &d, &dl); iconv_close(cd); } } return 0; }