libsolv/0007-Add-some-more-guards.patch
2026-08-11 11:11:48 +02:00

415 lines
16 KiB
Diff

From aa10f54529b9d8aed7422b5de3c06487c5ccef92 Mon Sep 17 00:00:00 2001
From: Michael Schroeder <mls@suse.de>
Date: Wed, 29 Apr 2026 11:00:24 +0200
Subject: [PATCH 2/3] Add some more guards
---
src/pool.c | 25 +++++++++++++++++++------
src/queue.c | 7 +++++++
src/repo.c | 8 +++++---
src/repo_solv.c | 24 ++++++++----------------
src/repodata.c | 30 +++++++++++++++++++++++-------
src/strpool.c | 2 ++
src/util.c | 2 +-
src/util.h | 4 +++-
8 files changed, 68 insertions(+), 34 deletions(-)
diff --git a/src/pool.c b/src/pool.c
index bfef9704..03f74bdb 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -275,7 +275,7 @@ pool_add_solvable_block(Pool *pool, int count)
Id nsolvables = pool->nsolvables;
if (!count)
return nsolvables;
- if (count < 0 || count >= SOLV_MAX_BLKLEN)
+ if (count < 0 || count >= SOLV_MAX_INDEX)
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);
@@ -407,7 +407,7 @@ pool_shrink_whatprovides(Pool *pool)
return;
r = pool->whatprovidesdataoff - o;
pool->whatprovidesdataoff = o;
- pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
+ pool->whatprovidesdata = solv_realloc2(pool->whatprovidesdata, o + pool->whatprovidesdataleft, sizeof(Id));
if (r > pool->whatprovidesdataleft)
r = pool->whatprovidesdataleft;
memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
@@ -436,7 +436,7 @@ pool_shrink_whatprovidesaux(Pool *pool)
*wp++ = id;
}
newoff = wp - pool->whatprovidesauxdata;
- pool->whatprovidesauxdata = solv_realloc(pool->whatprovidesauxdata, newoff * sizeof(Id));
+ pool->whatprovidesauxdata = solv_realloc2(pool->whatprovidesauxdata, newoff, sizeof(Id));
POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesauxdata from %d to %d\n", pool->whatprovidesauxdataoff, newoff);
pool->whatprovidesauxdataoff = newoff;
}
@@ -505,6 +505,8 @@ pool_createwhatprovides(Pool *pool)
*idp = 1; /* offset for empty list */
continue;
}
+ if (n >= 0xffff0000U - off)
+ solv_ovfl("pool whatprovides overflow");
off += n; /* make space for all providers */
*idp = off++; /* now idp points to terminating zero */
np++; /* inc # of provider 'slots' for stats */
@@ -516,8 +518,12 @@ pool_createwhatprovides(Pool *pool)
extra = 2 * pool->nrels;
if (extra < 256)
extra = 256;
+ if (extra > 0x10000000)
+ extra = 0x10000000;
+ if (off > 0xffff0000U - extra)
+ solv_ovfl("pool whatprovides overflow");
- POOL_DEBUG(SOLV_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
+ POOL_DEBUG(SOLV_DEBUG_STATS, "provide space needed: %u + %d\n", off, extra);
/* alloc space for all providers + extra */
whatprovidesdata = solv_calloc(off + extra, sizeof(Id));
@@ -570,6 +576,9 @@ pool_createwhatprovides(Pool *pool)
pool->whatprovidesdataoff = off;
pool->whatprovidesdataleft = extra;
pool_shrink_whatprovides(pool);
+ if (pool->whatprovidesdataoff >= SOLV_MAX_INDEX || pool->whatprovidesdataoff + pool->whatprovidesdataleft >= SOLV_MAX_INDEX)
+ solv_ovfl("pool whatprovides overflow");
+
if (pool->whatprovidesaux)
pool_shrink_whatprovidesaux(pool);
POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id)));
@@ -655,16 +664,20 @@ pool_ids2whatprovides(Pool *pool, Id *ids, int count)
{
Offset off;
- if (count == 0) /* queue empty -> 1 */
+ if (count <= 0) /* queue empty -> 1 */
return 1;
if (count == 1 && *ids == SYSTEMSOLVABLE)
return 2;
+ if (count >= SOLV_MAX_INDEX)
+ solv_ovfl("pool whatprovides data overflow");
/* extend whatprovidesdata if needed, +1 for 0-termination */
if (pool->whatprovidesdataleft < count + 1)
{
POOL_DEBUG(SOLV_DEBUG_STATS, "growing provides hash data...\n");
- pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
+ if ((unsigned int)(SOLV_MAX_INDEX - pool->whatprovidesdataoff) < (unsigned int)count + 4096)
+ solv_ovfl("pool whatprovides data overflow");
+ pool->whatprovidesdata = solv_realloc2(pool->whatprovidesdata, pool->whatprovidesdataoff + count + 4096, sizeof(Id));
pool->whatprovidesdataleft = count + 4096;
}
diff --git a/src/queue.c b/src/queue.c
index 6d5e531d..d7133f42 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -16,6 +16,8 @@
#include "queue.h"
#include "util.h"
+#define SOLV_MAX_QUEUECOUNT SOLV_MAX_INDEX
+
static inline int
queue_extra_space(int size)
{
@@ -87,6 +89,8 @@ queue_alloc_one(Queue *q)
else
{
int extra_space = queue_extra_space(q->count);
+ if (q->count + extra_space >= SOLV_MAX_QUEUECOUNT)
+ solv_ovfl("queue count overflow");
if (!q->alloc)
{
q->alloc = solv_malloc2(q->count + extra_space, sizeof(Id));
@@ -210,6 +214,9 @@ queue_prealloc(Queue *q, int n)
queue_alloc_one(q);
off = q->elements - q->alloc;
extra_space = queue_extra_space(q->count + n);
+ if (n >= SOLV_MAX_QUEUECOUNT || (unsigned int)(off + q->count + n + extra_space) >= (unsigned int)SOLV_MAX_QUEUECOUNT)
+ solv_ovfl("queue count overflow");
+
q->alloc = solv_realloc2(q->alloc, off + q->count + n + extra_space, sizeof(Id));
q->elements = q->alloc + off;
q->left = n + extra_space;
diff --git a/src/repo.c b/src/repo.c
index d6cd9747..050ea24e 100644
--- a/src/repo.c
+++ b/src/repo.c
@@ -49,7 +49,7 @@ repo_create(Pool *pool, const char *name)
}
else
{
- if (pool->nrepos + 1 >= SOLV_MAX_BLKLEN)
+ if (pool->nrepos + 1 >= SOLV_MAX_INDEX)
solv_ovfl("repository count overflow");
pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
}
@@ -623,7 +623,7 @@ solv_depmarker(Id keyname, Id marker)
Offset
repo_reserve_ids(Repo *repo, Offset olddeps, int num)
{
- if (num < 0 || num >= SOLV_MAX_BLKLEN)
+ if (num < 0 || num >= SOLV_MAX_INDEX)
solv_ovfl("dependency array overflow");
num++; /* room for trailing ID_NULL */
@@ -648,6 +648,8 @@ repo_reserve_ids(Repo *repo, Offset olddeps, int num)
for (idstart = idend = repo->idarraydata + olddeps; *idend++; ) /* find end */
;
+ if (idend - idstart >= SOLV_MAX_INDEX - (num + 1))
+ solv_ovfl("dependency array overflow");
count = idend - idstart - 1 + num; /* new size */
repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
@@ -1358,7 +1360,7 @@ repo_add_repodata(Repo *repo, int flags)
}
else
{
- if (repo->nrepodata + 1 >= SOLV_MAX_BLKLEN)
+ if (repo->nrepodata + 1 >= SOLV_MAX_INDEX)
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 f9156920..ca3fa213 100644
--- a/src/repo_solv.c
+++ b/src/repo_solv.c
@@ -118,11 +118,6 @@ 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;
@@ -159,11 +154,6 @@ 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)
@@ -858,6 +848,8 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
}
idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
}
+ if ((unsigned int)pool->nrels >= (unsigned int)SOLV_MAX_INDEX)
+ solv_ovfl("relation count overflow");
pool_shrink_rels(pool); /* vacuum */
}
@@ -933,8 +925,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 : SOLV_MAX_BLKLEN);
- key->storage = read_id(&data, SOLV_MAX_BLKLEN);
+ key->size = read_id(&data, type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : type == REPOKEY_TYPE_CONSTANT ? 0 : SOLV_MAX_INDEX);
+ key->storage = read_id(&data, SOLV_MAX_INDEX);
/* 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);
@@ -986,7 +978,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
/******* Part 5: Schemata ********************************************/
- id = read_id(&data, SOLV_MAX_BLKLEN);
+ id = read_id(&data, SOLV_MAX_INDEX);
schemadata = solv_calloc(id + 1, sizeof(Id));
schemadatap = schemadata + 1;
schemadataend = schemadatap + id;
@@ -1026,8 +1018,8 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
idarraydatap = idarraydataend = 0;
size_idarray = 0;
- maxsize = read_id(&data, SOLV_MAX_BLKLEN);
- allsize = read_id(&data, SOLV_MAX_BLKLEN);
+ maxsize = read_id(&data, SOLV_MAX_INDEX);
+ allsize = read_id(&data, SOLV_MAX_INDEX);
if (data.error)
goto data_error;
maxsize += 5; /* so we can read the next schema of an array */
@@ -1295,7 +1287,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
&& id >= INTERESTED_START && id <= INTERESTED_END)
{
size_idarray += keys[i].size;
- if ((unsigned int)size_idarray >= (unsigned int)SOLV_MAX_BLKLEN)
+ if ((unsigned int)size_idarray >= (unsigned int)SOLV_MAX_INDEX)
break;
}
}
diff --git a/src/repodata.c b/src/repodata.c
index 20493d4c..f3ab4348 100644
--- a/src/repodata.c
+++ b/src/repodata.c
@@ -160,6 +160,8 @@ repodata_key2id(Repodata *data, Repokey *key, int create)
if (!create)
return 0;
/* allocate new key */
+ if (data->nkeys >= SOLV_MAX_INDEX)
+ solv_ovfl("repodata key overflow");
data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
data->keys[data->nkeys++] = *key;
if (data->verticaloffset)
@@ -224,8 +226,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");
+ if (len >= SOLV_MAX_INDEX)
+ solv_ovfl("repodata 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 */
@@ -314,6 +316,8 @@ repodata_str2dir(Repodata *data, const char *dir, int create)
while (*dir)
{
dire = strchrnul(dir, '/');
+ if (dire - dir >= (size_t)0x40000000)
+ solv_ovfl("repodata dir component size overflow");
if (data->localpool)
id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
else
@@ -2532,9 +2536,11 @@ void
repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
{
Repokey key;
- int l;
+ size_t l;
l = strlen(str) + 1;
+ if (l >= 0x40000000)
+ solv_ovfl("repodata string size overflow");
key.name = keyname;
key.type = REPOKEY_TYPE_STR;
key.size = 0;
@@ -2553,6 +2559,8 @@ repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
if (len < 0)
return;
+ if (len >= 0x40000000)
+ solv_ovfl("repodata binary size overflow");
key.name = keyname;
key.type = REPOKEY_TYPE_BINARY;
key.size = 0;
@@ -2697,9 +2705,11 @@ evrid2vrstr(Pool *pool, Id evrid)
}
static inline void
-repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
+repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, size_t l)
{
Id id;
+ if (l >= (size_t)0x40000000)
+ solv_ovfl("repodata poolstr size overflow");
if (data->localpool)
id = stringpool_strn2id(&data->spool, str, l, 1);
else
@@ -2708,7 +2718,7 @@ repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, in
}
static inline void
-repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
+repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, size_t l)
{
if (!str[l])
repodata_set_str(data, solvid, keyname, str);
@@ -2727,7 +2737,7 @@ repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, c
Pool *pool = data->repo->pool;
Solvable *s;
const char *str, *fp;
- int l = 0;
+ size_t l = 0;
if (medianr)
repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
@@ -2867,6 +2877,8 @@ repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
return;
}
+ if (p - sourcepkg >= (size_t)0x40000000)
+ solv_ovfl("repodata sourcepkg size overflow");
p--;
while (p > sourcepkg && *p != '.')
p--;
@@ -2916,6 +2928,8 @@ repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
repodata_set(data, solvid, &key, data->attriddatalen);
+ if (q->count + 1 >= SOLV_MAX_INDEX)
+ solv_ovfl("repodata idarray size overflow");
data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
for (i = 0; i < q->count; i++)
data->attriddata[data->attriddatalen++] = q->elements[i];
@@ -2940,10 +2954,12 @@ void
repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
{
Id stroff;
- int l;
+ size_t l;
assert(dir);
l = strlen(str) + 1;
+ if (l >= SOLV_MAX_INDEX)
+ solv_ovfl("repodata dirstr size overflow");
data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
memcpy(data->attrdata + data->attrdatalen, str, l);
stroff = data->attrdatalen;
diff --git a/src/strpool.c b/src/strpool.c
index 98a9a07f..8d7c1212 100644
--- a/src/strpool.c
+++ b/src/strpool.c
@@ -263,6 +263,8 @@ stringpool_integrate(Stringpool *ss, int numid, Offset sizeid, Id *idmap)
idmap[i] = id; /* repo relative -> pool relative */
sp += l; /* next string */
}
+ if ((unsigned int)ss->nstrings >= (unsigned int)SOLV_MAX_INDEX)
+ solv_ovfl("string count overpool");
stringpool_shrink(ss); /* vacuum */
return 1;
}
diff --git a/src/util.c b/src/util.c
index da3963c9..cfcd0d01 100644
--- a/src/util.c
+++ b/src/util.c
@@ -111,7 +111,7 @@ solv_extend_realloc(void *old, size_t len, size_t size, size_t block)
len = nlen;
}
}
- if (len >= SOLV_MAX_BLKLEN)
+ if (len >= SOLV_MAX_INDEX)
solv_ovfl("solv extend realloc overflow");
return solv_realloc2(old, len, size);
}
diff --git a/src/util.h b/src/util.h
index 28ec523c..15c694f1 100644
--- a/src/util.h
+++ b/src/util.h
@@ -45,7 +45,9 @@ extern char *solv_latin1toutf8(const char *buf);
extern char *solv_replacebadutf8(const char *buf, int replchar);
#ifdef LIBSOLV_INTERNAL
-#define SOLV_MAX_BLKLEN 0x7fff0000
+/* our index values are 32 bit signed integers. We use a bit less than the
+ * maximum value to allow for a bit of overshooting */
+#define SOLV_MAX_INDEX 0x7fff0000
extern void solv_ovfl(const char *);
#endif
--
2.55.0