From 37fd93194db10fc832ed3fa1ec880ebc26be904b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 6 Oct 2012 13:23:05 +0200 Subject: [PATCH] tdb: Make robust against shrinking tdbs When probing for a size change (eg. just before tdb_expand, tdb_check, tdb_rescue) we call tdb_oob(tdb, tdb->map_size, 1, 1). Unfortunately this does nothing if the tdb has actually shrunk, which as Volker demonstrated, can actually happen if a "longlived" parent crashes. So move the map/update size/remap before the limit check. Signed-off-by: Rusty Russell --- lib/tdb/common/io.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c index 3131f4fa0af..25968bfef2d 100644 --- a/lib/tdb/common/io.c +++ b/lib/tdb/common/io.c @@ -63,16 +63,6 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, return -1; } - if (st.st_size < (size_t)off + len) { - if (!probe) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n", - (int)(off + len), (int)st.st_size)); - } - return -1; - } - /* Beware >4G files! */ if ((tdb_off_t)st.st_size != st.st_size) { /* Ensure ecode is set for log fn. */ @@ -82,13 +72,31 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, return -1; } - /* Unmap, update size, remap */ + /* Unmap, update size, remap. We do this unconditionally, to handle + * the unusual case where the db is truncated. + * + * This can happen to a child using tdb_reopen_all(true) on a + * TDB_CLEAR_IF_FIRST tdb whose parent crashes: the next + * opener will truncate the database. */ if (tdb_munmap(tdb) == -1) { tdb->ecode = TDB_ERR_IO; return -1; } tdb->map_size = st.st_size; - return tdb_mmap(tdb); + if (tdb_mmap(tdb) != 0) { + return - 1; + } + + if (st.st_size < (size_t)off + len) { + if (!probe) { + /* Ensure ecode is set for log fn. */ + tdb->ecode = TDB_ERR_IO; + TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n", + (int)(off + len), (int)st.st_size)); + } + return -1; + } + return 0; } /* write a lump of data at a specified offset */ -- 2.11.4.GIT