From: Bryam Vargas <[email protected]>

node_check() weighs a node header against itself and nothing else, which
leaves three shapes the writers never produce and the reader accepts: a
zero value_size, which collapses value_ptr()'s stride so max_entries
alone places the value area, off the end of the block; an internal node
whose value_size is not the __le64 stride value64() indexes it with; and
a max_entries that disagrees with calc_max_entries(), the formula every
writer computes it from.

Reject all three. Conforming metadata satisfies them by construction:
dm_btree_empty() and btree_split_beneath() take max_entries from
calc_max_entries() and write sizeof(__le64) for an internal node, and
the split paths copy flags, max_entries and value_size together.
calc_max_entries() gains a declaration in dm-btree-internal.h so the
validator shares the formula rather than open-coding it.

Fixes: 3241b1d3e0aa ("dm: add persistent data library")
Cc: [email protected]
Signed-off-by: Bryam Vargas <[email protected]>
---
 drivers/md/persistent-data/dm-btree-internal.h |  2 ++
 drivers/md/persistent-data/dm-btree-spine.c    | 20 +++++++++++++++++++-
 drivers/md/persistent-data/dm-btree.c          |  2 +-
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/md/persistent-data/dm-btree-internal.h 
b/drivers/md/persistent-data/dm-btree-internal.h
index acebd32858a7..404739149d02 100644
--- a/drivers/md/persistent-data/dm-btree-internal.h
+++ b/drivers/md/persistent-data/dm-btree-internal.h
@@ -43,6 +43,8 @@ struct btree_node {
 } __packed __aligned(8);
 
 
+uint32_t calc_max_entries(size_t value_size, size_t block_size);
+
 /*
  * Locks a block using the btree node validator.
  */
diff --git a/drivers/md/persistent-data/dm-btree-spine.c 
b/drivers/md/persistent-data/dm-btree-spine.c
index c46fc50c274e..076f836912c8 100644
--- a/drivers/md/persistent-data/dm-btree-spine.c
+++ b/drivers/md/persistent-data/dm-btree-spine.c
@@ -57,6 +57,25 @@ static int node_check(const struct dm_block_validator *v,
        nr_entries = le32_to_cpu(h->nr_entries);
        max_entries = le32_to_cpu(h->max_entries);
        value_size = le32_to_cpu(h->value_size);
+       flags = le32_to_cpu(h->flags);
+
+       if (!value_size) {
+               DMERR_LIMIT("%s failed: value_size is zero", __func__);
+               return -EILSEQ;
+       }
+
+       if ((flags & INTERNAL_NODE) && value_size != sizeof(__le64)) {
+               DMERR_LIMIT("%s failed: internal node value_size %zu != %zu",
+                           __func__, value_size, sizeof(__le64));
+               return -EILSEQ;
+       }
+
+       if (max_entries != calc_max_entries(value_size, block_size)) {
+               DMERR_LIMIT("%s failed: max_entries %u != wanted %u for 
value_size %zu",
+                           __func__, max_entries,
+                           calc_max_entries(value_size, block_size), 
value_size);
+               return -EILSEQ;
+       }
 
        if (sizeof(struct node_header) +
            (sizeof(__le64) + value_size) * max_entries > block_size) {
@@ -72,7 +91,6 @@ static int node_check(const struct dm_block_validator *v,
        /*
         * The node must be either INTERNAL or LEAF.
         */
-       flags = le32_to_cpu(h->flags);
        if (!(flags & INTERNAL_NODE) && !(flags & LEAF_NODE)) {
                DMERR_LIMIT("%s failed: node is neither INTERNAL or LEAF", 
__func__);
                return -EILSEQ;
diff --git a/drivers/md/persistent-data/dm-btree.c 
b/drivers/md/persistent-data/dm-btree.c
index dd02eee4a23c..5ed3b3e9abb9 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -114,7 +114,7 @@ static int insert_at(size_t value_size, struct btree_node 
*node, unsigned int in
  * We want 3n entries (for some n).  This works more nicely for repeated
  * insert remove loops than (2n + 1).
  */
-static uint32_t calc_max_entries(size_t value_size, size_t block_size)
+uint32_t calc_max_entries(size_t value_size, size_t block_size)
 {
        uint32_t total, n;
        size_t elt_size = sizeof(uint64_t) + value_size; /* key + value */

-- 
2.55.0



Reply via email to