From 01c0bad5d4e1af8a3ab8672bc150643e83b860ac Mon Sep 17 00:00:00 2001 From: Hayaki Saito Date: Sun, 22 Jul 2018 02:38:14 +0900 Subject: [PATCH] Prevent stack-buffer-overflow reported in #71 https://github.com/saitoha/libsixel/issues/71 --- src/frompnm.c | 103 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 20 deletions(-) diff --git a/src/frompnm.c b/src/frompnm.c index 56e7ca8f..812330d0 100644 --- a/src/frompnm.c +++ b/src/frompnm.c @@ -26,6 +26,9 @@ #include #include +#define PNM_MAX_WIDTH (1 << 16) +#define PNM_MAX_HEIGHT (1 << 16) +#define PNM_MAX_DEPTH (1 << 16) static unsigned char * pnm_get_line(unsigned char *p, unsigned char *end, unsigned char *line) @@ -74,6 +77,7 @@ load_pnm(unsigned char /* in */ *p, int width; int height; int deps; + char message[256]; unsigned char *s; unsigned char *end; unsigned char tmp[256]; @@ -97,72 +101,117 @@ load_pnm(unsigned char /* in */ *p, switch(tmp[1]) { case '1': + /* Portable bitmap - ASCII */ ascii = 1; maps = 0; break; case '2': + /* Portable graymap - ASCII */ ascii = 1; maps = 1; break; case '3': + /* Portable pixmap - ASCII */ ascii = 1; maps = 2; break; case '4': + /* Portable bitmap - Binary */ ascii = 0; maps = 0; break; case '5': + /* Portable graymap - Binary */ ascii = 0; maps = 1; break; case '6': + /* Portable pixmap - Binary */ ascii = 0; maps = 2; break; default: - status = SIXEL_RUNTIME_ERROR; - sixel_helper_set_additional_message( - "load_pnm: unknown ppm format."); - goto end; + goto unknown; } p = pnm_get_line(p, end, tmp); + if (p == end) { + /* check empty content */ + /* Issue 71: https://github.com/saitoha/libsixel/issues/71 */ + goto invalid; + } s = tmp; + + /* parse width */ width = 0; - while (isdigit(*s) && width >= 0) { - width = width * 10 + (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; ++s) { + width = width * 10 + (*s - '0'); + if (width > PNM_MAX_WIDTH) { + status = SIXEL_RUNTIME_ERROR; + sprintf( + message, + "load_pnm: image width exceeds the limit %d.", + PNM_MAX_WIDTH); + sixel_helper_set_additional_message(message); + goto end; + } } + while (*s == ' ') { s++; } + + /* parse height */ height = 0; - while (isdigit(*s) && height >= 0) { - height = height * 10 + (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; ++s) { + height = height * 10 + (*s - '0'); + if (width > PNM_MAX_WIDTH) { + status = SIXEL_RUNTIME_ERROR; + sprintf( + message, + "load_pnm: image height exceeds the limit %d.", + PNM_MAX_HEIGHT); + sixel_helper_set_additional_message(message); + goto end; + } } + while (*s != '\0') { s++; } if (maps > 0) { p = pnm_get_line(p, end, tmp); + if (p == end) { + /* check empty content */ + /* Issue 71: https://github.com/saitoha/libsixel/issues/71 */ + goto invalid; + } s = tmp; deps = 0; - while (isdigit(*s) && deps >= 0) { - deps = deps * 10 + (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; ++s) { + deps = deps * 10 + (*s - '0'); + } + if (width > PNM_MAX_WIDTH) { + status = SIXEL_RUNTIME_ERROR; + sprintf( + message, + "load_pnm: image depth exceeds the limit %d.", + PNM_MAX_DEPTH); + sixel_helper_set_additional_message(message); + goto end; } } if (width < 1 || height < 1 || deps < 1) { - status = SIXEL_RUNTIME_ERROR; - sixel_helper_set_additional_message( - "load_pnm: invalid data detected."); - goto end; + goto invalid; } - *result = (unsigned char *)sixel_allocator_malloc(allocator, - (size_t)(width * height * 3 + 1)); + *result = (unsigned char *)sixel_allocator_malloc( + allocator, + (size_t)(width * height * 3 + 1)); + if (*result == NULL) { sixel_helper_set_additional_message( "load_pnm: sixel_allocator_malloc() failed."); @@ -231,10 +280,7 @@ load_pnm(unsigned char /* in */ *p, component[2] = (component[2] * 255 / deps); break; default: - status = SIXEL_RUNTIME_ERROR; - sixel_helper_set_additional_message( - "load_pnm: unknown ppm format."); - goto end; + goto unknown; } *(*result + (y * width + x) * 3 + 0) = component[0]; @@ -248,6 +294,23 @@ load_pnm(unsigned char /* in */ *p, *ppixelformat = SIXEL_PIXELFORMAT_RGB888; status = SIXEL_OK; + goto end; + +unknown: + status = SIXEL_RUNTIME_ERROR; + sixel_helper_set_additional_message( + "load_pnm: unknown ppm format."); + sixel_allocator_free(allocator, *result); + *result = NULL; + goto end; + +invalid: + status = SIXEL_RUNTIME_ERROR; + sixel_helper_set_additional_message( + "load_pnm: invalid data detected."); + sixel_allocator_free(allocator, *result); + *result = NULL; + goto end; end: return status;