Commit ed81f394 authored by Rusty Russell's avatar Rusty Russell

tdb2: make sure records with extra padding have a 0 byte.

As detailed in doc/design.lyx section 2.16 "Record Headers Are Not
Expandible", we make sure that if there is padding at the end of a record,
the first byte of padding is a zero.
parent 812391f1
......@@ -30,7 +30,8 @@ static bool append(tdb_off_t **arr, size_t *num, tdb_off_t off)
return true;
}
static enum TDB_ERROR check_header(struct tdb_context *tdb, tdb_off_t *recovery)
static enum TDB_ERROR check_header(struct tdb_context *tdb, tdb_off_t *recovery,
uint64_t *features)
{
uint64_t hash_test;
struct tdb_header hdr;
......@@ -59,6 +60,16 @@ static enum TDB_ERROR check_header(struct tdb_context *tdb, tdb_off_t *recovery)
hdr.magic_food);
}
/* Features which are used must be a subset of features offered. */
if (hdr.features_used & ~hdr.features_offered) {
return tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
"check: features used (0x%llx) which"
" are not offered (0x%llx)",
(long long)hdr.features_used,
(long long)hdr.features_offered);
}
*features = hdr.features_offered;
*recovery = hdr.recovery;
if (*recovery) {
if (*recovery < sizeof(hdr) || *recovery > tdb->map_size) {
......@@ -568,7 +579,7 @@ tdb_off_t dead_space(struct tdb_context *tdb, tdb_off_t off)
static enum TDB_ERROR check_linear(struct tdb_context *tdb,
tdb_off_t **used, size_t *num_used,
tdb_off_t **fr, size_t *num_free,
tdb_off_t recovery)
uint64_t features, tdb_off_t recovery)
{
tdb_off_t off;
tdb_len_t len;
......@@ -697,6 +708,28 @@ static enum TDB_ERROR check_linear(struct tdb_context *tdb,
(long long)len,
(long long)off);
}
/* Check that records have correct 0 at end (but may
* not in future). */
if (extra && !features) {
const char *p;
char c;
p = tdb_access_read(tdb, off + sizeof(rec.u)
+ klen + dlen, 1, false);
if (TDB_PTR_IS_ERR(p))
return TDB_PTR_ERR(p);
c = *p;
tdb_access_release(tdb, p);
if (c != '\0') {
return tdb_logerr(tdb, TDB_ERR_CORRUPT,
TDB_LOG_ERROR,
"tdb_check:"
" non-zero extra"
" at %llu",
(long long)off);
}
}
} else {
return tdb_logerr(tdb, TDB_ERR_CORRUPT,
TDB_LOG_ERROR,
......@@ -724,6 +757,7 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb,
{
tdb_off_t *fr = NULL, *used = NULL, ft, recovery;
size_t num_free = 0, num_used = 0, num_found = 0, num_ftables = 0;
uint64_t features;
enum TDB_ERROR ecode;
ecode = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
......@@ -737,12 +771,13 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb,
return ecode;
}
ecode = check_header(tdb, &recovery);
ecode = check_header(tdb, &recovery, &features);
if (ecode != TDB_SUCCESS)
goto out;
/* First we do a linear scan, checking all records. */
ecode = check_linear(tdb, &used, &num_used, &fr, &num_free, recovery);
ecode = check_linear(tdb, &used, &num_used, &fr, &num_free, features,
recovery);
if (ecode != TDB_SUCCESS)
goto out;
......
......@@ -1434,7 +1434,13 @@ Status
\end_layout
\begin_layout Standard
\change_deleted 0 1300360766
Incomplete.
\change_inserted 0 1300360767
Complete.
\change_unchanged
\end_layout
\begin_layout Subsection
......
......@@ -523,6 +523,15 @@ again:
goto unlock_err;
}
/* For futureproofing, we put a 0 in any unused space. */
if (rec_extra_padding(&rec)) {
ecode = tdb->methods->twrite(tdb, best_off + sizeof(rec)
+ keylen + datalen, "", 1);
if (ecode != TDB_SUCCESS) {
goto unlock_err;
}
}
/* Bucket of leftover will be <= current bucket, so nested
* locking is allowed. */
if (leftover) {
......
......@@ -510,6 +510,21 @@ static enum TDB_ERROR replace_data(struct tdb_context *tdb,
return TDB_SUCCESS;
}
static enum TDB_ERROR update_data(struct tdb_context *tdb,
tdb_off_t off,
struct tdb_data dbuf,
tdb_len_t extra)
{
enum TDB_ERROR ecode;
ecode = tdb->methods->twrite(tdb, off, dbuf.dptr, dbuf.dsize);
if (ecode == TDB_SUCCESS && extra) {
/* Put a zero in; future versions may append other data. */
ecode = tdb->methods->twrite(tdb, off + dbuf.dsize, "", 1);
}
return ecode;
}
enum TDB_ERROR tdb_store(struct tdb_context *tdb,
struct tdb_data key, struct tdb_data dbuf, int flag)
{
......@@ -542,11 +557,10 @@ enum TDB_ERROR tdb_store(struct tdb_context *tdb,
if (ecode != TDB_SUCCESS) {
goto out;
}
ecode = tdb->methods->twrite(tdb,
off + sizeof(rec)
+ key.dsize,
dbuf.dptr,
dbuf.dsize);
ecode = update_data(tdb,
off + sizeof(rec)
+ key.dsize, dbuf,
old_room - dbuf.dsize);
if (ecode != TDB_SUCCESS) {
goto out;
}
......@@ -602,8 +616,8 @@ enum TDB_ERROR tdb_append(struct tdb_context *tdb,
}
off += sizeof(rec) + key.dsize + old_dlen;
ecode = tdb->methods->twrite(tdb, off, dbuf.dptr,
dbuf.dsize);
ecode = update_data(tdb, off, dbuf,
rec_extra_padding(&rec));
goto out;
}
......
......@@ -92,6 +92,12 @@ static void set_free_record(void *mem, tdb_len_t len)
/* We do all the work in add_to_freetable */
}
static void add_zero_pad(struct tdb_used_record *u, size_t len, size_t extra)
{
if (extra)
((char *)(u + 1))[len] = '\0';
}
static void set_data_record(void *mem, struct tdb_context *tdb,
struct tle_used *used)
{
......@@ -103,6 +109,7 @@ static void set_data_record(void *mem, struct tdb_context *tdb,
memcpy(u + 1, used->key.dptr, used->key.dsize);
memcpy((char *)(u + 1) + used->key.dsize,
used->data.dptr, used->data.dsize);
add_zero_pad(u, used->key.dsize + used->data.dsize, used->extra);
}
static void set_hashtable(void *mem, struct tdb_context *tdb,
......@@ -113,6 +120,7 @@ static void set_hashtable(void *mem, struct tdb_context *tdb,
set_header(tdb, u, TDB_HTABLE_MAGIC, 0, len, len + htable->extra, 0);
memset(u + 1, 0, len);
add_zero_pad(u, len, htable->extra);
}
static void set_freetable(void *mem, struct tdb_context *tdb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment