From aa10f54529b9d8aed7422b5de3c06487c5ccef92 Mon Sep 17 00:00:00 2001 From: Michael Schroeder 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