From 61957a1523a8192fc284243765f82a3cf03ac296 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 21 Oct 2010 11:55:19 +0200 Subject: [PATCH] tdb: put example hashes into header, so we notice incorrect hash_fn. This is Stefan Metzmacher 's patch with minor changes: 1) Use the TDB_MAGIC constant so both hashes aren't of strings. 2) Check the hash in tdb_check (paranoia, really). 3) Additional check in the (unlikely!) case where both examples hash to 0. 4) Cosmetic changes to var names and complaint message. Signed-off-by: Rusty Russell (cherry picked (modified for v3-4) from commit 786b7263000dedcb97e7369402e2e9dc967e36c4) Signed-off-by: Stefan Metzmacher --- lib/tdb/common/open.c | 55 +++++++++++++++++++++++++++++++++++- lib/tdb/common/tdb_private.h | 8 ++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c index 49b8e85f12..9eaa701b7d 100644 --- a/lib/tdb/common/open.c +++ b/lib/tdb/common/open.c @@ -44,6 +44,25 @@ static unsigned int default_tdb_hash(TDB_DATA *key) return (1103515243 * value + 12345); } +/* We use two hashes to double-check they're using the right hash function. */ +void tdb_header_hash(struct tdb_context *tdb, + uint32_t *magic1_hash, uint32_t *magic2_hash) +{ + TDB_DATA hash_key; + uint32_t tdb_magic = TDB_MAGIC; + + hash_key.dptr = (unsigned char *)TDB_MAGIC_FOOD; + hash_key.dsize = sizeof(TDB_MAGIC_FOOD); + *magic1_hash = tdb->hash_fn(&hash_key); + + hash_key.dptr = CONVERT(tdb_magic); + hash_key.dsize = sizeof(tdb_magic); + *magic2_hash = tdb->hash_fn(&hash_key); + + /* Make sure at least one hash is non-zero! */ + if (*magic1_hash == 0 && *magic2_hash == 0) + *magic1_hash = 1; +} /* initialise a new database with a specified hash size */ static int tdb_new_database(struct tdb_context *tdb, int hash_size) @@ -61,6 +80,9 @@ static int tdb_new_database(struct tdb_context *tdb, int hash_size) /* Fill in the header */ newdb->version = TDB_VERSION; newdb->hash_size = hash_size; + + tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash); + if (tdb->flags & TDB_INTERNAL) { tdb->map_size = size; tdb->map_ptr = (char *)newdb; @@ -153,6 +175,9 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, unsigned char *vp; uint32_t vertest; unsigned v; + uint32_t magic1_hash; + uint32_t magic2_hash; + const char *hash_alg; if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { /* Can't log this */ @@ -171,7 +196,14 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, tdb->log.log_fn = null_log_fn; tdb->log.log_private = NULL; } - tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash; + + if (hash_fn) { + tdb->hash_fn = hash_fn; + hash_alg = "user defined"; + } else { + tdb->hash_fn = default_tdb_hash; + hash_alg = "default"; + } /* cache the page size */ tdb->page_size = getpagesize(); @@ -270,6 +302,27 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, goto fail; } + tdb_header_hash(tdb, &magic1_hash, &magic2_hash); + + if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) { + /* older TDB without magic hash references */ + } else if ((tdb->header.magic1_hash != magic1_hash) || + (tdb->header.magic2_hash != magic2_hash)) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " + "%s was not created with the %s hash function we are using\n" + "magic1_hash[0x%08X %s 0x%08X] " + "magic2_hash[0x%08X %s 0x%08X]\n", + name, hash_alg, + tdb->header.magic1_hash, + (tdb->header.magic1_hash == magic1_hash) ? "==" : "!=", + magic1_hash, + tdb->header.magic2_hash, + (tdb->header.magic2_hash == magic2_hash) ? "==" : "!=", + magic2_hash)); + errno = EINVAL; + goto fail; + } + /* Is it already in the open list? If so, fail. */ if (tdb_already_open(st.st_dev, st.st_ino)) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h index 562b813ff1..92a2a302f0 100644 --- a/lib/tdb/common/tdb_private.h +++ b/lib/tdb/common/tdb_private.h @@ -114,7 +114,9 @@ struct tdb_header { tdb_off_t rwlocks; /* obsolete - kept to detect old formats */ tdb_off_t recovery_start; /* offset of transaction recovery region */ tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */ - tdb_off_t reserved[29]; + uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */ + uint32_t magic2_hash; /* hash of TDB_MAGIC. */ + tdb_off_t reserved[27]; }; struct tdb_lock_type { @@ -209,5 +211,5 @@ void tdb_io_init(struct tdb_context *tdb); int tdb_expand(struct tdb_context *tdb, tdb_off_t size); int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec); - - +void tdb_header_hash(struct tdb_context *tdb, + uint32_t *magic1_hash, uint32_t *magic2_hash); -- 2.34.1