From a4a0ab69d286c7638741e70a11f04fb3d7b49db2 Mon Sep 17 00:00:00 2001
From: Alex Tutubalin <lexa@lexa.ru>
Date: Wed, 11 Mar 2026 11:57:24 +0300
Subject: [PATCH] X3F decoder: implemented hard single allocation limit via
 LIBRAW_X3F_ALLOC_LIMIT_MB define; allocation size calculation converted to 64
 bit arithm; fix for TALOS-2026-2359

---
 libraw/libraw_const.h         |   5 ++
 src/x3f/x3f_utils_patched.cpp | 104 ++++++++++++++++++++--------------
 2 files changed, 68 insertions(+), 41 deletions(-)

Index: LibRaw-0.21.4/libraw/libraw_const.h
===================================================================
--- LibRaw-0.21.4.orig/libraw/libraw_const.h
+++ LibRaw-0.21.4/libraw/libraw_const.h
@@ -54,7 +54,10 @@ it under the terms of the one of two lic
 #define LIBRAW_CR3_MEMPOOL
 #endif
 
-
+/* max data size for known foveon cameras: 30mpix * 3 channels * 2 bytes = 180Mb, so 512Mb is OK for everything until/if new cameras will arrive */
+#ifndef LIBRAW_X3F_ALLOC_LIMIT_MB
+#define LIBRAW_X3F_ALLOC_LIMIT_MB 512ULL
+#endif
 
 /* LibRaw uses own memory pool management, with LIBRAW_MSIZE (512)
 entries. It is enough for parsing/decoding non-damaged files, but
Index: LibRaw-0.21.4/src/x3f/x3f_utils_patched.cpp
===================================================================
--- LibRaw-0.21.4.orig/src/x3f/x3f_utils_patched.cpp
+++ LibRaw-0.21.4/src/x3f/x3f_utils_patched.cpp
@@ -50,6 +50,37 @@ BSD-style License
 /* Reading and writing - assuming little endian in the file              */
 /* --------------------------------------------------------------------- */
 
+static void *x3f_limited_malloc(UINT64 sz)
+{
+  if (sz > LIBRAW_X3F_ALLOC_LIMIT_MB * 1024ULL * 1024ULL)
+    throw LIBRAW_EXCEPTION_TOOBIG;
+  void *ret = malloc(sz);
+  if (!ret)
+    throw LIBRAW_EXCEPTION_ALLOC;
+  return ret;
+}
+
+static void *x3f_limited_calloc(UINT64 n, UINT64 sz)
+{
+  if (sz * n > LIBRAW_X3F_ALLOC_LIMIT_MB * 1024ULL * 1024ULL)
+    throw LIBRAW_EXCEPTION_TOOBIG;
+  void *ret = calloc(n, sz);
+  if (!ret)
+    throw LIBRAW_EXCEPTION_ALLOC;
+  return ret;
+}
+
+static void *x3f_limited_realloc(void *ptr, UINT64 sz)
+{
+  if (sz > LIBRAW_X3F_ALLOC_LIMIT_MB * 1024ULL * 1024ULL)
+    throw LIBRAW_EXCEPTION_TOOBIG;
+  void *ret = realloc(ptr, sz);
+  if (!ret)
+    throw LIBRAW_EXCEPTION_ALLOC;
+  return ret;
+}
+
+
 static int x3f_get1(LibRaw_abstract_datastream *f)
 {
   /* Little endian file */
@@ -134,7 +165,7 @@ unsigned x3f_get4(LibRaw_abstract_datast
     int _i;                                                                    \
     (_T).size = (_NUM);                                                        \
     (_T).element =                                                             \
-        (_TYPE *)realloc((_T).element, (_NUM) * sizeof((_T).element[0]));      \
+        (_TYPE *)x3f_limited_realloc((_T).element, (_NUM) * sizeof((_T).element[0]));      \
     for (_i = 0; _i < (int)(_T).size; _i++)                                         \
       _GETX((_T).element[_i]);                                                 \
   } while (0)
@@ -144,7 +175,7 @@ unsigned x3f_get4(LibRaw_abstract_datast
   {                                                                            \
     int _i;                                                                    \
     (_T).size = (_NUM);                                                        \
-    (_T).element = (x3f_property_t *)realloc(                                  \
+    (_T).element = (x3f_property_t *)x3f_limited_realloc(                                  \
         (_T).element, (_NUM) * sizeof((_T).element[0]));                       \
     for (_i = 0; _i < (int)(_T).size; _i++)                                         \
     {                                                                          \
@@ -161,7 +192,7 @@ unsigned x3f_get4(LibRaw_abstract_datast
     for (_i = 0;; _i++)                                                        \
     {                                                                          \
       (_T).size = _i + 1;                                                      \
-      (_T).element = (x3f_true_huffman_element_t *)realloc(                    \
+      (_T).element = (x3f_true_huffman_element_t *)x3f_limited_realloc(                    \
           (_T).element, (_i + 1) * sizeof((_T).element[0]));                   \
       GET1((_T).element[_i].code_size);                                        \
       GET1((_T).element[_i].code);                                             \
@@ -182,7 +213,7 @@ static void new_huffman_tree(x3f_hufftre
 
   HTP->free_node_index = 0;
   HTP->total_node_index = HUF_TREE_MAX_NODES(leaves);
-  HTP->nodes = (x3f_huffnode_t *)calloc(1, HUF_TREE_MAX_NODES(leaves) *
+  HTP->nodes = (x3f_huffnode_t *)x3f_limited_calloc(1, HUF_TREE_MAX_NODES(leaves) *
                                                sizeof(x3f_huffnode_t));
 }
 
@@ -209,7 +240,7 @@ static void cleanup_true(x3f_true_t **TR
 
 static x3f_true_t *new_true(x3f_true_t **TRUP)
 {
-  x3f_true_t *TRU = (x3f_true_t *)calloc(1, sizeof(x3f_true_t));
+  x3f_true_t *TRU = (x3f_true_t *)x3f_limited_calloc(1, sizeof(x3f_true_t));
 
   cleanup_true(TRUP);
 
@@ -241,7 +272,7 @@ static void cleanup_quattro(x3f_quattro_
 
 static x3f_quattro_t *new_quattro(x3f_quattro_t **QP)
 {
-  x3f_quattro_t *Q = (x3f_quattro_t *)calloc(1, sizeof(x3f_quattro_t));
+  x3f_quattro_t *Q = (x3f_quattro_t *)x3f_limited_calloc(1, sizeof(x3f_quattro_t));
   int i;
 
   cleanup_quattro(QP);
@@ -286,7 +317,7 @@ static void cleanup_huffman(x3f_huffman_
 
 static x3f_huffman_t *new_huffman(x3f_huffman_t **HUFP)
 {
-  x3f_huffman_t *HUF = (x3f_huffman_t *)calloc(1, sizeof(x3f_huffman_t));
+  x3f_huffman_t *HUF = (x3f_huffman_t *)x3f_limited_calloc(1, sizeof(x3f_huffman_t));
 
   cleanup_huffman(HUFP);
 
@@ -317,9 +348,7 @@ static x3f_huffman_t *new_huffman(x3f_hu
   if (!infile)
     return NULL;
   INT64 fsize = infile->size();
-  x3f_t *x3f = (x3f_t *)calloc(1, sizeof(x3f_t));
-  if (!x3f)
-    throw LIBRAW_EXCEPTION_ALLOC;
+  x3f_t *x3f = (x3f_t *)x3f_limited_calloc(1, sizeof(x3f_t));
   try
   {
     x3f_info_t *I = NULL;
@@ -383,7 +412,7 @@ static x3f_huffman_t *new_huffman(x3f_hu
     if (DS->num_directory_entries > 0)
     {
       size_t size = DS->num_directory_entries * sizeof(x3f_directory_entry_t);
-      DS->directory_entry = (x3f_directory_entry_t *)calloc(1, size);
+      DS->directory_entry = (x3f_directory_entry_t *)x3f_limited_calloc(1, size);
     }
 
     /* Traverse the directory */
@@ -1220,15 +1249,8 @@ static uint32_t read_data_block(void **d
 
   if (fpos + size > I->input.file->size())
     throw LIBRAW_EXCEPTION_IO_CORRUPT;
-
-  // All known files from real cameras are many times smaller than 1 GB, so the hard limit is OK here.
-
-  if(size > 1024*1024*1024)
-    throw LIBRAW_EXCEPTION_ALLOC;
-
-  *data = (void *)malloc(size);
-  if (!*data)
-	  throw LIBRAW_EXCEPTION_ALLOC;
+
+  *data = (void *)x3f_limited_malloc(size);
 
   GETN(*data, size);
 
@@ -1363,36 +1385,36 @@ static void x3f_load_true(x3f_info_t *I,
     uint32_t columns = Q->plane[0].columns;
     uint32_t rows = Q->plane[0].rows;
     uint32_t channels = 3;
-    uint32_t size = columns * rows * channels;
+    UINT64 size = UINT64(columns) * UINT64(rows) * UINT64(channels);
 
     TRU->x3rgb16.columns = columns;
     TRU->x3rgb16.rows = rows;
     TRU->x3rgb16.channels = channels;
     TRU->x3rgb16.row_stride = columns * channels;
-    TRU->x3rgb16.buf = malloc(sizeof(uint16_t) * size);
+    TRU->x3rgb16.buf = x3f_limited_malloc(sizeof(uint16_t) * size);
     TRU->x3rgb16.data = (uint16_t *)TRU->x3rgb16.buf;
 
     columns = Q->plane[2].columns;
     rows = Q->plane[2].rows;
     channels = 1;
-    size = columns * rows * channels;
+    size = UINT64(columns) * UINT64(rows) * UINT64(channels);
 
     Q->top16.columns = columns;
     Q->top16.rows = rows;
     Q->top16.channels = channels;
     Q->top16.row_stride = columns * channels;
-    Q->top16.buf = malloc(sizeof(uint16_t) * size);
+    Q->top16.buf = x3f_limited_malloc(sizeof(uint16_t) * size);
     Q->top16.data = (uint16_t *)Q->top16.buf;
   }
   else
   {
-    uint32_t size = ID->columns * ID->rows * 3;
+    UINT64 size = UINT64(ID->columns) * UINT64(ID->rows) * 3ULL;
 
     TRU->x3rgb16.columns = ID->columns;
     TRU->x3rgb16.rows = ID->rows;
     TRU->x3rgb16.channels = 3;
     TRU->x3rgb16.row_stride = ID->columns * 3;
-    TRU->x3rgb16.buf = malloc(sizeof(uint16_t) * size);
+    TRU->x3rgb16.buf = x3f_limited_malloc(sizeof(uint16_t) * size);
     TRU->x3rgb16.data = (uint16_t *)TRU->x3rgb16.buf;
   }
 
@@ -1441,7 +1463,7 @@ static void x3f_load_huffman(x3f_info_t
   x3f_directory_entry_header_t *DEH = &DE->header;
   x3f_image_data_t *ID = &DEH->data_subsection.image_data;
   x3f_huffman_t *HUF = new_huffman(&ID->huffman);
-  uint32_t size;
+  UINT64 size;
 
   if (use_map_table)
   {
@@ -1454,21 +1476,21 @@ static void x3f_load_huffman(x3f_info_t
   {
   case X3F_IMAGE_RAW_HUFFMAN_X530:
   case X3F_IMAGE_RAW_HUFFMAN_10BIT:
-    size = ID->columns * ID->rows * 3;
+    size = UINT64(ID->columns) * UINT64(ID->rows) * 3ULL;
     HUF->x3rgb16.columns = ID->columns;
     HUF->x3rgb16.rows = ID->rows;
     HUF->x3rgb16.channels = 3;
     HUF->x3rgb16.row_stride = ID->columns * 3;
-    HUF->x3rgb16.buf = malloc(sizeof(uint16_t) * size);
+    HUF->x3rgb16.buf = x3f_limited_malloc(sizeof(uint16_t) * size);
     HUF->x3rgb16.data = (uint16_t *)HUF->x3rgb16.buf;
     break;
   case X3F_IMAGE_THUMB_HUFFMAN:
-    size = ID->columns * ID->rows * 3;
+    size = UINT64(ID->columns) * UINT64(ID->rows) * 3ULL;
     HUF->rgb8.columns = ID->columns;
     HUF->rgb8.rows = ID->rows;
     HUF->rgb8.channels = 3;
     HUF->rgb8.row_stride = ID->columns * 3;
-    HUF->rgb8.buf = malloc(sizeof(uint8_t) * size);
+    HUF->rgb8.buf = x3f_limited_malloc(sizeof(uint8_t) * size);
     HUF->rgb8.data = (uint8_t *)HUF->rgb8.buf;
     break;
   default:
@@ -1568,7 +1590,7 @@ static void x3f_load_camf_decode_type2(x
   int i;
 
   CAMF->decoded_data_size = CAMF->data_size;
-  CAMF->decoded_data = malloc(CAMF->decoded_data_size);
+  CAMF->decoded_data = x3f_limited_malloc(CAMF->decoded_data_size);
 
   for (i = 0; i < (int)CAMF->data_size; i++)
   {
@@ -1609,7 +1631,7 @@ static void camf_decode_type4(x3f_camf_t
 
   CAMF->decoded_data_size = dst_size;
 
-  CAMF->decoded_data = malloc(CAMF->decoded_data_size);
+  CAMF->decoded_data = x3f_limited_malloc(CAMF->decoded_data_size);
   memset(CAMF->decoded_data, 0, CAMF->decoded_data_size);
 
   dst = (uint8_t *)CAMF->decoded_data;
@@ -1688,7 +1710,7 @@ static void x3f_load_camf_decode_type4(x
   for (i = 0, p = (uint8_t *)CAMF->data; *p != 0; i++)
   {
     /* TODO: Is this too expensive ??*/
-    element = (x3f_true_huffman_element_t *)realloc(element,
+    element = (x3f_true_huffman_element_t *)x3f_limited_realloc(element,
                                                     (i + 1) * sizeof(*element));
 
     element[i].code_size = *p++;
@@ -1729,7 +1751,7 @@ static void camf_decode_type5(x3f_camf_t
   int32_t i;
 
   CAMF->decoded_data_size = CAMF->t5.decoded_data_size;
-  CAMF->decoded_data = malloc(CAMF->decoded_data_size);
+  CAMF->decoded_data = x3f_limited_malloc(CAMF->decoded_data_size);
 
   dst = (uint8_t *)CAMF->decoded_data;
 
@@ -1753,7 +1775,7 @@ static void x3f_load_camf_decode_type5(x
   for (i = 0, p = (uint8_t *)CAMF->data; *p != 0; i++)
   {
     /* TODO: Is this too expensive ??*/
-    element = (x3f_true_huffman_element_t *)realloc(element,
+    element = (x3f_true_huffman_element_t *)x3f_limited_realloc(element,
                                                     (i + 1) * sizeof(*element));
 
     element[i].code_size = *p++;
@@ -1796,8 +1818,8 @@ static void x3f_setup_camf_property_entr
   uint32_t num = entry->property_num = *(uint32_t *)v;
   uint32_t off = *(uint32_t *)(v + 4);
 
-  entry->property_name = (char **)malloc(num * sizeof(uint8_t *));
-  entry->property_value = (uint8_t **)malloc(num * sizeof(uint8_t *));
+  entry->property_name = (char **)x3f_limited_malloc(num * sizeof(uint8_t *));
+  entry->property_value = (uint8_t **)x3f_limited_malloc(num * sizeof(uint8_t *));
 
   for (i = 0; i < (int)num; i++)
   {
@@ -1851,7 +1873,7 @@ static void get_matrix_copy(camf_entry_t
                                                        : sizeof(uint32_t)) *
                 elements;
 
-  entry->matrix_decoded = malloc(size);
+  entry->matrix_decoded = x3f_limited_malloc(size);
 
   switch (element_size)
   {
@@ -1921,7 +1943,7 @@ static void x3f_setup_camf_matrix_entry(
   uint32_t dim = entry->matrix_dim = *(uint32_t *)(v + 4);
   uint32_t off = entry->matrix_data_off = *(uint32_t *)(v + 8);
   camf_dim_entry_t *dentry = entry->matrix_dim_entry =
-      (camf_dim_entry_t *)malloc(dim * sizeof(camf_dim_entry_t));
+      (camf_dim_entry_t *)x3f_limited_malloc(dim * sizeof(camf_dim_entry_t));
 
   for (i = 0; i < (int)dim; i++)
   {
@@ -1972,7 +1994,7 @@ static void x3f_setup_camf_entries(x3f_c
     }
 
     /* TODO: lots of realloc - may be inefficient */
-    entry = (camf_entry_t *)realloc(entry, (i + 1) * sizeof(camf_entry_t));
+    entry = (camf_entry_t *)x3f_limited_realloc(entry, (i + 1) * sizeof(camf_entry_t));
 
     /* Pointer */
     entry[i].entry = p;
