diff options
author | Volker Lendecke <vl@samba.org> | 2013-05-30 15:24:27 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2013-06-03 10:21:31 +0200 |
commit | 8b215df4454883b3733733af4f49f87eb0a2a46a (patch) | |
tree | c6493a0cce6c8cf147df1c666ae6dcb483770388 | |
parent | 7ae09a9695bcc5fad606441db3ab6e413b9d48ce (diff) | |
download | samba-8b215df4454883b3733733af4f49f87eb0a2a46a.tar.gz samba-8b215df4454883b3733733af4f49f87eb0a2a46a.tar.bz2 samba-8b215df4454883b3733733af4f49f87eb0a2a46a.zip |
tdb: Make tdb_recovery_size overflow-safe
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | lib/tdb/common/tdb_private.h | 3 | ||||
-rw-r--r-- | lib/tdb/common/transaction.c | 32 |
2 files changed, 28 insertions, 7 deletions
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h index c37246f150..ce92188688 100644 --- a/lib/tdb/common/tdb_private.h +++ b/lib/tdb/common/tdb_private.h @@ -283,4 +283,7 @@ void tdb_header_hash(struct tdb_context *tdb, unsigned int tdb_old_hash(TDB_DATA *key); size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off); bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret); + +/* tdb_off_t and tdb_len_t right now are both uint32_t */ +#define tdb_add_len_t tdb_add_off_t #endif /* TDB_PRIVATE_H */ diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c index 81cfd16942..080d0586c3 100644 --- a/lib/tdb/common/transaction.c +++ b/lib/tdb/common/transaction.c @@ -630,28 +630,37 @@ _PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb) /* work out how much space the linearised recovery data will consume */ -static tdb_len_t tdb_recovery_size(struct tdb_context *tdb) +static bool tdb_recovery_size(struct tdb_context *tdb, tdb_len_t *result) { tdb_len_t recovery_size = 0; int i; recovery_size = sizeof(uint32_t); for (i=0;i<tdb->transaction->num_blocks;i++) { + tdb_len_t block_size; if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) { break; } if (tdb->transaction->blocks[i] == NULL) { continue; } - recovery_size += 2*sizeof(tdb_off_t); + if (!tdb_add_len_t(recovery_size, 2*sizeof(tdb_off_t), + &recovery_size)) { + return false; + } if (i == tdb->transaction->num_blocks-1) { - recovery_size += tdb->transaction->last_block_size; + block_size = tdb->transaction->last_block_size; } else { - recovery_size += tdb->transaction->block_size; + block_size = tdb->transaction->block_size; + } + if (!tdb_add_len_t(recovery_size, block_size, + &recovery_size)) { + return false; } } - return recovery_size; + *result = recovery_size; + return true; } int tdb_recovery_area(struct tdb_context *tdb, @@ -700,7 +709,11 @@ static int tdb_recovery_allocate(struct tdb_context *tdb, return -1; } - *recovery_size = tdb_recovery_size(tdb); + if (!tdb_recovery_size(tdb, recovery_size)) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: " + "overflow recovery size\n")); + return -1; + } /* Existing recovery area? */ if (recovery_head != 0 && *recovery_size <= rec.rec_len) { @@ -728,7 +741,12 @@ static int tdb_recovery_allocate(struct tdb_context *tdb, /* the tdb_free() call might have increased * the recovery size */ - *recovery_size = tdb_recovery_size(tdb); + if (!tdb_recovery_size(tdb, recovery_size)) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, + "tdb_recovery_allocate: " + "overflow recovery size\n")); + return -1; + } } /* New head will be at end of file. */ |