--- db-18.1.32/src/btree/bt_cursor.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/btree/bt_cursor.c 2020-05-29 23:28:22.000000000 +0530 @@ -282,6 +282,8 @@ * * 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); --- db-18.1.32/src/btree/bt_verify.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/btree/bt_verify.c 2020-05-29 23:28:22.000000000 +0530 @@ -700,7 +700,11 @@ isbad = 1; goto err; default: + if (ret == 0) { + isbad = 1; + ret = DB_VERIFY_FATAL; + goto err; + } - DB_ASSERT(env, ret != 0); break; } @@ -1074,7 +1078,7 @@ DBT dbta, dbtb, dup_1, dup_2, *p1, *p2, *tmp; ENV *env; PAGE *child; + db_pgno_t cpgno, grandparent; - db_pgno_t cpgno; VRFY_PAGEINFO *pip; db_indx_t i, *inp; int adj, cmp, freedup_1, freedup_2, isbad, ret, t_ret; @@ -1106,7 +1110,8 @@ buf1 = buf2 = NULL; + if (LF_ISSET(DB_NOORDERCHK)) + return (EINVAL); - DB_ASSERT(env, !LF_ISSET(DB_NOORDERCHK)); dupfunc = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare; if (TYPE(h) == P_LDUP) @@ -1115,6 +1120,7 @@ func = __bam_defcmp; if (dbp->bt_internal != NULL) { bt = (BTREE *)dbp->bt_internal; + grandparent = bt->bt_root; if (TYPE(h) == P_IBTREE && (bt->bt_compare != NULL || dupfunc != __bam_defcmp)) { /* @@ -974,8 +980,24 @@ */ mpf = dbp->mpf; child = h; + cpgno = pgno; while (TYPE(child) == P_IBTREE) { + if (NUM_ENT(child) == 0) { + EPRINT((env, DB_STR_A("1088", + "Page %lu: internal page is empty and should not be", + "%lu"), (u_long)cpgno)); + ret = DB_VERIFY_BAD; + goto err; + } bi = GET_BINTERNAL(dbp, child, 0); + if (grandparent == bi->pgno) { + EPRINT((env, DB_STR_A("5552", + "Page %lu: found twice in the btree", + "%lu"), (u_long)grandparent)); + ret = DB_VERIFY_FATAL; + goto err; + } else + grandparent = cpgno; cpgno = bi->pgno; if (child != h && (ret = __memp_fput(mpf, @@ -1402,7 +1416,10 @@ */ if (dup_1.data == NULL || dup_2.data == NULL) { + if (ovflok) { + isbad = 1; + goto err; + } - DB_ASSERT(env, !ovflok); if (pip != NULL) F_SET(pip, VRFY_INCOMPLETE); @@ -1747,9 +1764,10 @@ (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; + break; + } else - else goto done; } @@ -1823,9 +1841,10 @@ stflags | DB_ST_TOPLEVEL, NULL, NULL, NULL)) != 0) { if (ret == + DB_VERIFY_BAD) { - DB_VERIFY_BAD) isbad = 1; + break; + } else - else goto err; } } @@ -1969,7 +1988,10 @@ */ /* Otherwise, __db_vrfy_childput would be broken. */ + if (child->refcnt < 1) { + isbad = 1; + goto err; + } - DB_ASSERT(env, child->refcnt >= 1); /* * An overflow referenced more than twice here @@ -1986,9 +2008,10 @@ 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; + break; + } else - else goto done; } } @@ -2026,9 +2049,10 @@ if ((ret = __bam_vrfy_subtree(dbp, vdp, li->pgno, i == 0 ? NULL : li, ri, flags, &child_level, &child_nrecs, NULL)) != 0) { + if (ret == DB_VERIFY_BAD) { - if (ret == DB_VERIFY_BAD) isbad = 1; + break; + } else - else goto done; } @@ -2929,7 +2953,11 @@ db_pgno_t current, p; int err_ret, ret; + if (pgset == NULL) { + EPRINT((dbp->env, DB_STR("5542", + "Error, database contains no visible pages."))); + return (DB_RUNRECOVERY); + } - DB_ASSERT(dbp->env, pgset != NULL); mpf = dbp->mpf; h = NULL; --- db-18.1.32/src/db/db_conv.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/db/db_conv.c 2020-05-29 23:28:22.000000000 +0530 @@ -493,8 +493,11 @@ 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); if (pgin) { M_32_SWAP(h->lsn.file); @@ -513,26 +516,41 @@ 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; + if (P_ENTRY(dbp, h, i) >= pgend) + 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, @@ -544,14 +562,20 @@ 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 */ @@ -559,7 +583,6 @@ default: return (__db_pgfmt(env, pg)); } - } /* @@ -576,8 +599,12 @@ 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 @@ -597,7 +624,7 @@ 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); @@ -605,6 +632,8 @@ 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; @@ -618,12 +647,17 @@ 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); @@ -634,6 +668,10 @@ 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); @@ -648,12 +686,16 @@ 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); --- db-18.1.32/src/db/db_vrfy.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/db/db_vrfy.c 2020-05-29 23:28:22.000000000 +0530 @@ -381,8 +381,10 @@ vdp, name, 0, lp, rp, flags)) != 0) { if (t_ret == DB_VERIFY_BAD) isbad = 1; + else { + ret = t_ret; + goto err; + } - else - goto err; } /* @@ -771,9 +773,10 @@ */ 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) { - F_ISSET(dbp, DB_AM_INMEM))) { if ((t_ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0) goto err1; @@ -945,6 +948,8 @@ return (ret == 0 ? t_ret : ret); } + if (ret == DB_PAGE_NOTFOUND && isbad == 1) + ret = 0; return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); } @@ -1581,7 +1586,7 @@ if (pgno == PGNO_BASE_MD && dbtype != DB_QUEUE && meta->last_pgno != vdp->last_pgno) { #ifdef HAVE_FTRUNCATE + ret = DB_VERIFY_FATAL; - isbad = 1; EPRINT((env, DB_STR_A("0552", "Page %lu: last_pgno is not correct: %lu != %lu", "%lu %lu %lu"), (u_long)pgno, @@ -1622,7 +1627,11 @@ env = dbp->env; pgset = vdp->pgset; + if (pgset == NULL) { + EPRINT((env, DB_STR("5543", + "Error, database contains no visible pages."))); + return (DB_RUNRECOVERY); + } - DB_ASSERT(env, pgset != NULL); if ((ret = __db_vrfy_getpageinfo(vdp, meta, &pip)) != 0) return (ret); @@ -2014,7 +2023,8 @@ int keyflag, ret, t_ret; env = dbp->env; + if (!LF_ISSET(DB_SALVAGE)) + return (EINVAL); - DB_ASSERT(env, LF_ISSET(DB_SALVAGE)); /* * !!! @@ -2126,10 +2136,8 @@ 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)) @@ -2242,8 +2253,8 @@ ret = t_ret; break; case SALVAGE_OVERFLOW: + EPRINT((env, DB_STR("5544", "Invalid page type to salvage."))); + return (EINVAL); - DB_ASSERT(env, 0); /* Shouldn't ever happen. */ - break; case SALVAGE_HASH: if ((t_ret = __ham_salvage(dbp, vdp, pgno, h, handle, callback, flags)) != 0 && ret == 0) @@ -2256,8 +2267,8 @@ * Shouldn't happen, but if it does, just do what the * nice man says. */ + EPRINT((env, DB_STR("5545", "Invalid page type to salvage."))); + return (EINVAL); - DB_ASSERT(env, 0); - break; } if ((t_ret = __memp_fput(mpf, vdp->thread_info, h, dbp->priority)) != 0 && ret == 0) @@ -2303,8 +2314,8 @@ ret = t_ret; break; default: + EPRINT((env, DB_STR("5546", "Invalid page type to salvage."))); + return (EINVAL); - DB_ASSERT(env, 0); /* Shouldn't ever happen. */ - break; } if ((t_ret = __memp_fput(mpf, vdp->thread_info, h, dbp->priority)) != 0 && ret == 0) @@ -2361,7 +2372,10 @@ env = dbp->env; + if (himarkp == NULL) { + __db_msg(env, "Page %lu index has no end.", (u_long)pgno); + return (DB_VERIFY_FATAL); + } - DB_ASSERT(env, himarkp != NULL); inp = P_INP(dbp, h); /* @@ -2783,7 +2797,11 @@ goto err; ovfl_bufsz = bkkey->len + 1; } + if (subdbname == NULL) { + EPRINT((env, DB_STR("5547", "Subdatabase cannot be null."))); + ret = EINVAL; + goto err; + } - DB_ASSERT(env, subdbname != NULL); memcpy(subdbname, bkkey->data, bkkey->len); subdbname[bkkey->len] = '\0'; } --- db-18.1.32/src/db/db_vrfyutil.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/db/db_vrfyutil.c 2020-05-29 23:28:22.000000000 +0530 @@ -214,7 +214,8 @@ if ((ret = __db_get(pgdbp, vdp->thread_info, vdp->txn, &key, &data, 0)) == 0) { /* Found it. */ + if (data.size != sizeof(VRFY_PAGEINFO)) + return (DB_VERIFY_FATAL); - DB_ASSERT(env, data.size == sizeof(VRFY_PAGEINFO)); pip = data.data; LIST_INSERT_HEAD(&vdp->activepips, pip, links); goto found; @@ -342,7 +343,8 @@ F_SET(&data, DB_DBT_USERMEM); if ((ret = __db_get(dbp, ip, txn, &key, &data, 0)) == 0) { + if (data.size != sizeof(int)) + return (EINVAL); - DB_ASSERT(dbp->env, data.size == sizeof(int)); } else if (ret == DB_NOTFOUND) val = 0; else @@ -382,7 +384,8 @@ F_SET(&data, DB_DBT_USERMEM); if ((ret = __db_get(dbp, ip, txn, &key, &data, 0)) == 0) { + if (data.size != sizeof(int)) + return (DB_VERIFY_FATAL); - DB_ASSERT(dbp->env, data.size == sizeof(int)); } else if (ret != DB_NOTFOUND) return (ret); @@ -419,7 +422,8 @@ if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT)) != 0) return (ret); + if (key.size != sizeof(db_pgno_t)) + return (DB_VERIFY_FATAL); - DB_ASSERT(dbc->env, key.size == sizeof(db_pgno_t)); *pgnop = pgno; return (0); @@ -566,7 +570,8 @@ if ((ret = __dbc_get(dbc, &key, &data, DB_SET)) != 0) return (ret); + if (data.size != sizeof(VRFY_CHILDINFO)) + return (DB_VERIFY_FATAL); - DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO)); *cipp = (VRFY_CHILDINFO *)data.data; return (0); @@ -594,7 +599,8 @@ if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT_DUP)) != 0) return (ret); + if (data.size != sizeof(VRFY_CHILDINFO)) + return (DB_VERIFY_FATAL); - DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO)); *cipp = (VRFY_CHILDINFO *)data.data; return (0); @@ -721,7 +727,8 @@ return (ret); while ((ret = __dbc_get(*dbcp, &key, &data, DB_NEXT)) == 0) { + if (data.size != sizeof(u_int32_t)) + return (DB_VERIFY_FATAL); - DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t)); memcpy(&pgtype, data.data, sizeof(pgtype)); if (skip_overflow && pgtype == SALVAGE_OVERFLOW) @@ -730,8 +737,9 @@ if ((ret = __dbc_del(*dbcp, 0)) != 0) return (ret); if (pgtype != SALVAGE_IGNORE) { + if (key.size != sizeof(db_pgno_t) + || data.size != sizeof(u_int32_t)) + return (DB_VERIFY_FATAL); - DB_ASSERT(dbp->env, key.size == sizeof(db_pgno_t)); - DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t)); *pgnop = *(db_pgno_t *)key.data; *pgtypep = *(u_int32_t *)data.data; --- db-18.1.32/src/db/partition.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/db/partition.c 2020-05-29 23:28:22.000000000 +0530 @@ -461,9 +461,19 @@ } else part->nparts = meta->nparts; } else if (meta->nparts != 0 && part->nparts != meta->nparts) { + ret = EINVAL; __db_errx(env, DB_STR("0656", "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, DB_STR_A("5553", + "Too many partitions %lu", "%lu"), (u_long)(meta->nparts)); goto err; } @@ -2106,10 +2116,13 @@ 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; + if (ret == ENOENT) + break; + } -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; } err: if (lp != NULL) --- db-18.1.32/src/hash/hash_page.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/hash/hash_page.c 2020-05-29 23:28:22.000000000 +0530 @@ -869,7 +869,11 @@ /* Validate that next, prev pointers are OK */ n = NUM_ENT(p); dbp = dbc->dbp; + if (n % 2 != 0) { + __db_errx(dbp->env, DB_STR_A("5549", + "Odd number of entries on page: %lu", "%lu"), (u_long)(p->pgno)); + return (DB_VERIFY_FATAL); + } - DB_ASSERT(dbp->env, n%2 == 0 ); env = dbp->env; t = dbp->h_internal; @@ -940,7 +944,12 @@ if ((ret = __db_prpage(dbp, p, DB_PR_PAGE)) != 0) return (ret); #endif + if (res >= 0) { + __db_errx(env, DB_STR_A("5550", + "Odd number of entries on page: %lu", "%lu"), + (u_long)p->pgno); + return (DB_VERIFY_FATAL); + } - DB_ASSERT(dbp->env, res < 0); } prev = curr; --- db-18.1.32/src/hash/hash_verify.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/hash/hash_verify.c 2020-05-29 23:28:22.000000000 +0530 @@ -615,7 +615,7 @@ isbad = 1; else goto err; + } - } /* * There may be unused hash pages corresponding to buckets @@ -746,7 +746,7 @@ "Page %lu: impossible first page in bucket %lu", "%lu %lu"), (u_long)pgno, (u_long)bucket)); /* Unsafe to continue. */ + ret = DB_VERIFY_FATAL; - isbad = 1; goto err; } @@ -776,7 +776,7 @@ EPRINT((env, DB_STR_A("1116", "Page %lu: hash page referenced twice", "%lu"), (u_long)pgno)); + ret = DB_VERIFY_FATAL; - isbad = 1; /* Unsafe to continue. */ goto err; } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, @@ -1307,7 +1307,11 @@ COMPQUIET(flags, 0); ip = vdp->thread_info; + if (pgset == NULL) { + EPRINT((dbp->env, DB_STR("5548", + "Error, database contains no visible pages."))); + return (DB_VERIFY_FATAL); + } - DB_ASSERT(dbp->env, pgset != NULL); mpf = dbp->mpf; totpgs = 0; --- db-18.1.32/src/qam/qam_verify.c 2019-02-20 03:21:20.000000000 +0530 +++ db-18.1.40/src/qam/qam_verify.c 2020-05-29 23:28:22.000000000 +0530 @@ -465,7 +465,14 @@ /* 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, DB_STR_A("5551", +"Warning, many possible extends files (%lu), will take a long time to verify", + "%lu"), (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.