Index: db-4.8.30/btree/bt_cursor.c =================================================================== --- db-4.8.30.orig/btree/bt_cursor.c +++ db-4.8.30/btree/bt_cursor.c @@ -282,6 +282,8 @@ __bamc_refresh(dbc) * * Recno uses the btree bt_ovflsize value -- it's close enough. */ + if (t->bt_minkey == 0) + return (DB_RECOVER); cp->ovflsize = B_MINKEY_TO_OVFLSIZE( dbp, F_ISSET(dbc, DBC_OPD) ? 2 : t->bt_minkey, dbp->pgsize); Index: db-4.8.30/btree/bt_verify.c =================================================================== --- db-4.8.30.orig/btree/bt_verify.c +++ db-4.8.30/btree/bt_verify.c @@ -613,7 +613,11 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentri isbad = 1; goto err; default: - DB_ASSERT(env, ret != 0); + if (ret == 0) { + isbad = 1; + ret = DB_VERIFY_FATAL; + goto err; + } break; } @@ -934,8 +939,8 @@ __bam_vrfy_itemorder(dbp, vdp, ip, h, pg F_SET(&dbtb, DB_DBT_REALLOC); buf1 = buf2 = NULL; - - DB_ASSERT(env, !LF_ISSET(DB_NOORDERCHK)); + if (LF_ISSET(DB_NOORDERCHK)) + return (EINVAL); dupfunc = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare; if (TYPE(h) == P_LDUP) @@ -1178,8 +1184,12 @@ overflow: if (!ovflok) { */ if (dup_1.data == NULL || dup_2.data == NULL) { - DB_ASSERT(env, !ovflok); - F_SET(pip, VRFY_INCOMPLETE); + if (ovflok) { + isbad = 1; + goto err; + } + if (pip != NULL) + F_SET(pip, VRFY_INCOMPLETE); goto err; } @@ -1510,9 +1520,10 @@ bad_prev: isbad = 1; (ret = __db_vrfy_ovfl_structure(dbp, vdp, child->pgno, child->tlen, flags | DB_ST_OVFL_LEAF)) != 0) { - if (ret == DB_VERIFY_BAD) + if (ret == DB_VERIFY_BAD) { isbad = 1; - else + break; + } else goto done; } @@ -1586,9 +1597,10 @@ bad_prev: isbad = 1; stflags | DB_ST_TOPLEVEL, NULL, NULL, NULL)) != 0) { if (ret == - DB_VERIFY_BAD) + DB_VERIFY_BAD) { isbad = 1; - else + break; + } else goto err; } } @@ -1728,7 +1740,10 @@ bad_prev: isbad = 1; */ /* Otherwise, __db_vrfy_childput would be broken. */ - DB_ASSERT(env, child->refcnt >= 1); + if (child->refcnt < 1) { + isbad = 1; + goto err; + } /* * An overflow referenced more than twice here @@ -1744,9 +1759,10 @@ bad_prev: isbad = 1; if ((ret = __db_vrfy_ovfl_structure(dbp, vdp, child->pgno, child->tlen, flags)) != 0) { - if (ret == DB_VERIFY_BAD) + if (ret == DB_VERIFY_BAD) { isbad = 1; - else + break; + } else goto done; } } @@ -2609,7 +2625,11 @@ __bam_meta2pgset(dbp, vdp, btmeta, flags db_pgno_t current, p; int err_ret, ret; - DB_ASSERT(dbp->env, pgset != NULL); + if (pgset == NULL) { + EPRINT((dbp->env, + "Error, database contains no visible pages.")); + return (DB_RUNRECOVERY); + } mpf = dbp->mpf; h = NULL; Index: db-4.8.30/db/db_conv.c =================================================================== --- db-4.8.30.orig/db/db_conv.c +++ db-4.8.30/db/db_conv.c @@ -447,8 +447,11 @@ __db_byteswap(dbp, pg, h, pagesize, pgin db_indx_t i, *inp, len, tmp; u_int8_t *end, *p, *pgend; - if (pagesize == 0) - return (0); + /* This function is also used to byteswap logs, so + * the pagesize might not be an actual page size. + */ + if (!(pagesize >= 24 && pagesize <= DB_MAX_PGSIZE)) + return (EINVAL); env = dbp->env; @@ -465,26 +468,41 @@ __db_byteswap(dbp, pg, h, pagesize, pgin pgend = (u_int8_t *)h + pagesize; inp = P_INP(dbp, h); - if ((u_int8_t *)inp >= pgend) - goto out; + if ((u_int8_t *)inp > pgend) + return (__db_pgfmt(env, pg)); switch (TYPE(h)) { case P_HASH_UNSORTED: case P_HASH: for (i = 0; i < NUM_ENT(h); i++) { + if ((u_int8_t*)(inp + i) >= pgend) + return (__db_pgfmt(env, pg)); + if (inp[i] == 0) + continue; if (pgin) M_16_SWAP(inp[i]); + if (inp[i] >= pagesize) + return (__db_pgfmt(env, pg)); if (P_ENTRY(dbp, h, i) >= pgend) - continue; + return (__db_pgfmt(env, pg)); switch (HPAGE_TYPE(dbp, h, i)) { case H_KEYDATA: break; case H_DUPLICATE: + if (LEN_HITEM(dbp, h, pagesize, i) < + HKEYDATA_SIZE(0)) + return (__db_pgfmt(env, pg)); + len = LEN_HKEYDATA(dbp, h, pagesize, i); p = HKEYDATA_DATA(P_ENTRY(dbp, h, i)); - for (end = p + len; p < end;) { + + end = p + len; + if (end > pgend) + return (__db_pgfmt(env, pg)); + + while (p < end) { if (pgin) { P_16_SWAP(p); memcpy(&tmp, @@ -496,14 +514,20 @@ __db_byteswap(dbp, pg, h, pagesize, pgin SWAP16(p); } p += tmp; + if (p >= end) + return (__db_pgfmt(env, pg)); SWAP16(p); } break; case H_OFFDUP: + if ((inp[i] + HOFFDUP_SIZE) > pagesize) + return (__db_pgfmt(env, pg)); p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i)); SWAP32(p); /* pgno */ break; case H_OFFPAGE: + if ((inp[i] + HOFFPAGE_SIZE) > pagesize) + return (__db_pgfmt(env, pg)); p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i)); SWAP32(p); /* pgno */ SWAP32(p); /* tlen */ @@ -528,8 +552,12 @@ __db_byteswap(dbp, pg, h, pagesize, pgin case P_LDUP: case P_LRECNO: for (i = 0; i < NUM_ENT(h); i++) { + if ((u_int8_t *)(inp + i) >= pgend) + return (__db_pgfmt(env, pg)); if (pgin) M_16_SWAP(inp[i]); + if (inp[i] >= pagesize) + return (__db_pgfmt(env, pg)); /* * In the case of on-page duplicates, key information @@ -549,7 +577,7 @@ __db_byteswap(dbp, pg, h, pagesize, pgin bk = GET_BKEYDATA(dbp, h, i); if ((u_int8_t *)bk >= pgend) - continue; + return (__db_pgfmt(env, pg)); switch (B_TYPE(bk->type)) { case B_KEYDATA: M_16_SWAP(bk->len); @@ -557,6 +585,8 @@ __db_byteswap(dbp, pg, h, pagesize, pgin case B_DUPLICATE: case B_OVERFLOW: bo = (BOVERFLOW *)bk; + if (((u_int8_t *)bo + BOVERFLOW_SIZE) > pgend) + return (__db_pgfmt(env, pg)); M_32_SWAP(bo->pgno); M_32_SWAP(bo->tlen); break; @@ -570,12 +600,17 @@ __db_byteswap(dbp, pg, h, pagesize, pgin break; case P_IBTREE: for (i = 0; i < NUM_ENT(h); i++) { + if ((u_int8_t *)(inp + i) > pgend) + return (__db_pgfmt(env, pg)); if (pgin) M_16_SWAP(inp[i]); + if ((u_int16_t)(inp[i] + + BINTERNAL_SIZE(0) - 1) > pagesize) + break; bi = GET_BINTERNAL(dbp, h, i); - if ((u_int8_t *)bi >= pgend) - continue; + if (((u_int8_t *)bi + BINTERNAL_SIZE(0)) > pgend) + return (__db_pgfmt(env, pg)); M_16_SWAP(bi->len); M_32_SWAP(bi->pgno); @@ -586,6 +621,10 @@ __db_byteswap(dbp, pg, h, pagesize, pgin break; case B_DUPLICATE: case B_OVERFLOW: + if ((u_int16_t)(inp[i] + + BINTERNAL_SIZE(BOVERFLOW_SIZE) - 1) > + pagesize) + goto out; bo = (BOVERFLOW *)bi->data; M_32_SWAP(bo->pgno); M_32_SWAP(bo->tlen); @@ -600,12 +639,16 @@ __db_byteswap(dbp, pg, h, pagesize, pgin break; case P_IRECNO: for (i = 0; i < NUM_ENT(h); i++) { + if ((u_int8_t *)(inp + i) >= pgend) + return (__db_pgfmt(env, pg)); if (pgin) M_16_SWAP(inp[i]); + if (inp[i] >= pagesize) + return (__db_pgfmt(env, pg)); ri = GET_RINTERNAL(dbp, h, i); - if ((u_int8_t *)ri >= pgend) - continue; + if ((((u_int8_t *)ri) + RINTERNAL_SIZE) > pgend) + return (__db_pgfmt(env, pg)); M_32_SWAP(ri->pgno); M_32_SWAP(ri->nrecs); Index: db-4.8.30/db/db_vrfy.c =================================================================== --- db-4.8.30.orig/db/db_vrfy.c +++ db-4.8.30/db/db_vrfy.c @@ -360,8 +360,10 @@ __db_verify(dbp, ip, name, subdb, handle vdp, name, 0, lp, rp, flags)) != 0) { if (t_ret == DB_VERIFY_BAD) isbad = 1; - else + else { + ret = t_ret; goto err; + } } /* @@ -680,7 +682,10 @@ __db_vrfy_walkpages(dbp, vdp, handle, ca */ if ((t_ret = __memp_fget(mpf, &i, vdp->thread_info, NULL, 0, &h)) != 0) { - if (dbp->type == DB_HASH) { + if ((dbp->type == DB_HASH || + (dbp->type == DB_QUEUE && + F_ISSET(dbp, DB_AM_INMEM))) && + t_ret != DB_RUNRECOVERY) { if ((t_ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0) goto err1; @@ -840,6 +845,8 @@ err: if (h != NULL && (t_ret = __memp_f return (ret == 0 ? t_ret : ret); } + if (ret == DB_PAGE_NOTFOUND && isbad == 1) + ret = 0; return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); } @@ -1434,7 +1441,7 @@ __db_vrfy_meta(dbp, vdp, meta, pgno, fla */ if (pgno == PGNO_BASE_MD && meta->last_pgno != vdp->last_pgno) { #ifdef HAVE_FTRUNCATE - isbad = 1; + ret = DB_VERIFY_FATAL; EPRINT((env, "Page %lu: last_pgno is not correct: %lu != %lu", (u_long)pgno, @@ -1475,7 +1482,11 @@ __db_vrfy_freelist(dbp, vdp, meta, flags env = dbp->env; pgset = vdp->pgset; - DB_ASSERT(env, pgset != NULL); + if (pgset == NULL) { + EPRINT((env, + "Error, database contains no visible pages.")); + return (DB_RUNRECOVERY); + } if ((ret = __db_vrfy_getpageinfo(vdp, meta, &pip)) != 0) return (ret); @@ -1851,7 +1862,8 @@ __db_salvage_pg(dbp, vdp, pgno, h, handl int keyflag, ret, t_ret; env = dbp->env; - DB_ASSERT(env, LF_ISSET(DB_SALVAGE)); + if (!LF_ISSET(DB_SALVAGE)) + return (EINVAL); /* * !!! @@ -1974,10 +1986,8 @@ __db_salvage_leaf(dbp, vdp, pgno, h, han int (*callback) __P((void *, const void *)); u_int32_t flags; { - ENV *env; - - env = dbp->env; - DB_ASSERT(env, LF_ISSET(DB_SALVAGE)); + if (!LF_ISSET(DB_SALVAGE)) + return (EINVAL); /* If we got this page in the subdb pass, we can safely skip it. */ if (__db_salvage_isdone(vdp, pgno)) @@ -2068,8 +2078,8 @@ __db_salvage_unknowns(dbp, vdp, handle, ret = t_ret; break; case SALVAGE_OVERFLOW: - DB_ASSERT(env, 0); /* Shouldn't ever happen. */ - break; + EPRINT((env, "Invalid page type to salvage.")); + return (EINVAL); case SALVAGE_HASH: if ((t_ret = __ham_salvage(dbp, vdp, pgno, h, handle, callback, flags)) != 0 && ret == 0) @@ -2082,8 +2092,8 @@ __db_salvage_unknowns(dbp, vdp, handle, * Shouldn't happen, but if it does, just do what the * nice man says. */ - DB_ASSERT(env, 0); - break; + EPRINT((env, "Invalid page type to salvage.")); + return (EINVAL); } if ((t_ret = __memp_fput(mpf, vdp->thread_info, h, dbp->priority)) != 0 && ret == 0) @@ -2129,8 +2139,8 @@ __db_salvage_unknowns(dbp, vdp, handle, ret = t_ret; break; default: - DB_ASSERT(env, 0); /* Shouldn't ever happen. */ - break; + EPRINT((env, "Invalid page type to salvage.")); + return (EINVAL); } if ((t_ret = __memp_fput(mpf, vdp->thread_info, h, dbp->priority)) != 0 && ret == 0) @@ -2187,7 +2197,10 @@ __db_vrfy_inpitem(dbp, h, pgno, i, is_bt env = dbp->env; - DB_ASSERT(env, himarkp != NULL); + if (himarkp == NULL) { + __db_msg(env, "Page %lu index has no end.", pgno); + return (DB_VERIFY_FATAL); + } inp = P_INP(dbp, h); /* @@ -2597,7 +2610,11 @@ __db_salvage_subdbpg(dbp, vdp, master, h goto err; ovfl_bufsz = bkkey->len + 1; } - DB_ASSERT(env, subdbname != NULL); + if (subdbname == NULL) { + EPRINT((env, "Subdatabase cannot be null.")); + ret = EINVAL; + goto err; + } memcpy(subdbname, bkkey->data, bkkey->len); subdbname[bkkey->len] = '\0'; } Index: db-4.8.30/db/db_vrfyutil.c =================================================================== --- db-4.8.30.orig/db/db_vrfyutil.c +++ db-4.8.30/db/db_vrfyutil.c @@ -198,7 +198,8 @@ __db_vrfy_getpageinfo(vdp, pgno, pipp) if ((ret = __db_get(pgdbp, vdp->thread_info, NULL, &key, &data, 0)) == 0) { /* Found it. */ - DB_ASSERT(env, data.size == sizeof(VRFY_PAGEINFO)); + if (data.size != sizeof(VRFY_PAGEINFO)) + return (DB_VERIFY_FATAL); pip = data.data; LIST_INSERT_HEAD(&vdp->activepips, pip, links); goto found; @@ -325,7 +326,8 @@ __db_vrfy_pgset_get(dbp, ip, pgno, valp) F_SET(&data, DB_DBT_USERMEM); if ((ret = __db_get(dbp, ip, NULL, &key, &data, 0)) == 0) { - DB_ASSERT(dbp->env, data.size == sizeof(int)); + if (data.size != sizeof(int)) + return (EINVAL); } else if (ret == DB_NOTFOUND) val = 0; else @@ -363,7 +365,8 @@ __db_vrfy_pgset_inc(dbp, ip, pgno) F_SET(&data, DB_DBT_USERMEM); if ((ret = __db_get(dbp, ip, NULL, &key, &data, 0)) == 0) { - DB_ASSERT(dbp->env, data.size == sizeof(int)); + if (data.size != sizeof(int)) + return (DB_VERIFY_FATAL); } else if (ret != DB_NOTFOUND) return (ret); @@ -400,7 +403,8 @@ __db_vrfy_pgset_next(dbc, pgnop) if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT)) != 0) return (ret); - DB_ASSERT(dbc->env, key.size == sizeof(db_pgno_t)); + if (key.size != sizeof(db_pgno_t)) + return (DB_VERIFY_FATAL); *pgnop = pgno; return (0); @@ -547,7 +551,8 @@ __db_vrfy_ccset(dbc, pgno, cipp) if ((ret = __dbc_get(dbc, &key, &data, DB_SET)) != 0) return (ret); - DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO)); + if (data.size != sizeof(VRFY_CHILDINFO)) + return (DB_VERIFY_FATAL); *cipp = (VRFY_CHILDINFO *)data.data; return (0); @@ -575,7 +580,8 @@ __db_vrfy_ccnext(dbc, cipp) if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT_DUP)) != 0) return (ret); - DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO)); + if (data.size != sizeof(VRFY_CHILDINFO)) + return (DB_VERIFY_FATAL); *cipp = (VRFY_CHILDINFO *)data.data; return (0); @@ -702,7 +708,8 @@ __db_salvage_getnext(vdp, dbcp, pgnop, p return (ret); while ((ret = __dbc_get(*dbcp, &key, &data, DB_NEXT)) == 0) { - DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t)); + if (data.size != sizeof(u_int32_t)) + return (DB_VERIFY_FATAL); memcpy(&pgtype, data.data, sizeof(pgtype)); if (skip_overflow && pgtype == SALVAGE_OVERFLOW) @@ -711,8 +718,9 @@ __db_salvage_getnext(vdp, dbcp, pgnop, p if ((ret = __dbc_del(*dbcp, 0)) != 0) return (ret); if (pgtype != SALVAGE_IGNORE) { - DB_ASSERT(dbp->env, key.size == sizeof(db_pgno_t)); - DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t)); + if (key.size != sizeof(db_pgno_t) + || data.size != sizeof(u_int32_t)) + return (DB_VERIFY_FATAL); *pgnop = *(db_pgno_t *)key.data; *pgtypep = *(u_int32_t *)data.data; Index: db-4.8.30/db/partition.c =================================================================== --- db-4.8.30.orig/db/partition.c +++ db-4.8.30/db/partition.c @@ -452,10 +452,20 @@ __partition_chk_meta(dbp, ip, txn, flags } else part->nparts = meta->nparts; } else if (meta->nparts != 0 && part->nparts != meta->nparts) { + ret = EINVAL; __db_errx(env, "Number of partitions does not match."); ret = EINVAL; goto err; } + /* + * There is no limit on the number of partitions, but I cannot imagine a real + * database having more than 10000. + */ + if (meta->nparts > 10000) { + ret = EINVAL; + __db_errx(env, "Too many partitions %lu", meta->nparts); + goto err; + } if (meta->magic == DB_HASHMAGIC) { if (!F_ISSET(part, PART_CALLBACK)) { @@ -1863,10 +1874,13 @@ __part_verify(dbp, vdp, fname, handle, c memcpy(rp->data, key->data, key->size); B_TSET(rp->type, B_KEYDATA); } -vrfy: if ((t_ret = __db_verify(*pdbp, ip, (*pdbp)->fname, - NULL, handle, callback, - lp, rp, flags | DB_VERIFY_PARTITION)) != 0 && ret == 0) - ret = t_ret; +vrfy: if ((t_ret = __db_verify(*pdbp, ip, (*pdbp)->fname, + NULL, handle, callback, + lp, rp, flags | DB_VERIFY_PARTITION)) != 0 && ret == 0) { + ret = t_ret; + if (ret == ENOENT) + break; + } } err: if (lp != NULL) Index: db-4.8.30/hash/hash_page.c =================================================================== --- db-4.8.30.orig/hash/hash_page.c +++ db-4.8.30/hash/hash_page.c @@ -862,7 +862,11 @@ __ham_verify_sorted_page (dbc, p) /* Validate that next, prev pointers are OK */ n = NUM_ENT(p); dbp = dbc->dbp; - DB_ASSERT(dbp->env, n%2 == 0 ); + if (n % 2 != 0) { + __db_errx(dbp->env, + "Odd number of entries on page: %lu", (u_long)p->pgno); + return (DB_VERIFY_FATAL); + } env = dbp->env; t = dbp->h_internal; @@ -933,7 +937,12 @@ __ham_verify_sorted_page (dbc, p) if ((ret = __db_prpage(dbp, p, DB_PR_PAGE)) != 0) return (ret); #endif - DB_ASSERT(dbp->env, res < 0); + if (res >= 0) { + __db_errx(env, + "Odd number of entries on page: %lu", + (u_long)p->pgno); + return (DB_VERIFY_FATAL); + } } prev = curr; Index: db-4.8.30/hash/hash_verify.c =================================================================== --- db-4.8.30.orig/hash/hash_verify.c +++ db-4.8.30/hash/hash_verify.c @@ -562,7 +562,7 @@ __ham_vrfy_bucket(dbp, vdp, m, bucket, f "Page %lu: impossible first page in bucket %lu", (u_long)pgno, (u_long)bucket)); /* Unsafe to continue. */ - isbad = 1; + ret = DB_VERIFY_FATAL; goto err; } @@ -592,7 +592,7 @@ __ham_vrfy_bucket(dbp, vdp, m, bucket, f EPRINT((env, "Page %lu: hash page referenced twice", (u_long)pgno)); - isbad = 1; + ret = DB_VERIFY_FATAL; /* Unsafe to continue. */ goto err; } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, @@ -1036,7 +1036,11 @@ __ham_meta2pgset(dbp, vdp, hmeta, flags, COMPQUIET(flags, 0); ip = vdp->thread_info; - DB_ASSERT(dbp->env, pgset != NULL); + if (pgset == NULL) { + EPRINT((dbp->env, + "Error, database contains no visible pages.")); + return (DB_VERIFY_FATAL); + } mpf = dbp->mpf; totpgs = 0; Index: db-4.8.30/qam/qam_verify.c =================================================================== --- db-4.8.30.orig/qam/qam_verify.c +++ db-4.8.30/qam/qam_verify.c @@ -445,7 +445,13 @@ __qam_vrfy_walkqueue(dbp, vdp, handle, c /* Verify/salvage each page. */ if ((ret = __db_cursor(dbp, vdp->thread_info, NULL, &dbc, 0)) != 0) return (ret); -begin: for (; i <= stop; i++) { +begin: if ((stop - i) > 100000) { + EPRINT((env, "Warning, many possible extends files (%lu), will take a long time to verify", + (u_long)(stop - i))); + } + for (; i <= stop; i++) { + if (i == UINT32_MAX) + break; /* * If DB_SALVAGE is set, we inspect our database of completed * pages, and skip any we've already printed in the subdb pass.