linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] Misc XArray, IDR & Radix Tree patches
@ 2019-11-03 11:40 Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 1/5] XArray: Fix xas_next() with a single entry at 0 Matthew Wilcox
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Wilcox (Oracle), Cong Wang

From: "Matthew Wilcox (Oracle)" <willy@infradead.org>

These patches all fix various bugs, some of which people have tripped
over and some of which have been caught by automatic tools.  Find them
in this git tree:

http://git.infradead.org/users/willy/linux-dax.git/shortlog/refs/heads/xarray

Matthew Wilcox (Oracle) (5):
  XArray: Fix xas_next() with a single entry at 0
  idr: Fix idr_get_next_ul race with idr_remove
  radix tree: Remove radix_tree_iter_find
  idr: Fix integer overflow in idr_for_each_entry
  idr: Fix idr_alloc_u32 on 32-bit systems

 include/linux/idr.h        |  2 +-
 include/linux/radix-tree.h | 18 ------------------
 lib/idr.c                  | 31 +++++++++++--------------------
 lib/radix-tree.c           |  2 +-
 lib/test_xarray.c          | 24 ++++++++++++++++++++++++
 lib/xarray.c               |  4 ++++
 6 files changed, 41 insertions(+), 40 deletions(-)

-- 
2.24.0.rc1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/5] XArray: Fix xas_next() with a single entry at 0
  2019-11-03 11:40 [PATCH 0/5] Misc XArray, IDR & Radix Tree patches Matthew Wilcox
@ 2019-11-03 11:40 ` Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 2/5] idr: Fix idr_get_next_ul race with idr_remove Matthew Wilcox
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Wilcox (Oracle), Cong Wang, Kent Overstreet

From: "Matthew Wilcox (Oracle)" <willy@infradead.org>

If there is only a single entry at 0, the first time we call xas_next(),
we return the entry.  Unfortunately, all subsequent times we call
xas_next(), we also return the entry at 0 instead of noticing that the
xa_index is now greater than zero.  This broke find_get_pages_contig().

Fixes: 64d3e9a9e0cc ("xarray: Step through an XArray")
Reported-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 lib/test_xarray.c | 24 ++++++++++++++++++++++++
 lib/xarray.c      |  4 ++++
 2 files changed, 28 insertions(+)

diff --git a/lib/test_xarray.c b/lib/test_xarray.c
index 9d631a7b6a70..7df4f7f395bf 100644
--- a/lib/test_xarray.c
+++ b/lib/test_xarray.c
@@ -1110,6 +1110,28 @@ static noinline void check_find_entry(struct xarray *xa)
 	XA_BUG_ON(xa, !xa_empty(xa));
 }
 
+static noinline void check_move_tiny(struct xarray *xa)
+{
+	XA_STATE(xas, xa, 0);
+
+	XA_BUG_ON(xa, !xa_empty(xa));
+	rcu_read_lock();
+	XA_BUG_ON(xa, xas_next(&xas) != NULL);
+	XA_BUG_ON(xa, xas_next(&xas) != NULL);
+	rcu_read_unlock();
+	xa_store_index(xa, 0, GFP_KERNEL);
+	rcu_read_lock();
+	xas_set(&xas, 0);
+	XA_BUG_ON(xa, xas_next(&xas) != xa_mk_index(0));
+	XA_BUG_ON(xa, xas_next(&xas) != NULL);
+	xas_set(&xas, 0);
+	XA_BUG_ON(xa, xas_prev(&xas) != xa_mk_index(0));
+	XA_BUG_ON(xa, xas_prev(&xas) != NULL);
+	rcu_read_unlock();
+	xa_erase_index(xa, 0);
+	XA_BUG_ON(xa, !xa_empty(xa));
+}
+
 static noinline void check_move_small(struct xarray *xa, unsigned long idx)
 {
 	XA_STATE(xas, xa, 0);
@@ -1217,6 +1239,8 @@ static noinline void check_move(struct xarray *xa)
 
 	xa_destroy(xa);
 
+	check_move_tiny(xa);
+
 	for (i = 0; i < 16; i++)
 		check_move_small(xa, 1UL << i);
 
diff --git a/lib/xarray.c b/lib/xarray.c
index 446b956c9188..1237c213f52b 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -994,6 +994,8 @@ void *__xas_prev(struct xa_state *xas)
 
 	if (!xas_frozen(xas->xa_node))
 		xas->xa_index--;
+	if (!xas->xa_node)
+		return set_bounds(xas);
 	if (xas_not_node(xas->xa_node))
 		return xas_load(xas);
 
@@ -1031,6 +1033,8 @@ void *__xas_next(struct xa_state *xas)
 
 	if (!xas_frozen(xas->xa_node))
 		xas->xa_index++;
+	if (!xas->xa_node)
+		return set_bounds(xas);
 	if (xas_not_node(xas->xa_node))
 		return xas_load(xas);
 
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/5] idr: Fix idr_get_next_ul race with idr_remove
  2019-11-03 11:40 [PATCH 0/5] Misc XArray, IDR & Radix Tree patches Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 1/5] XArray: Fix xas_next() with a single entry at 0 Matthew Wilcox
@ 2019-11-03 11:40 ` Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 3/5] radix tree: Remove radix_tree_iter_find Matthew Wilcox
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Wilcox (Oracle), Cong Wang

From: "Matthew Wilcox (Oracle)" <willy@infradead.org>

Commit 5c089fd0c734 ("idr: Fix idr_get_next race with idr_remove")
neglected to fix idr_get_next_ul().  As far as I can tell, nobody's
actually using this interface under the RCU read lock, but fix it now
before anybody decides to use it.

Fixes: 5c089fd0c734 ("idr: Fix idr_get_next race with idr_remove")
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 lib/idr.c | 31 +++++++++++--------------------
 1 file changed, 11 insertions(+), 20 deletions(-)

diff --git a/lib/idr.c b/lib/idr.c
index 66a374892482..c2cf2c52bbde 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -215,7 +215,7 @@ int idr_for_each(const struct idr *idr,
 EXPORT_SYMBOL(idr_for_each);
 
 /**
- * idr_get_next() - Find next populated entry.
+ * idr_get_next_ul() - Find next populated entry.
  * @idr: IDR handle.
  * @nextid: Pointer to an ID.
  *
@@ -224,7 +224,7 @@ EXPORT_SYMBOL(idr_for_each);
  * to the ID of the found value.  To use in a loop, the value pointed to by
  * nextid must be incremented by the user.
  */
-void *idr_get_next(struct idr *idr, int *nextid)
+void *idr_get_next_ul(struct idr *idr, unsigned long *nextid)
 {
 	struct radix_tree_iter iter;
 	void __rcu **slot;
@@ -245,18 +245,14 @@ void *idr_get_next(struct idr *idr, int *nextid)
 	}
 	if (!slot)
 		return NULL;
-	id = iter.index + base;
-
-	if (WARN_ON_ONCE(id > INT_MAX))
-		return NULL;
 
-	*nextid = id;
+	*nextid = iter.index + base;
 	return entry;
 }
-EXPORT_SYMBOL(idr_get_next);
+EXPORT_SYMBOL(idr_get_next_ul);
 
 /**
- * idr_get_next_ul() - Find next populated entry.
+ * idr_get_next() - Find next populated entry.
  * @idr: IDR handle.
  * @nextid: Pointer to an ID.
  *
@@ -265,22 +261,17 @@ EXPORT_SYMBOL(idr_get_next);
  * to the ID of the found value.  To use in a loop, the value pointed to by
  * nextid must be incremented by the user.
  */
-void *idr_get_next_ul(struct idr *idr, unsigned long *nextid)
+void *idr_get_next(struct idr *idr, int *nextid)
 {
-	struct radix_tree_iter iter;
-	void __rcu **slot;
-	unsigned long base = idr->idr_base;
 	unsigned long id = *nextid;
+	void *entry = idr_get_next_ul(idr, &id);
 
-	id = (id < base) ? 0 : id - base;
-	slot = radix_tree_iter_find(&idr->idr_rt, &iter, id);
-	if (!slot)
+	if (WARN_ON_ONCE(id > INT_MAX))
 		return NULL;
-
-	*nextid = iter.index + base;
-	return rcu_dereference_raw(*slot);
+	*nextid = id;
+	return entry;
 }
-EXPORT_SYMBOL(idr_get_next_ul);
+EXPORT_SYMBOL(idr_get_next);
 
 /**
  * idr_replace() - replace pointer for given ID.
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/5] radix tree: Remove radix_tree_iter_find
  2019-11-03 11:40 [PATCH 0/5] Misc XArray, IDR & Radix Tree patches Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 1/5] XArray: Fix xas_next() with a single entry at 0 Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 2/5] idr: Fix idr_get_next_ul race with idr_remove Matthew Wilcox
@ 2019-11-03 11:40 ` Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 4/5] idr: Fix integer overflow in idr_for_each_entry Matthew Wilcox
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Wilcox (Oracle), Cong Wang

From: "Matthew Wilcox (Oracle)" <willy@infradead.org>

This API is unsafe to use under the RCU lock.  With no in-tree users
remaining, remove it to prevent future bugs.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 include/linux/radix-tree.h | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index b5116013f27e..63e62372443a 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -315,24 +315,6 @@ radix_tree_iter_lookup(const struct radix_tree_root *root,
 	return radix_tree_next_chunk(root, iter, RADIX_TREE_ITER_CONTIG);
 }
 
-/**
- * radix_tree_iter_find - find a present entry
- * @root: radix tree root
- * @iter: iterator state
- * @index: start location
- *
- * This function returns the slot containing the entry with the lowest index
- * which is at least @index.  If @index is larger than any present entry, this
- * function returns NULL.  The @iter is updated to describe the entry found.
- */
-static inline void __rcu **
-radix_tree_iter_find(const struct radix_tree_root *root,
-			struct radix_tree_iter *iter, unsigned long index)
-{
-	radix_tree_iter_init(iter, index);
-	return radix_tree_next_chunk(root, iter, 0);
-}
-
 /**
  * radix_tree_iter_retry - retry this chunk of the iteration
  * @iter:	iterator state
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/5] idr: Fix integer overflow in idr_for_each_entry
  2019-11-03 11:40 [PATCH 0/5] Misc XArray, IDR & Radix Tree patches Matthew Wilcox
                   ` (2 preceding siblings ...)
  2019-11-03 11:40 ` [PATCH 3/5] radix tree: Remove radix_tree_iter_find Matthew Wilcox
@ 2019-11-03 11:40 ` Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 4/5] idr: Handle integer overflow correctly Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 5/5] idr: Fix idr_alloc_u32 on 32-bit systems Matthew Wilcox
  5 siblings, 0 replies; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Wilcox (Oracle), Cong Wang

From: "Matthew Wilcox (Oracle)" <willy@infradead.org>

If there is an entry at INT_MAX then idr_for_each_entry() will increment
id after handling it.  This is undefined behaviour, and is caught by
UBSAN.  Adding 1U to id forces the operation to be carried out as an
unsigned addition which (when assigned to id) will result in INT_MIN.
Since there is never an entry stored at INT_MIN, idr_get_next() will
return NULL, ending the loop as expected.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 include/linux/idr.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/idr.h b/include/linux/idr.h
index ee7abae143d3..dc09bd646bcb 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -185,7 +185,7 @@ static inline void idr_preload_end(void)
  * is convenient for a "not found" value.
  */
 #define idr_for_each_entry(idr, entry, id)			\
-	for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; ++id)
+	for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; id += 1U)
 
 /**
  * idr_for_each_entry_ul() - Iterate over an IDR's elements of a given type.
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/5] idr: Handle integer overflow correctly
  2019-11-03 11:40 [PATCH 0/5] Misc XArray, IDR & Radix Tree patches Matthew Wilcox
                   ` (3 preceding siblings ...)
  2019-11-03 11:40 ` [PATCH 4/5] idr: Fix integer overflow in idr_for_each_entry Matthew Wilcox
@ 2019-11-03 11:40 ` Matthew Wilcox
  2019-11-03 11:41   ` Matthew Wilcox
  2019-11-03 11:40 ` [PATCH 5/5] idr: Fix idr_alloc_u32 on 32-bit systems Matthew Wilcox
  5 siblings, 1 reply; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Wilcox, Cong Wang

If there is an entry at INT_MAX then idr_for_each_entry() will increment
id after handling it.  This is undefined behaviour, and is caught by
UBSAN.  Adding 1U to id forces the operation to be carried out as an
unsigned addition which (when assigned to id) will result in INT_MIN.
Since there is never an entry stored at INT_MIN, idr_get_next() will
return NULL, ending the loop as expected.

Signed-off-by: Matthew Wilcox <willy@infradead.org>
---
 include/linux/idr.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/idr.h b/include/linux/idr.h
index ee7abae143d3..dc09bd646bcb 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -185,7 +185,7 @@ static inline void idr_preload_end(void)
  * is convenient for a "not found" value.
  */
 #define idr_for_each_entry(idr, entry, id)			\
-	for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; ++id)
+	for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; id += 1U)
 
 /**
  * idr_for_each_entry_ul() - Iterate over an IDR's elements of a given type.
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/5] idr: Fix idr_alloc_u32 on 32-bit systems
  2019-11-03 11:40 [PATCH 0/5] Misc XArray, IDR & Radix Tree patches Matthew Wilcox
                   ` (4 preceding siblings ...)
  2019-11-03 11:40 ` [PATCH 4/5] idr: Handle integer overflow correctly Matthew Wilcox
@ 2019-11-03 11:40 ` Matthew Wilcox
  5 siblings, 0 replies; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Wilcox (Oracle), Cong Wang

From: "Matthew Wilcox (Oracle)" <willy@infradead.org>

Attempting to allocate an entry at 0xffffffff when one is already
present would succeed in allocating one at 2^32, which would confuse
everything.  Return -ENOSPC in this case, as expected.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 lib/radix-tree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 18c1dfbb1765..c8fa1d274530 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1529,7 +1529,7 @@ void __rcu **idr_get_free(struct radix_tree_root *root,
 			offset = radix_tree_find_next_bit(node, IDR_FREE,
 							offset + 1);
 			start = next_index(start, node, offset);
-			if (start > max)
+			if (start > max || start == 0)
 				return ERR_PTR(-ENOSPC);
 			while (offset == RADIX_TREE_MAP_SIZE) {
 				offset = node->offset + 1;
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/5] idr: Handle integer overflow correctly
  2019-11-03 11:40 ` [PATCH 4/5] idr: Handle integer overflow correctly Matthew Wilcox
@ 2019-11-03 11:41   ` Matthew Wilcox
  0 siblings, 0 replies; 8+ messages in thread
From: Matthew Wilcox @ 2019-11-03 11:41 UTC (permalink / raw)
  To: linux-kernel; +Cc: Cong Wang

On Sun, Nov 03, 2019 at 03:40:11AM -0800, Matthew Wilcox wrote:
> If there is an entry at INT_MAX then idr_for_each_entry() will increment
> id after handling it.  This is undefined behaviour, and is caught by
> UBSAN.  Adding 1U to id forces the operation to be carried out as an
> unsigned addition which (when assigned to id) will result in INT_MIN.
> Since there is never an entry stored at INT_MIN, idr_get_next() will
> return NULL, ending the loop as expected.

This was an earlier version which got left around in the git format-patch
directory.  Please ignore.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-11-03 11:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-03 11:40 [PATCH 0/5] Misc XArray, IDR & Radix Tree patches Matthew Wilcox
2019-11-03 11:40 ` [PATCH 1/5] XArray: Fix xas_next() with a single entry at 0 Matthew Wilcox
2019-11-03 11:40 ` [PATCH 2/5] idr: Fix idr_get_next_ul race with idr_remove Matthew Wilcox
2019-11-03 11:40 ` [PATCH 3/5] radix tree: Remove radix_tree_iter_find Matthew Wilcox
2019-11-03 11:40 ` [PATCH 4/5] idr: Fix integer overflow in idr_for_each_entry Matthew Wilcox
2019-11-03 11:40 ` [PATCH 4/5] idr: Handle integer overflow correctly Matthew Wilcox
2019-11-03 11:41   ` Matthew Wilcox
2019-11-03 11:40 ` [PATCH 5/5] idr: Fix idr_alloc_u32 on 32-bit systems Matthew Wilcox

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).