282 lines
9.0 KiB
Diff
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
|
|
|