Graphics: Disallow PNGs of size greater than MAX_IMAGE_DIMENSION to match behavior with loading RGB data

This commit is contained in:
Kovid Goyal 2025-11-14 07:58:04 +05:30
parent 9bc29a7fa6
commit d4633bf5f9
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 10 additions and 6 deletions

View file

@ -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) {

View file

@ -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);

View file

@ -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);