]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Also guard against block size overflows master
authorMichael Schroeder <mls@suse.de>
Tue, 28 Apr 2026 12:35:11 +0000 (14:35 +0200)
committerMichael Schroeder <mls@suse.de>
Tue, 28 Apr 2026 12:35:11 +0000 (14:35 +0200)
src/pool.c
src/repo.c
src/repo_solv.c
src/repodata.c
src/strpool.c
src/util.c
src/util.h

index 3be2e444b93075dc7af9325f02db99fdde89052f..fcfcbc950e2a52f73639afd92df8ce692b3528f1 100644 (file)
@@ -267,6 +267,8 @@ pool_add_solvable_block(Pool *pool, int count)
   Id nsolvables = pool->nsolvables;
   if (!count)
     return nsolvables;
+  if (count < 0 || count >= SOLV_MAX_BLKLEN)
+    solv_ovfl("solvable count overflow");
   pool->solvables = solv_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
   pool->nsolvables += count;
index b266d8d575d7a27c8a1c4b2a87359db3693ed333..d6cd9747f17f1e8035a23929f2d9b4a664a8cd27 100644 (file)
@@ -48,7 +48,11 @@ repo_create(Pool *pool, const char *name)
       pool->repos = (Repo **)solv_calloc(2, sizeof(Repo *));
     }
   else
-    pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
+    {
+      if (pool->nrepos + 1 >= SOLV_MAX_BLKLEN)
+       solv_ovfl("repository count overflow");
+      pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
+    }
   pool->repos[pool->nrepos] = repo;
   pool->urepos++;
   repo->repoid = pool->nrepos++;
@@ -619,6 +623,8 @@ solv_depmarker(Id keyname, Id marker)
 Offset
 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
 {
+  if (num < 0 || num >= SOLV_MAX_BLKLEN)
+    solv_ovfl("dependency array overflow");
   num++;       /* room for trailing ID_NULL */
 
   if (!repo->idarraysize)             /* ensure buffer space */
@@ -1352,6 +1358,8 @@ repo_add_repodata(Repo *repo, int flags)
     }
   else
     {
+      if (repo->nrepodata + 1 >= SOLV_MAX_BLKLEN)
+       solv_ovfl("repodata count overflow");
       repo->nrepodata++;
       repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
     }
index b8c981fa9af466867db0c73631ef86f13800363e..f9156920f757f80def776d093f0672e82d059b1f 100644 (file)
@@ -18,7 +18,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#include <limits.h>
 
 #include "repo_solv.h"
 #include "util.h"
@@ -119,6 +118,11 @@ read_id(Repodata *data, Id max)
              data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_id: id too large (%u/%u)", x, max);
              return 0;
            }
+         else if (x >= 0x7fffffffU)
+           {
+             data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_id: id too large (%u)", x);
+             return 0;
+           }
          return x;
        }
       x = (x << 7) ^ c ^ 128;
@@ -155,6 +159,11 @@ read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
          data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_idarray: id too large (%u/%u)", x, max);
          return 0;
        }
+      else if (x >= 0x7fffffffU)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_idarray: id too large (%u)", x);
+         return 0;
+       }
       if (map)
        x = map[x];
       if (store == end)
@@ -924,8 +933,8 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
       key = keys + i;
       key->name = id;
       key->type = type;
-      key->size = read_id(&data, type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
-      key->storage = read_id(&data, 0);
+      key->size = read_id(&data, type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : SOLV_MAX_BLKLEN);
+      key->storage = read_id(&data, SOLV_MAX_BLKLEN);
       /* old versions used SOLVABLE for main solvable data */
       if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET && key->storage != KEY_STORAGE_SOLVABLE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
        data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", key->storage);
@@ -977,7 +986,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
 
   /*******  Part 5: Schemata ********************************************/
 
-  id = read_id(&data, 0);
+  id = read_id(&data, SOLV_MAX_BLKLEN);
   schemadata = solv_calloc(id + 1, sizeof(Id));
   schemadatap = schemadata + 1;
   schemadataend = schemadatap + id;
@@ -1017,20 +1026,10 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
   idarraydatap = idarraydataend = 0;
   size_idarray = 0;
 
-  maxsize = read_id(&data, 0);
-  allsize = read_id(&data, 0);
-  if (maxsize < 0 || allsize < 0)
-    {
-      data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "negative data size in solv header");
-      id = 0;
-      goto data_error;
-    }
-  if (maxsize > INT_MAX - 5)
-    {
-      data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "data size overflow in solv header");
-      id = 0;
-      goto data_error;
-    }
+  maxsize = read_id(&data, SOLV_MAX_BLKLEN);
+  allsize = read_id(&data, SOLV_MAX_BLKLEN);
+  if (data.error)
+    goto data_error;
   maxsize += 5;        /* so we can read the next schema of an array */
   if (maxsize > allsize)
     maxsize = allsize;
@@ -1294,7 +1293,17 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
                  id = keys[i].name;
                  if ((keys[i].type == REPOKEY_TYPE_IDARRAY || keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
                      && id >= INTERESTED_START && id <= INTERESTED_END)
-                   size_idarray += keys[i].size;
+                   {
+                     size_idarray += keys[i].size;
+                     if ((unsigned int)size_idarray >= (unsigned int)SOLV_MAX_BLKLEN)
+                       break;
+                   }
+               }
+             if (i < numkeys)
+               {
+                 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "idarray size overflow");
+                 size_idarray = 0;
+                 break;                /* overflow */
                }
              /* allocate needed space in repo */
              /* we add maxsize because it is an upper limit for all idarrays, thus we can't overflow */
index 9c265031ebe085141dd3d8d086cd4f1313b667cd..b9e9db946299ec6600ad0bd33017f6735f9ef643 100644 (file)
@@ -183,9 +183,10 @@ repodata_key2id(Repodata *data, Repokey *key, int create)
 Id
 repodata_schema2id(Repodata *data, Id *schema, int create)
 {
-  int h, len, i;
+  int h, i;
   Id *sp, cid;
   Id *schematahash;
+  size_t len;
 
   if (!*schema)
     return 0;  /* XXX: allow empty schema? */
@@ -223,6 +224,8 @@ repodata_schema2id(Repodata *data, Id *schema, int create)
   /* a new one */
   if (!create)
     return 0;
+  if (len >= SOLV_MAX_BLKLEN)
+    solv_ovfl("schema length overflow");
   data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
   data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
   /* add schema */
index 0b95f0f7a749a3a5f1e565f83b2ee3e13885083a..98a9a07ffa72616689df416e75ec4b52da66b8ed 100644 (file)
@@ -12,6 +12,8 @@
 #define STRING_BLOCK      2047
 #define STRINGSPACE_BLOCK 65535
 
+#define STRING_MAXSIZE 0x40000000
+
 void
 stringpool_init(Stringpool *ss, const char *strs[])
 {
@@ -113,6 +115,12 @@ stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create
   if (!len)
     return STRID_EMPTY;
 
+  if (len >= STRING_MAXSIZE)
+    {
+      solv_ovfl("maximum string size overflow");
+      return 0;
+    }
+
   hashmask = ss->stringhashmask;
 
   /* expand hashtable if needed */
@@ -160,11 +168,18 @@ stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create
 Id
 stringpool_str2id(Stringpool *ss, const char *str, int create)
 {
+  size_t len;
   if (!str)
     return STRID_NULL;
   if (!*str)
     return STRID_EMPTY;
-  return stringpool_strn2id(ss, str, (unsigned int)strlen(str), create);
+  len = strlen(str);
+  if (len >= STRING_MAXSIZE)
+    {
+      solv_ovfl("maximum string size overflow");
+      return 0;
+    }
+  return stringpool_strn2id(ss, str, (unsigned int)len, create);
 }
 
 void
index a60ed3daf1d2779f57af9ed9d279b95295b50356..5f7268d68b3b2926634d766dde10490a590625d8 100644 (file)
 
 #include "util.h"
 
+void
+solv_ovfl(const char *str)
+{
+  fprintf(stderr, "%s\n", str);
+  abort();
+  exit(1);
+}
+
 void
 solv_oom(size_t num, size_t len)
 {
@@ -103,6 +111,8 @@ solv_extend_realloc(void *old, size_t len, size_t size, size_t block)
            len = nlen;
        }
     }
+  if (len >= SOLV_MAX_BLKLEN)
+    solv_ovfl("solv extend realloc overflow");
   return solv_realloc2(old, len, size);
 }
 
index 9c2b8249755b9ec4bfbb2911d0fc0e41a4c052ab..28ec523c374233990f75afef86b917e814718764 100644 (file)
@@ -44,6 +44,11 @@ extern size_t solv_validutf8(const char *buf);
 extern char *solv_latin1toutf8(const char *buf);
 extern char *solv_replacebadutf8(const char *buf, int replchar);
 
+#ifdef LIBSOLV_INTERNAL
+#define SOLV_MAX_BLKLEN        0x7fff0000
+extern void solv_ovfl(const char *);
+#endif
+
 
 static inline void *solv_extend(void *buf, size_t len, size_t nmemb, size_t size, size_t block)
 {