Re: mm: NULL ptr deref in migrate_page_move_mapping

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Hugh,

On 09/22/2014 07:04 PM, Hugh Dickins wrote:
>> but I'm not sure what went wrong.
> Most likely would be a zeroing of the radix_tree node, just as you
> were experiencing zeroing of other mm structures in earlier weeks.
> 
> Not that I've got any suggestions on where to take it from there.

I've actually mailed this one because I thought that the root reason
isn't the same as the corruption before.

Previously, the radix tree itself would get corrupted, so we'd deref
a NULL ptr inside the radix tree functions. In this case, it seems
that if it was indeed a corruption, it affected the objects that are
held in the tree rather than the tree itself.

If you suspect it's a corruption specific to the tree, how about:

diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 33170db..9dc19d9 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -27,6 +27,8 @@
 #include <linux/kernel.h>
 #include <linux/rcupdate.h>

+#define RADIX_POISON 0x8BADBEEF
+
 /*
  * An indirect pointer (root->rnode pointing to a radix_tree_node, rather
  * than a data item) is signalled by the low bit set in the root->rnode
@@ -85,6 +87,7 @@ static inline int radix_tree_is_indirect_ptr(void *ptr)
 #define RADIX_TREE_COUNT_MASK	((1UL << RADIX_TREE_COUNT_SHIFT) - 1)

 struct radix_tree_node {
+	unsigned int	poison_start;
 	unsigned int	path;	/* Offset in parent & height from the bottom */
 	unsigned int	count;
 	union {
@@ -101,19 +104,24 @@ struct radix_tree_node {
 	struct list_head private_list;
 	void __rcu	*slots[RADIX_TREE_MAP_SIZE];
 	unsigned long	tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
+	unsigned int	poison_end;
 };

 /* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */
 struct radix_tree_root {
+	unsigned int		poison_start;
 	unsigned int		height;
 	gfp_t			gfp_mask;
 	struct radix_tree_node	__rcu *rnode;
+	unsigned int		poison_end;
 };

 #define RADIX_TREE_INIT(mask)	{					\
 	.height = 0,							\
 	.gfp_mask = (mask),						\
 	.rnode = NULL,							\
+	.poison_start = RADIX_POISON,					\
+	.poison_end = RADIX_POISON,					\
 }

 #define RADIX_TREE(name, mask) \
@@ -124,6 +132,8 @@ do {									\
 	(root)->height = 0;						\
 	(root)->gfp_mask = (mask);					\
 	(root)->rnode = NULL;						\
+	(root)->poison_start = RADIX_POISON;				\
+	(root)->poison_end = RADIX_POISON;				\
 } while (0)

 /**
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 3291a8e..5ef8f52 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -230,7 +230,7 @@ static void radix_tree_node_rcu_free(struct rcu_head *head)

 	node->slots[0] = NULL;
 	node->count = 0;
-
+	BUG_ON(node->poison_start != RADIX_POISON || node->poison_end != RADIX_POISON);
 	kmem_cache_free(radix_tree_node_cachep, node);
 }

@@ -460,6 +460,7 @@ int radix_tree_insert(struct radix_tree_root *root,
 		node->count++;
 		BUG_ON(tag_get(node, 0, index & RADIX_TREE_MAP_MASK));
 		BUG_ON(tag_get(node, 1, index & RADIX_TREE_MAP_MASK));
+		BUG_ON(node->poison_start != RADIX_POISON || node->poison_end != RADIX_POISON);
 	} else {
 		BUG_ON(root_tag_get(root, 0));
 		BUG_ON(root_tag_get(root, 1));
@@ -489,11 +490,11 @@ void *__radix_tree_lookup(struct radix_tree_root *root, unsigned long index,
 	struct radix_tree_node *node, *parent;
 	unsigned int height, shift;
 	void **slot;
-
+	BUG_ON(root->poison_start != RADIX_POISON || root->poison_end != RADIX_POISON);
 	node = rcu_dereference_raw(root->rnode);
 	if (node == NULL)
 		return NULL;
-
+	BUG_ON(node->poison_start != RADIX_POISON || node->poison_end != RADIX_POISON);
 	if (!radix_tree_is_indirect_ptr(node)) {
 		if (index > 0)
 			return NULL;
@@ -518,7 +519,7 @@ void *__radix_tree_lookup(struct radix_tree_root *root, unsigned long index,
 		node = rcu_dereference_raw(*slot);
 		if (node == NULL)
 			return NULL;
-
+		BUG_ON(node->poison_start != RADIX_POISON || node->poison_end != RADIX_POISON);
 		shift -= RADIX_TREE_MAP_SHIFT;
 		height--;
 	} while (height > 0);

I'll run with it for the night.


Thanks,
Sasha

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]