summaryrefslogtreecommitdiff
path: root/lib/list_debug.c
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2016-08-17 14:42:08 -0700
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2016-10-31 13:01:56 -0700
commitd7c816733d501b59dbdc2483f2cc8e4431fd9160 (patch)
tree2b612eb24d1a506dc4cf4a5a519fb53e382b8bc0 /lib/list_debug.c
parent1001354ca34179f3db924eb66672442a173147dc (diff)
downloadlwn-d7c816733d501b59dbdc2483f2cc8e4431fd9160.tar.gz
lwn-d7c816733d501b59dbdc2483f2cc8e4431fd9160.zip
list: Split list_add() debug checking into separate function
Right now, __list_add() code is repeated either in list.h or in list_debug.c, but the only differences between the two versions are the debug checks. This commit therefore extracts these debug checks into a separate __list_add_valid() function and consolidates __list_add(). Additionally this new __list_add_valid() function will stop list manipulations if a corruption is detected, instead of allowing for further corruption that may lead to even worse conditions. This is slight refactoring of the same hardening done in PaX and Grsecurity. Signed-off-by: Kees Cook <keescook@chromium.org> Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Acked-by: Rik van Riel <riel@redhat.com>
Diffstat (limited to 'lib/list_debug.c')
-rw-r--r--lib/list_debug.c48
1 files changed, 23 insertions, 25 deletions
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 3859bf63561c..149dd57b583b 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -2,8 +2,7 @@
* Copyright 2006, Red Hat, Inc., Dave Jones
* Released under the General Public License (GPL).
*
- * This file contains the linked list implementations for
- * DEBUG_LIST.
+ * This file contains the linked list validation for DEBUG_LIST.
*/
#include <linux/export.h>
@@ -13,33 +12,32 @@
#include <linux/rculist.h>
/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
+ * Check that the data structures for the list manipulations are reasonably
+ * valid. Failures here indicate memory corruption (and possibly an exploit
+ * attempt).
*/
-void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
+bool __list_add_valid(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
{
- WARN(next->prev != prev,
- "list_add corruption. next->prev should be "
- "prev (%p), but was %p. (next=%p).\n",
- prev, next->prev, next);
- WARN(prev->next != next,
- "list_add corruption. prev->next should be "
- "next (%p), but was %p. (prev=%p).\n",
- next, prev->next, prev);
- WARN(new == prev || new == next,
- "list_add double add: new=%p, prev=%p, next=%p.\n",
- new, prev, next);
- next->prev = new;
- new->next = next;
- new->prev = prev;
- WRITE_ONCE(prev->next, new);
+ if (unlikely(next->prev != prev)) {
+ WARN(1, "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n",
+ prev, next->prev, next);
+ return false;
+ }
+ if (unlikely(prev->next != next)) {
+ WARN(1, "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n",
+ next, prev->next, prev);
+ return false;
+ }
+ if (unlikely(new == prev || new == next)) {
+ WARN(1, "list_add double add: new=%p, prev=%p, next=%p.\n",
+ new, prev, next);
+ return false;
+ }
+ return true;
}
-EXPORT_SYMBOL(__list_add);
+EXPORT_SYMBOL(__list_add_valid);
void __list_del_entry(struct list_head *entry)
{