hl2sdk/thirdparty/libspng/tests/spng_write_fuzzer.c
2025-02-19 18:36:16 -05:00

184 lines
4.2 KiB
C

#include "../spng/spng.h"
#include <string.h>
struct buf_state
{
const uint8_t *data;
size_t bytes_left;
};
static int stream_write_fn(spng_ctx *ctx, void *user, void *data, size_t length)
{
struct buf_state *state = (struct buf_state*)user;
(void)ctx;
if(length > state->bytes_left) return SPNG_IO_EOF;
state->bytes_left -= length;
if(state->data)
{
memcpy(data, state->data, length);
state->data += length;
}
return 0;
}
#define copy_val(val) \
if(size < sizeof(val)) goto err; \
memcpy(&val, data, sizeof(val)); \
data += sizeof(val); \
size -= sizeof(val)
#ifdef __cplusplus
extern "C"
#endif
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
uint8_t params[4];
if(size < sizeof(params)) return 0;
memcpy(params, data, sizeof(params));
size -= sizeof(params);
data += sizeof(params);
//int flags = params[0];
int fmt = params[2] | (params[1] << 8);
int stream = params[3] & 1;
int progressive = params[3] & 2;
//int file_stream = params[3] & 4;
int get_buffer = params[3] & 8;
int ret;
size_t png_size = 0;
void *png = NULL;
struct buf_state state;
unsigned char *img = NULL;
size_t img_size;
size_t pixel_bits = 0;
spng_ctx *ctx = spng_ctx_new(SPNG_CTX_ENCODER);
if(ctx == NULL) return 0;
spng_set_image_limits(ctx, 200000, 200000);
spng_set_chunk_limits(ctx, 4 * 1000 * 1000, 8 * 1000 * 1000);
state.data = NULL;
state.bytes_left = SIZE_MAX;
spng_set_option(ctx, SPNG_IMG_COMPRESSION_LEVEL, 0);
if(stream) ret = spng_set_png_stream(ctx, stream_write_fn, &state);
else ret = spng_set_option(ctx, SPNG_ENCODE_TO_BUFFER, 1);
if(ret) goto err;
struct spng_ihdr ihdr;
struct spng_plte plte;
struct spng_trns trns;
struct spng_chrm chrm;
struct spng_chrm_int chrm_int;
double gamma;
struct spng_sbit sbit;
uint8_t srgb_rendering_intent;
struct spng_bkgd bkgd;
struct spng_hist hist;
struct spng_phys phys;
struct spng_time time;
copy_val(ihdr);
copy_val(plte);
copy_val(trns);
copy_val(chrm);
copy_val(chrm_int);
copy_val(gamma);
copy_val(sbit);
copy_val(srgb_rendering_intent);
copy_val(bkgd);
copy_val(hist);
copy_val(phys);
copy_val(time);
if(spng_set_ihdr(ctx, &ihdr)) goto err;
spng_set_plte(ctx, &plte);
spng_set_trns(ctx, &trns);
spng_set_chrm(ctx, &chrm);
spng_set_chrm_int(ctx, &chrm_int);
spng_set_gama(ctx, gamma);
spng_set_sbit(ctx, &sbit);
spng_set_srgb(ctx, srgb_rendering_intent);
spng_set_bkgd(ctx, &bkgd);
spng_set_hist(ctx, &hist);
spng_set_phys(ctx, &phys);
spng_set_time(ctx, &time);
switch(ihdr.color_type)
{
case SPNG_COLOR_TYPE_GRAYSCALE:
case SPNG_COLOR_TYPE_INDEXED:
pixel_bits = ihdr.bit_depth;
break;
case SPNG_COLOR_TYPE_TRUECOLOR:
pixel_bits = ihdr.bit_depth * 3;
break;
case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA:
pixel_bits = ihdr.bit_depth * 2;
break;
case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA:
pixel_bits = ihdr.bit_depth * 4;
break;
default: goto err;
}
img_size = ihdr.width * pixel_bits + 7;
img_size /= 8;
img_size *= ihdr.height;
if(img_size > size) goto err;
if(img_size > 80000000) goto err;
img = (unsigned char*)data;
if(progressive)
{
if(spng_encode_image(ctx, NULL, 0, fmt, SPNG_ENCODE_PROGRESSIVE | SPNG_ENCODE_FINALIZE)) goto err;
size_t ioffset, img_width = img_size / ihdr.height;
struct spng_row_info ri;
do
{
if(spng_get_row_info(ctx, &ri)) break;
ioffset = ri.row_num * img_width;
}while(!spng_encode_row(ctx, img + ioffset, img_size));
}
else if(spng_encode_image(ctx, img, img_size, fmt, SPNG_ENCODE_FINALIZE)) goto err;
if(get_buffer)
{
png = spng_get_png_buffer(ctx, &png_size, &ret);
// These are potential vulnerabilities
if(png && !png_size) return 1;
if(!png && png_size) return 1;
if(ret && (png || png_size)) return 1;
}
err:
spng_ctx_free(ctx);
free(png);
return 0;
}