diff options
author | Kees Cook <keescook@chromium.org> | 2016-08-17 17:42:10 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2016-10-31 16:01:57 -0400 |
commit | 0cd340dcb05c4a43742fe156f36737bb2a321bfd (patch) | |
tree | 1e45dac53b3a090f28e2e11a5328f0f5a8b4d6a0 /lib | |
parent | 54acd4397d7e7a725c94101180cd9f38ef701acc (diff) |
list: Split list_del() debug checking into separate function
Similar to the list_add() debug consolidation, this commit consolidates
the debug checking performed during CONFIG_DEBUG_LIST into a new
__list_del_entry_valid() function, and stops list updates when corruption
is found.
Refactored from same hardening 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')
-rw-r--r-- | lib/list_debug.c | 53 |
1 files changed, 23 insertions, 30 deletions
diff --git a/lib/list_debug.c b/lib/list_debug.c index d0b89b9d0736..276565fca2a6 100644 --- a/lib/list_debug.c +++ b/lib/list_debug.c | |||
@@ -39,41 +39,34 @@ bool __list_add_valid(struct list_head *new, struct list_head *prev, | |||
39 | } | 39 | } |
40 | EXPORT_SYMBOL(__list_add_valid); | 40 | EXPORT_SYMBOL(__list_add_valid); |
41 | 41 | ||
42 | void __list_del_entry(struct list_head *entry) | 42 | bool __list_del_entry_valid(struct list_head *entry) |
43 | { | 43 | { |
44 | struct list_head *prev, *next; | 44 | struct list_head *prev, *next; |
45 | 45 | ||
46 | prev = entry->prev; | 46 | prev = entry->prev; |
47 | next = entry->next; | 47 | next = entry->next; |
48 | 48 | ||
49 | if (WARN(next == LIST_POISON1, | 49 | if (unlikely(next == LIST_POISON1)) { |
50 | "list_del corruption, %p->next is LIST_POISON1 (%p)\n", | 50 | WARN(1, "list_del corruption, %p->next is LIST_POISON1 (%p)\n", |
51 | entry, LIST_POISON1) || | 51 | entry, LIST_POISON1); |
52 | WARN(prev == LIST_POISON2, | 52 | return false; |
53 | "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", | 53 | } |
54 | entry, LIST_POISON2) || | 54 | if (unlikely(prev == LIST_POISON2)) { |
55 | WARN(prev->next != entry, | 55 | WARN(1, "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", |
56 | "list_del corruption. prev->next should be %p, " | 56 | entry, LIST_POISON2); |
57 | "but was %p\n", entry, prev->next) || | 57 | return false; |
58 | WARN(next->prev != entry, | 58 | } |
59 | "list_del corruption. next->prev should be %p, " | 59 | if (unlikely(prev->next != entry)) { |
60 | "but was %p\n", entry, next->prev)) | 60 | WARN(1, "list_del corruption. prev->next should be %p, but was %p\n", |
61 | return; | 61 | entry, prev->next); |
62 | 62 | return false; | |
63 | __list_del(prev, next); | 63 | } |
64 | } | 64 | if (unlikely(next->prev != entry)) { |
65 | EXPORT_SYMBOL(__list_del_entry); | 65 | WARN(1, "list_del corruption. next->prev should be %p, but was %p\n", |
66 | entry, next->prev); | ||
67 | return false; | ||
68 | } | ||
69 | return true; | ||
66 | 70 | ||
67 | /** | ||
68 | * list_del - deletes entry from list. | ||
69 | * @entry: the element to delete from the list. | ||
70 | * Note: list_empty on entry does not return true after this, the entry is | ||
71 | * in an undefined state. | ||
72 | */ | ||
73 | void list_del(struct list_head *entry) | ||
74 | { | ||
75 | __list_del_entry(entry); | ||
76 | entry->next = LIST_POISON1; | ||
77 | entry->prev = LIST_POISON2; | ||
78 | } | 71 | } |
79 | EXPORT_SYMBOL(list_del); | 72 | EXPORT_SYMBOL(__list_del_entry_valid); |