From b8c60a3257294ab7558cb1c9f08683af9b32c366 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 9 Nov 2015 14:10:11 +1300 Subject: [PATCH 1/2] tdb: Refuse to load a database with hash size 0 Found with american fuzzy lop BUG: https://bugzilla.samba.org/show_bug.cgi?id=11603 Signed-off-by: Andrew Bartlett --- lib/tdb/common/open.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c index 3b53fa7..0c5d3c6 100644 --- a/lib/tdb/common/open.c +++ b/lib/tdb/common/open.c @@ -593,6 +593,11 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td errno = ENOSYS; goto fail; } + if (header.hash_size == 0) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: invalid database: 0 hash_size\n")); + errno = ENOSYS; + goto fail; + } tdb->hash_size = header.hash_size; if (header.rwlocks == TDB_FEATURE_FLAG_MAGIC) { -- 2.6.1 From 2747459e93b7c2f5b399c64cdbd2c982dbf4f5a9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 9 Nov 2015 18:07:56 -0800 Subject: [PATCH 2/2] tdb: Avoid integer overflow when loading database records Found with american fuzzy lop Based on a WIP patch by Jeremy Allison BUG: https://bugzilla.samba.org/show_bug.cgi?id=11603 Signed-off-by: Andrew Bartlett --- lib/tdb/common/tdb.c | 44 +++++++++++++++++++++++++++++++++++++++++++- lib/tdb/common/traverse.c | 14 ++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c index 9885d8c..964b108 100644 --- a/lib/tdb/common/tdb.c +++ b/lib/tdb/common/tdb.c @@ -160,7 +160,25 @@ static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, } /* must be long enough key, data and tailer */ - if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) { + if (rec.rec_len < sizeof(tdb_off_t)) { + tdb->ecode = TDB_SUCCESS; /* Not really an error */ + return -1; + } + + /* must be long enough key, data and tailer */ + if (rec.rec_len - sizeof(tdb_off_t) < key.dsize + dbuf.dsize) { + tdb->ecode = TDB_SUCCESS; /* Not really an error */ + return -1; + } + + /* must be long enough key, data and tailer */ + if (rec.rec_len - sizeof(tdb_off_t) < key.dsize) { + tdb->ecode = TDB_SUCCESS; /* Not really an error */ + return -1; + } + + /* must be long enough key, data and tailer */ + if (rec.rec_len - sizeof(tdb_off_t) < dbuf.dsize) { tdb->ecode = TDB_SUCCESS; /* Not really an error */ return -1; } @@ -250,6 +268,21 @@ _PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, } tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0); + if (rec_ptr + sizeof(rec) < rec_ptr) { + tdb->ecode = TDB_ERR_CORRUPT; + return -1; + } + + if (rec_ptr + rec.key_len < rec_ptr) { + tdb->ecode = TDB_ERR_CORRUPT; + return -1; + } + + if (rec_ptr + sizeof(rec) + rec.key_len < rec_ptr) { + tdb->ecode = TDB_ERR_CORRUPT; + return -1; + } + ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len, rec.data_len, parser, private_data); @@ -520,6 +553,15 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key, if (flag != TDB_INSERT) tdb_delete_hash(tdb, key, hash); + /* check for overflow */ + if (key.dsize + dbuf.dsize < key.dsize) { + goto fail; + } + + if (key.dsize + sizeof(rec) < key.dsize) { + goto fail; + } + /* we have to allocate some space */ rec_ptr = tdb_allocate(tdb, hash, key.dsize + dbuf.dsize, &rec); diff --git a/lib/tdb/common/traverse.c b/lib/tdb/common/traverse.c index e18e3c3..d8d72df 100644 --- a/lib/tdb/common/traverse.c +++ b/lib/tdb/common/traverse.c @@ -164,6 +164,20 @@ static int tdb_traverse_internal(struct tdb_context *tdb, goto out; } count++; + /* Check for overflows. */ + if (tl->off + sizeof(rec) < tl->off) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, + "tdb_traverse: bad tl->off\n"));; + ret = -1; + goto out; + } + if (rec.key_len + rec.data_len < rec.key_len) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, + "tdb_traverse: key_len + data_len\n"));; + ret = -1; + goto out; + } + /* now read the full record */ key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec), rec.key_len + rec.data_len); -- 2.6.1