summaryrefslogtreecommitdiffstats
path: root/lib/tdb/common
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2013-05-30 15:24:27 +0200
committerVolker Lendecke <vl@samba.org>2013-06-03 10:21:31 +0200
commit8b215df4454883b3733733af4f49f87eb0a2a46a (patch)
treec6493a0cce6c8cf147df1c666ae6dcb483770388 /lib/tdb/common
parent7ae09a9695bcc5fad606441db3ab6e413b9d48ce (diff)
downloadsamba-8b215df4454883b3733733af4f49f87eb0a2a46a.tar.gz
samba-8b215df4454883b3733733af4f49f87eb0a2a46a.tar.xz
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>
Diffstat (limited to 'lib/tdb/common')
-rw-r--r--lib/tdb/common/tdb_private.h3
-rw-r--r--lib/tdb/common/transaction.c32
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. */