From: Michael Schroeder Date: Tue, 28 Apr 2026 12:35:11 +0000 (+0200) Subject: Also guard against block size overflows X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=HEAD;p=thirdparty%2Flibsolv.git Also guard against block size overflows --- diff --git a/src/pool.c b/src/pool.c index 3be2e444..fcfcbc95 100644 --- a/src/pool.c +++ b/src/pool.c @@ -267,6 +267,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 9c265031..b9e9db94 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 a60ed3da..5f7268d6 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) {