diff --git a/kitty/graphics.c b/kitty/graphics.c index c06cfe695..ad5679448 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -23,6 +23,7 @@ #include "png-reader.h" PyTypeObject GraphicsManager_Type; +#define MAX_IMAGE_DIMENSION 10000u #define DEFAULT_STORAGE_LIMIT 320u * (1024u * 1024u) #define REPORT_ERROR(...) { log_error(__VA_ARGS__); } #define RAII_CoalescedFrameData(name, initializer) __attribute__((cleanup(cfd_free))) CoalescedFrameData name = initializer @@ -380,7 +381,7 @@ png_error_handler(png_read_data *d UNUSED, const char *code, const char *msg) { static bool inflate_png(LoadData *load_data, uint8_t *buf, size_t bufsz) { png_read_data d = {.err_handler=png_error_handler}; - inflate_png_inner(&d, buf, bufsz); + inflate_png_inner(&d, buf, bufsz, MAX_IMAGE_DIMENSION); if (d.ok) { free_load_data(load_data); load_data->buf = d.decompressed; @@ -415,7 +416,7 @@ print_png_read_error(png_read_data *d, const char *code, const char* msg) { bool png_from_data(void *png_data, size_t png_data_sz, const char *path_for_error_messages, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz) { png_read_data d = {.err_handler=print_png_read_error}; - inflate_png_inner(&d, png_data, png_data_sz); + inflate_png_inner(&d, png_data, png_data_sz, MAX_IMAGE_DIMENSION); if (!d.ok) { log_error("Failed to decode PNG image at: %s with error: %s", path_for_error_messages, d.error.used > 0 ? d.error.buf : ""); free(d.decompressed); free(d.row_pointers); free(d.error.buf); @@ -693,7 +694,6 @@ initialize_load_data(GraphicsManager *self, const GraphicsCommand *g, Image *img tt = g->transmission_type ? g->transmission_type : 'd'; \ fmt = g->format ? g->format : RGBA; \ } -#define MAX_IMAGE_DIMENSION 10000u static void upload_to_gpu(GraphicsManager *self, Image *img, const bool is_opaque, const bool is_4byte_aligned, const uint8_t *data) { diff --git a/kitty/png-reader.c b/kitty/png-reader.c index 740d5eab0..4fcd2c6d4 100644 --- a/kitty/png-reader.c +++ b/kitty/png-reader.c @@ -47,7 +47,7 @@ read_png_warn_handler(png_structp UNUSED png_ptr, png_const_charp msg) { #define ABRT(code, msg) { if(d->err_handler) d->err_handler(d, #code, msg); goto err; } void -inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz) { +inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz, int max_image_dimension) { struct fake_file f = {.buf = buf, .sz = bufsz}; png_structp png = NULL; png_infop info = NULL; @@ -64,6 +64,10 @@ inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz) { png_byte color_type, bit_depth; d->width = png_get_image_width(png, info); d->height = png_get_image_height(png, info); + // libpng uses too much memory for overly large images + if (d->width > max_image_dimension || d->height > max_image_dimension) { + ABRT(ENOMEM, "PNG image is too large"); + } color_type = png_get_color_type(png, info); bit_depth = png_get_bit_depth(png, info); double image_gamma; @@ -208,7 +212,7 @@ load_png_data(PyObject *self UNUSED, PyObject *args) { const char *data; if (!PyArg_ParseTuple(args, "s#", &data, &sz)) return NULL; png_read_data d = {.err_handler=png_error_handler}; - inflate_png_inner(&d, (const uint8_t*)data, sz); + inflate_png_inner(&d, (const uint8_t*)data, sz, 10000); PyObject *ans = NULL; if (d.ok && !PyErr_Occurred()) { ans = Py_BuildValue("y#ii", d.decompressed, (int)d.sz, d.width, d.height); diff --git a/kitty/png-reader.h b/kitty/png-reader.h index 4d6175333..b0eeeb72d 100644 --- a/kitty/png-reader.h +++ b/kitty/png-reader.h @@ -27,5 +27,5 @@ typedef struct png_read_data { } error; } png_read_data; -void inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz); +void inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz, int max_image_dimension); const char* png_from_32bit_rgba(uint32_t *data, size_t width, size_t height, size_t *out_size, bool flip_vertically);