nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

Blame SOURCES/0410-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch

b1bcb2
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
b1bcb2
From: Daniel Axtens <dja@axtens.net>
b1bcb2
Date: Mon, 18 Jan 2021 16:49:44 +1100
b1bcb2
Subject: [PATCH] fs/nilfs2: Don't search children if provided number is too
b1bcb2
 large
b1bcb2
b1bcb2
NILFS2 reads the number of children a node has from the node. Unfortunately,
b1bcb2
that's not trustworthy. Check if it's beyond what the filesystem permits and
b1bcb2
reject it if so.
b1bcb2
b1bcb2
This blocks some OOB reads. I'm not sure how controllable the read is and what
b1bcb2
could be done with invalidly read data later on.
b1bcb2
b1bcb2
Signed-off-by: Daniel Axtens <dja@axtens.net>
b1bcb2
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
b1bcb2
---
b1bcb2
 grub-core/fs/nilfs2.c | 38 +++++++++++++++++++++++---------------
b1bcb2
 1 file changed, 23 insertions(+), 15 deletions(-)
b1bcb2
b1bcb2
diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c
b1bcb2
index 09e89f615bc..896d2c22c81 100644
b1bcb2
--- a/grub-core/fs/nilfs2.c
b1bcb2
+++ b/grub-core/fs/nilfs2.c
b1bcb2
@@ -416,14 +416,34 @@ grub_nilfs2_btree_node_get_key (struct grub_nilfs2_btree_node *node,
b1bcb2
 }
b1bcb2
 
b1bcb2
 static inline int
b1bcb2
-grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node,
b1bcb2
+grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data,
b1bcb2
+				      struct grub_nilfs2_btree_node *node)
b1bcb2
+{
b1bcb2
+  int node_children_max = ((NILFS2_BLOCK_SIZE (data) -
b1bcb2
+			    sizeof (struct grub_nilfs2_btree_node) -
b1bcb2
+			    NILFS_BTREE_NODE_EXTRA_PAD_SIZE) /
b1bcb2
+			   (sizeof (grub_uint64_t) + sizeof (grub_uint64_t)));
b1bcb2
+
b1bcb2
+  return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
b1bcb2
+}
b1bcb2
+
b1bcb2
+static inline int
b1bcb2
+grub_nilfs2_btree_node_lookup (struct grub_nilfs2_data *data,
b1bcb2
+			       struct grub_nilfs2_btree_node *node,
b1bcb2
 			       grub_uint64_t key, int *indexp)
b1bcb2
 {
b1bcb2
   grub_uint64_t nkey;
b1bcb2
   int index, low, high, s;
b1bcb2
 
b1bcb2
   low = 0;
b1bcb2
+
b1bcb2
   high = grub_le_to_cpu16 (node->bn_nchildren) - 1;
b1bcb2
+  if (high >= grub_nilfs2_btree_node_nchildren_max (data, node))
b1bcb2
+    {
b1bcb2
+      grub_error (GRUB_ERR_BAD_FS, "too many children");
b1bcb2
+      return 0;
b1bcb2
+    }
b1bcb2
+
b1bcb2
   index = 0;
b1bcb2
   s = 0;
b1bcb2
   while (low <= high)
b1bcb2
@@ -459,18 +479,6 @@ grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node,
b1bcb2
   return s == 0;
b1bcb2
 }
b1bcb2
 
b1bcb2
-static inline int
b1bcb2
-grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data,
b1bcb2
-				      struct grub_nilfs2_btree_node *node)
b1bcb2
-{
b1bcb2
-  int node_children_max = ((NILFS2_BLOCK_SIZE (data) -
b1bcb2
-			    sizeof (struct grub_nilfs2_btree_node) -
b1bcb2
-			    NILFS_BTREE_NODE_EXTRA_PAD_SIZE) /
b1bcb2
-			   (sizeof (grub_uint64_t) + sizeof (grub_uint64_t)));
b1bcb2
-
b1bcb2
-  return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
b1bcb2
-}
b1bcb2
-
b1bcb2
 static inline grub_uint64_t *
b1bcb2
 grub_nilfs2_btree_node_dptrs (struct grub_nilfs2_data *data,
b1bcb2
 			      struct grub_nilfs2_btree_node *node)
b1bcb2
@@ -517,7 +525,7 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data,
b1bcb2
   node = grub_nilfs2_btree_get_root (inode);
b1bcb2
   level = grub_nilfs2_btree_get_level (node);
b1bcb2
 
b1bcb2
-  found = grub_nilfs2_btree_node_lookup (node, key, &index);
b1bcb2
+  found = grub_nilfs2_btree_node_lookup (data, node, key, &index);
b1bcb2
   ptr = grub_nilfs2_btree_node_get_ptr (data, node, index);
b1bcb2
   if (need_translate)
b1bcb2
     ptr = grub_nilfs2_dat_translate (data, ptr);
b1bcb2
@@ -538,7 +546,7 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data,
b1bcb2
 	}
b1bcb2
 
b1bcb2
       if (!found)
b1bcb2
-	found = grub_nilfs2_btree_node_lookup (node, key, &index);
b1bcb2
+	found = grub_nilfs2_btree_node_lookup (data, node, key, &index);
b1bcb2
       else
b1bcb2
 	index = 0;
b1bcb2