diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2012-10-06 13:23:05 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2012-10-06 13:23:41 +0200 |
commit | 37fd93194db10fc832ed3fa1ec880ebc26be904b (patch) | |
tree | 6ee8e6ef1d15123fc4775cc687c872f6d77ea842 /lib/tdb/common/io.c | |
parent | 828793852f3785c620f2716c60f8b1640880ee50 (diff) | |
download | samba-37fd93194db10fc832ed3fa1ec880ebc26be904b.tar.gz |
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 <rusty@rustcorp.com.au>
Diffstat (limited to 'lib/tdb/common/io.c')
-rw-r--r-- | lib/tdb/common/io.c | 32 |
1 files 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 */ |