diff --git a/0006-Also-guard-against-block-size-overflows.patch b/0006-Also-guard-against-block-size-overflows.patch new file mode 100644 index 0000000..4b889fd --- /dev/null +++ b/0006-Also-guard-against-block-size-overflows.patch @@ -0,0 +1,281 @@ +From 5da52ee473f9af964d5131ace7fbd6841b54f2ec Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +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 + #include + #include +-#include + + #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 + diff --git a/0007-Add-some-more-guards.patch b/0007-Add-some-more-guards.patch new file mode 100644 index 0000000..ac79c2c --- /dev/null +++ b/0007-Add-some-more-guards.patch @@ -0,0 +1,414 @@ +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 + diff --git a/0008-Add-some-guards-to-the-tmpspace-functions.patch b/0008-Add-some-guards-to-the-tmpspace-functions.patch new file mode 100644 index 0000000..a792697 --- /dev/null +++ b/0008-Add-some-guards-to-the-tmpspace-functions.patch @@ -0,0 +1,76 @@ +From 0d38eb567a3f4b7c6c4898a502f7a505df588e88 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 19 May 2026 11:21:11 +0200 +Subject: [PATCH 3/3] Add some guards to the tmpspace functions + +I don't think this matters, but it's the right thing to do. +Also add pool_bin2hex to the size_t TODO list +--- + src/pool.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/pool.c b/src/pool.c +index 03f74bdb..f3b80e5e 100644 +--- a/src/pool.c ++++ b/src/pool.c +@@ -38,6 +38,8 @@ + #include "knownid.h" + #undef KNOWNID_INITIALIZE + ++#define POOL_MAX_TMPSPACE_LEN 0x1000000 ++ + /* create pool */ + Pool * + pool_create(void) +@@ -1760,6 +1762,8 @@ pool_alloctmpspace(Pool *pool, int len) + int n = pool->tmpspace.n; + if (!len) + return 0; ++ if (len >= POOL_MAX_TMPSPACE_LEN) ++ solv_ovfl("tmpspace size overflow"); + if (len > pool->tmpspace.len[n]) + { + pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32); +@@ -1809,11 +1813,13 @@ pool_freetmpspace(Pool *pool, const char *space) + char * + pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3) + { +- int l1, l2, l3; ++ size_t l1, l2, l3; + char *s, *str; + l1 = str1 ? strlen(str1) : 0; + l2 = str2 ? strlen(str2) : 0; + l3 = str3 ? strlen(str3) : 0; ++ if (l1 >= POOL_MAX_TMPSPACE_LEN || l2 >= POOL_MAX_TMPSPACE_LEN || l3 >= POOL_MAX_TMPSPACE_LEN) ++ solv_ovfl("tmpspace size overflow"); + s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1); + if (l1) + { +@@ -1837,12 +1843,14 @@ pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3) + char * + pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3) + { +- int l1, l2, l3; ++ size_t l1, l2, l3; + char *s, *str; + + l1 = str1 ? strlen(str1) : 0; + l2 = str2 ? strlen(str2) : 0; + l3 = str3 ? strlen(str3) : 0; ++ if (l1 >= POOL_MAX_TMPSPACE_LEN || l2 >= POOL_MAX_TMPSPACE_LEN || l3 >= POOL_MAX_TMPSPACE_LEN) ++ solv_ovfl("tmpspace size overflow"); + str = pool_alloctmpspace_free(pool, str1, l1 + l2 + l3 + 1); + if (str) + str1 = str; +@@ -1875,6 +1883,8 @@ pool_bin2hex(Pool *pool, const unsigned char *buf, int len) + char *s; + if (!len) + return ""; ++ if (len >= POOL_MAX_TMPSPACE_LEN / 2) ++ solv_ovfl("pool_bin2hex size overflow"); + s = pool_alloctmpspace(pool, 2 * len + 1); + solv_bin2hex(buf, len, s); + return s; +-- +2.55.0 + diff --git a/libsolv.spec b/libsolv.spec index 428ba36..01799cd 100644 --- a/libsolv.spec +++ b/libsolv.spec @@ -76,6 +76,14 @@ Patch3: 0004-Cope-with-integer-overflow-in-data-size-arithmetics-.patch # . Patch4: 0005-Fix-a-buffer-overflow-when-decompressing-solv-pages.patch +# Add guards that abort if an overflow is about to happen +# https://github.com/openSUSE/libsolv/commit/37a47d24e81fd3c02b0fdc7f0dd440e95e9fe7ae +Patch6: 0006-Also-guard-against-block-size-overflows.patch +# https://github.com/openSUSE/libsolv/commit/aa100c8382200e72461b03c1f731e7e6c03bba24 +Patch7: 0007-Add-some-more-guards.patch +# https://github.com/openSUSE/libsolv/commit/25dccfc54388f26b6b1196caa69647ffead05286 +Patch8: 0008-Add-some-guards-to-the-tmpspace-functions.patch + # AlmaLinux Patch Patch1000: 0001-Set-x86_64-arch-as-exchangeable-to-x86_64_v2.patch