]> git.ozlabs.org Git - ccan/commitdiff
tdb2: careful on wrap.
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 21 Dec 2011 05:54:41 +0000 (16:24 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 21 Dec 2011 05:54:41 +0000 (16:24 +1030)
It's much harder to wrap a 64-bit tdb2 than a 32-bit tdb1, but we should still
take care against bugs.

Also, we should *not* cast the length to a size_t when comparing it to
the stat result, in case size_t is 32 bit.

ccan/tdb2/check.c
ccan/tdb2/free.c
ccan/tdb2/io.c
ccan/tdb2/open.c
ccan/tdb2/private.h
ccan/tdb2/transaction.c

index 238a5b3a4659ef1fd6b37a6ed764135deeb364cc..ecd6c13c5394bc97e2b4e923cf3bdc2ca5110fc2 100644 (file)
@@ -497,8 +497,8 @@ static enum TDB_ERROR check_free(struct tdb_context *tdb,
 
        }
 
 
        }
 
-       ecode = tdb->tdb2.io->oob(tdb, off
-                                 frec_len(frec)
+       ecode = tdb->tdb2.io->oob(tdb, off,
+                                 frec_len(frec)
                                  + sizeof(struct tdb_used_record),
                                  false);
        if (ecode != TDB_SUCCESS) {
                                  + sizeof(struct tdb_used_record),
                                  false);
        if (ecode != TDB_SUCCESS) {
index 1b2c552a66fecea4a5e3190a4b4d3e1f5fe51cc3..03ca5a4f9471c17920bb9b1d44b7953e2f560eea 100644 (file)
@@ -898,7 +898,7 @@ static enum TDB_ERROR tdb_expand(struct tdb_context *tdb, tdb_len_t size)
 
        /* Someone else may have expanded the file, so retry. */
        old_size = tdb->file->map_size;
 
        /* Someone else may have expanded the file, so retry. */
        old_size = tdb->file->map_size;
-       tdb->tdb2.io->oob(tdb, tdb->file->map_size + 1, true);
+       tdb->tdb2.io->oob(tdb, tdb->file->map_size, 1, true);
        if (tdb->file->map_size != old_size) {
                tdb_unlock_expand(tdb, F_WRLCK);
                return TDB_SUCCESS;
        if (tdb->file->map_size != old_size) {
                tdb_unlock_expand(tdb, F_WRLCK);
                return TDB_SUCCESS;
index afab0c1a4cc37879abd9ffcd626dc9b4a49d20e0..b4a6f0beae11160ac37ab7987d957c81e92612ac 100644 (file)
@@ -81,8 +81,8 @@ void tdb_mmap(struct tdb_context *tdb)
 
    If probe is true, len being too large isn't a failure.
 */
 
    If probe is true, len being too large isn't a failure.
 */
-static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
-                             bool probe)
+static enum TDB_ERROR tdb_oob(struct tdb_context *tdb,
+                             tdb_off_t off, tdb_len_t len, bool probe)
 {
        struct stat st;
        enum TDB_ERROR ecode;
 {
        struct stat st;
        enum TDB_ERROR ecode;
@@ -92,7 +92,16 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
               || (tdb->flags & TDB_NOLOCK)
               || tdb_has_expansion_lock(tdb));
 
               || (tdb->flags & TDB_NOLOCK)
               || tdb_has_expansion_lock(tdb));
 
-       if (len <= tdb->file->map_size)
+       if (len + off < len) {
+               if (probe)
+                       return TDB_SUCCESS;
+
+               return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
+                                 "tdb_oob off %llu len %llu wrap\n",
+                                 (long long)off, (long long)len);
+       }
+
+       if (len + off <= tdb->file->map_size)
                return TDB_SUCCESS;
        if (tdb->flags & TDB_INTERNAL) {
                if (probe)
                return TDB_SUCCESS;
        if (tdb->flags & TDB_INTERNAL) {
                if (probe)
@@ -101,7 +110,7 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
                tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                           "tdb_oob len %lld beyond internal"
                           " malloc size %lld",
                tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                           "tdb_oob len %lld beyond internal"
                           " malloc size %lld",
-                          (long long)len,
+                          (long long)(off + len),
                           (long long)tdb->file->map_size);
                return TDB_ERR_IO;
        }
                           (long long)tdb->file->map_size);
                return TDB_ERR_IO;
        }
@@ -120,13 +129,13 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
 
        tdb_unlock_expand(tdb, F_RDLCK);
 
 
        tdb_unlock_expand(tdb, F_RDLCK);
 
-       if (st.st_size < (size_t)len) {
+       if (st.st_size < off + len) {
                if (probe)
                        return TDB_SUCCESS;
 
                tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                if (probe)
                        return TDB_SUCCESS;
 
                tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
-                          "tdb_oob len %zu beyond eof at %zu",
-                          (size_t)len, st.st_size);
+                          "tdb_oob len %llu beyond eof at %zu",
+                          (long long)(off + len), st.st_size);
                return TDB_ERR_IO;
        }
 
                return TDB_ERR_IO;
        }
 
@@ -253,7 +262,7 @@ static enum TDB_ERROR tdb_write(struct tdb_context *tdb, tdb_off_t off,
                                  "Write to read-only database");
        }
 
                                  "Write to read-only database");
        }
 
-       ecode = tdb->tdb2.io->oob(tdb, off + len, false);
+       ecode = tdb->tdb2.io->oob(tdb, off, len, false);
        if (ecode != TDB_SUCCESS) {
                return ecode;
        }
        if (ecode != TDB_SUCCESS) {
                return ecode;
        }
@@ -283,7 +292,7 @@ static enum TDB_ERROR tdb_read(struct tdb_context *tdb, tdb_off_t off,
 {
        enum TDB_ERROR ecode;
 
 {
        enum TDB_ERROR ecode;
 
-       ecode = tdb->tdb2.io->oob(tdb, off + len, false);
+       ecode = tdb->tdb2.io->oob(tdb, off, len, false);
        if (ecode != TDB_SUCCESS) {
                return ecode;
        }
        if (ecode != TDB_SUCCESS) {
                return ecode;
        }
@@ -574,7 +583,7 @@ static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len,
        if (unlikely(!tdb->file->map_ptr))
                return NULL;
 
        if (unlikely(!tdb->file->map_ptr))
                return NULL;
 
-       ecode = tdb_oob(tdb, off + len, false);
+       ecode = tdb_oob(tdb, off, len, false);
        if (unlikely(ecode != TDB_SUCCESS))
                return TDB_ERR_PTR(ecode);
        return (char *)tdb->file->map_ptr + off;
        if (unlikely(ecode != TDB_SUCCESS))
                return TDB_ERR_PTR(ecode);
        return (char *)tdb->file->map_ptr + off;
index 02ec0eb68d7f4bf07702b26e2d16cc96e6345149..e238d99248b6ed5813418661a9bb86f3c1f966da 100644 (file)
@@ -747,7 +747,7 @@ finished:
        if (tdb->flags & TDB_VERSION1) {
                ecode = tdb1_probe_length(tdb);
        } else {
        if (tdb->flags & TDB_VERSION1) {
                ecode = tdb1_probe_length(tdb);
        } else {
-               ecode = tdb->tdb2.io->oob(tdb, tdb->file->map_size + 1, true);
+               ecode = tdb->tdb2.io->oob(tdb, tdb->file->map_size, 1, true);
        }
        if (unlikely(ecode != TDB_SUCCESS))
                goto fail;
        }
        if (unlikely(ecode != TDB_SUCCESS))
                goto fail;
index 2062ac297b1bcb9985f026bdd8075a54473b8cef..da1f0a2c77c0995da5f4bc7f70b381c4dbeb2d56 100644 (file)
@@ -347,7 +347,7 @@ struct tdb_methods {
                                tdb_len_t);
        enum TDB_ERROR (*twrite)(struct tdb_context *, tdb_off_t, const void *,
                                 tdb_len_t);
                                tdb_len_t);
        enum TDB_ERROR (*twrite)(struct tdb_context *, tdb_off_t, const void *,
                                 tdb_len_t);
-       enum TDB_ERROR (*oob)(struct tdb_context *, tdb_off_t, bool);
+       enum TDB_ERROR (*oob)(struct tdb_context *, tdb_off_t, tdb_len_t, bool);
        enum TDB_ERROR (*expand_file)(struct tdb_context *, tdb_len_t);
        void *(*direct)(struct tdb_context *, tdb_off_t, size_t, bool);
 };
        enum TDB_ERROR (*expand_file)(struct tdb_context *, tdb_len_t);
        void *(*direct)(struct tdb_context *, tdb_off_t, size_t, bool);
 };
index 1af1c4acafa90b44de277e147cb5d6cfc84fdd6c..70e664fc2d60e5fe36bda442607fbdfba04677ff 100644 (file)
@@ -345,16 +345,16 @@ static void transaction_write_existing(struct tdb_context *tdb, tdb_off_t off,
 /*
   out of bounds check during a transaction
 */
 /*
   out of bounds check during a transaction
 */
-static enum TDB_ERROR transaction_oob(struct tdb_context *tdb, tdb_off_t len,
-                                     bool probe)
+static enum TDB_ERROR transaction_oob(struct tdb_context *tdb,
+                                     tdb_off_t off, tdb_len_t len, bool probe)
 {
 {
-       if (len <= tdb->file->map_size || probe) {
+       if ((off + len >= off && off + len <= tdb->file->map_size) || probe) {
                return TDB_SUCCESS;
        }
 
        tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                   "tdb_oob len %lld beyond transaction size %lld",
                return TDB_SUCCESS;
        }
 
        tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                   "tdb_oob len %lld beyond transaction size %lld",
-                  (long long)len,
+                  (long long)(off + len),
                   (long long)tdb->file->map_size);
        return TDB_ERR_IO;
 }
                   (long long)tdb->file->map_size);
        return TDB_ERR_IO;
 }
@@ -601,7 +601,7 @@ enum TDB_ERROR tdb_transaction_start(struct tdb_context *tdb)
 
        /* make sure we know about any file expansions already done by
           anyone else */
 
        /* make sure we know about any file expansions already done by
           anyone else */
-       tdb->tdb2.io->oob(tdb, tdb->file->map_size + 1, true);
+       tdb->tdb2.io->oob(tdb, tdb->file->map_size, 1, true);
        tdb->tdb2.transaction->old_map_size = tdb->file->map_size;
 
        /* finally hook the io methods, replacing them with
        tdb->tdb2.transaction->old_map_size = tdb->file->map_size;
 
        /* finally hook the io methods, replacing them with