From: Peter Hull <peterhull90@gmail.com>
Date: Mon, 14 Jun 2021 21:43:17 +0100
Applied-Upstream: https://github.com/liballeg/allegro5/commit/cca179bc16827f358153060cd10ac73d394e758c
Subject: PCX loader validation

Validate bytes_per_line.

Validate palette
---
 addons/image/pcx.c |  5 ++++
 addons/image/tga.c | 86 ++++++++++++++++++++++++++++++++----------------------
 2 files changed, 56 insertions(+), 35 deletions(-)

diff --git a/addons/image/pcx.c b/addons/image/pcx.c
index d9464ea..08016e4 100644
--- a/addons/image/pcx.c
+++ b/addons/image/pcx.c
@@ -54,6 +54,11 @@ ALLEGRO_BITMAP *_al_load_pcx_f(ALLEGRO_FILE *f, int flags)
    }
 
    bytes_per_line = al_fread16le(f);
+   /* It can only be this because we only support 8 bit planes */
+   if (bytes_per_line != width) {
+      ALLEGRO_ERROR("Invalid bytes per line %d\n", bytes_per_line);
+      return NULL;
+   }
 
    for (c = 0; c < 60; c++)                /* skip some more junk */
       al_fgetc(f);
diff --git a/addons/image/tga.c b/addons/image/tga.c
index 38b5800..374f8de 100644
--- a/addons/image/tga.c
+++ b/addons/image/tga.c
@@ -271,6 +271,7 @@ static unsigned short *rle_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
    return b;
 }
 
+typedef unsigned char palette_entry[3];
 
 /* Like load_tga, but starts loading from the current place in the ALLEGRO_FILE
  *  specified. If successful the offset into the file will be left just after
@@ -280,10 +281,12 @@ static unsigned short *rle_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
  */
 ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
 {
-   unsigned char image_id[256], image_palette[256][3];
+   unsigned char image_id[256];
+   palette_entry image_palette[256];
    unsigned char id_length, palette_type, image_type, palette_entry_size;
    unsigned char bpp, descriptor_bits;
    short unsigned int palette_colors;
+   short unsigned int palette_start;
    short unsigned int image_width, image_height;
    bool left_to_right;
    bool top_to_bottom;
@@ -299,7 +302,7 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
    id_length = al_fgetc(f);
    palette_type = al_fgetc(f);
    image_type = al_fgetc(f);
-   al_fread16le(f); /* first_color */
+   palette_start = al_fread16le(f); /* first_color */
    palette_colors  = al_fread16le(f);
    palette_entry_size = al_fgetc(f);
    al_fread16le(f); /* left */
@@ -314,35 +317,6 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
 
    al_fread(f, image_id, id_length);
 
-   if (palette_type == 1) {
-
-      for (i = 0; i < palette_colors; i++) {
-
-         switch (palette_entry_size) {
-
-            case 16:
-               c = al_fread16le(f);
-               image_palette[i][0] = (c & 0x1F) << 3;
-               image_palette[i][1] = ((c >> 5) & 0x1F) << 3;
-               image_palette[i][2] = ((c >> 10) & 0x1F) << 3;
-               break;
-
-            case 24:
-            case 32:
-               image_palette[i][0] = al_fgetc(f);
-               image_palette[i][1] = al_fgetc(f);
-               image_palette[i][2] = al_fgetc(f);
-               if (palette_entry_size == 32)
-                  al_fgetc(f);
-               break;
-         }
-      }
-   }
-   else if (palette_type != 0) {
-      ALLEGRO_ERROR("Invalid palette type %d.\n", palette_type);
-      return NULL;
-   }
-
    /* Image type:
     *    0 = no image data
     *    1 = uncompressed color mapped
@@ -364,7 +338,9 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
 
       case 1:
          /* paletted image */
-         if ((palette_type != 1) || (bpp != 8)) {
+         /* Only support 8 bit palettes (up to 256 entries) though in principle the file format could have more(?)*/
+         if ((palette_type != 1) || (bpp != 8) || (palette_start + palette_colors) > 256) {
+            ALLEGRO_ERROR("Invalid palette/image/bpp combination %d/%d/%d.\n", image_type, palette_type, bpp);
             return NULL;
          }
 
@@ -402,6 +378,38 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
          return NULL;
    }
 
+   if (palette_type == 0) {
+      /* No-op */
+   } else if (palette_type == 1) {
+      for (i = 0; i < palette_colors; i++) {
+         palette_entry *entry = image_palette + palette_start + i;
+         switch (palette_entry_size) {
+            case 16:
+               c = al_fread16le(f);
+               (*entry)[0] = (c & 0x1F) << 3;
+               (*entry)[1] = ((c >> 5) & 0x1F) << 3;
+               (*entry)[2] = ((c >> 10) & 0x1F) << 3;
+               break;
+            case 24:
+               (*entry)[0] = al_fgetc(f);
+               (*entry)[1] = al_fgetc(f);
+               (*entry)[2] = al_fgetc(f);
+               break;
+            case 32:
+               (*entry)[0] = al_fgetc(f);
+               (*entry)[1] = al_fgetc(f);
+               (*entry)[2] = al_fgetc(f);
+               al_fgetc(f); /* Ignore 4th byte (alpha) */
+               break;
+         }
+      }
+   }
+   else  {
+      ALLEGRO_ERROR("Invalid palette type %d.\n", palette_type);
+      return NULL;
+   }
+
+
    bmp = al_create_bitmap(image_width, image_height);
    if (!bmp) {
       ALLEGRO_ERROR("Failed to create bitmap.\n");
@@ -452,9 +460,17 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
 
                unsigned char *dest = (unsigned char *)lr->data +
                   lr->pitch*true_y + true_x*4;
-               dest[0] = image_palette[pix][2];
-               dest[1] = image_palette[pix][1];
-               dest[2] = image_palette[pix][0];
+               if (pix < palette_start || pix >= (palette_start + palette_colors)) {
+                  al_free(buf);
+                  al_unlock_bitmap(bmp);
+                  al_destroy_bitmap(bmp);
+                  ALLEGRO_ERROR("Invalid image data.\n");
+                  return NULL;
+               }
+               palette_entry* entry = image_palette + pix;
+               dest[0] = (*entry)[2];
+               dest[1] = (*entry)[1];
+               dest[2] = (*entry)[0];
                dest[3] = 255;
             }
 
