libsolv/0006-Also-guard-against-block-size-overflows.patch
2026-08-11 11:11:48 +02:00

282 lines
9.0 KiB
Diff

From 5da52ee473f9af964d5131ace7fbd6841b54f2ec Mon Sep 17 00:00:00 2001
From: Michael Schroeder <mls@suse.de>
Date: Tue, 28 Apr 2026 14:35:11 +0200
Subject: [PATCH 1/3] Also guard against block size overflows
---
src/pool.c | 2 ++
src/repo.c | 10 +++++++++-
src/repo_solv.c | 47 ++++++++++++++++++++++++++++-------------------
src/repodata.c | 5 ++++-
src/strpool.c | 17 ++++++++++++++++-
src/util.c | 10 ++++++++++
src/util.h | 5 +++++
7 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/src/pool.c b/src/pool.c
index 0f989b16..bfef9704 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -275,6 +275,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;
diff --git a/src/repo.c b/src/repo.c
index b266d8d5..d6cd9747 100644
--- a/src/repo.c
+++ b/src/repo.c
@@ -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));
}
diff --git a/src/repo_solv.c b/src/repo_solv.c
index b8c981fa..f9156920 100644
--- a/src/repo_solv.c
+++ b/src/repo_solv.c
@@ -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 */
diff --git a/src/repodata.c b/src/repodata.c
index 10e7b42b..20493d4c 100644
--- a/src/repodata.c
+++ b/src/repodata.c
@@ -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 */
diff --git a/src/strpool.c b/src/strpool.c
index 0b95f0f7..98a9a07f 100644
--- a/src/strpool.c
+++ b/src/strpool.c
@@ -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
diff --git a/src/util.c b/src/util.c
index 72426e09..da3963c9 100644
--- a/src/util.c
+++ b/src/util.c
@@ -21,6 +21,14 @@
#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);
}
diff --git a/src/util.h b/src/util.h
index 9c2b8249..28ec523c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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)
{
--
2.55.0