summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2017-02-24 18:00:38 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-24 20:46:56 -0500
commit85caa95b9f19bb3a26d7e025d1134760b69e0c40 (patch)
tree9db3bbeccc4329287960f42189ba4b1d4ee7a561
parent849de0cd2c873c878fc2605156f10a8ade9bde28 (diff)
bug: switch data corruption check to __must_check
The CHECK_DATA_CORRUPTION() macro was designed to have callers do something meaningful/protective on failure. However, using "return false" in the macro too strictly limits the design patterns of callers. Instead, let callers handle the logic test directly, but make sure that the result IS checked by forcing __must_check (which appears to not be able to be used directly on macro expressions). Link: http://lkml.kernel.org/r/20170206204547.GA125312@beast Signed-off-by: Kees Cook <keescook@chromium.org> Suggested-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/bug.h12
-rw-r--r--lib/list_debug.c45
2 files changed, 31 insertions, 26 deletions
diff --git a/include/linux/bug.h b/include/linux/bug.h
index baff2e8fc8a8..5828489309bb 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -124,18 +124,20 @@ static inline enum bug_trap_type report_bug(unsigned long bug_addr,
124 124
125/* 125/*
126 * Since detected data corruption should stop operation on the affected 126 * Since detected data corruption should stop operation on the affected
127 * structures, this returns false if the corruption condition is found. 127 * structures. Return value must be checked and sanely acted on by caller.
128 */ 128 */
129static inline __must_check bool check_data_corruption(bool v) { return v; }
129#define CHECK_DATA_CORRUPTION(condition, fmt, ...) \ 130#define CHECK_DATA_CORRUPTION(condition, fmt, ...) \
130 do { \ 131 check_data_corruption(({ \
131 if (unlikely(condition)) { \ 132 bool corruption = unlikely(condition); \
133 if (corruption) { \
132 if (IS_ENABLED(CONFIG_BUG_ON_DATA_CORRUPTION)) { \ 134 if (IS_ENABLED(CONFIG_BUG_ON_DATA_CORRUPTION)) { \
133 pr_err(fmt, ##__VA_ARGS__); \ 135 pr_err(fmt, ##__VA_ARGS__); \
134 BUG(); \ 136 BUG(); \
135 } else \ 137 } else \
136 WARN(1, fmt, ##__VA_ARGS__); \ 138 WARN(1, fmt, ##__VA_ARGS__); \
137 return false; \
138 } \ 139 } \
139 } while (0) 140 corruption; \
141 }))
140 142
141#endif /* _LINUX_BUG_H */ 143#endif /* _LINUX_BUG_H */
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 7f7bfa55eb6d..a34db8d27667 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -20,15 +20,16 @@
20bool __list_add_valid(struct list_head *new, struct list_head *prev, 20bool __list_add_valid(struct list_head *new, struct list_head *prev,
21 struct list_head *next) 21 struct list_head *next)
22{ 22{
23 CHECK_DATA_CORRUPTION(next->prev != prev, 23 if (CHECK_DATA_CORRUPTION(next->prev != prev,
24 "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", 24 "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n",
25 prev, next->prev, next); 25 prev, next->prev, next) ||
26 CHECK_DATA_CORRUPTION(prev->next != next, 26 CHECK_DATA_CORRUPTION(prev->next != next,
27 "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", 27 "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n",
28 next, prev->next, prev); 28 next, prev->next, prev) ||
29 CHECK_DATA_CORRUPTION(new == prev || new == next, 29 CHECK_DATA_CORRUPTION(new == prev || new == next,
30 "list_add double add: new=%p, prev=%p, next=%p.\n", 30 "list_add double add: new=%p, prev=%p, next=%p.\n",
31 new, prev, next); 31 new, prev, next))
32 return false;
32 33
33 return true; 34 return true;
34} 35}
@@ -41,18 +42,20 @@ bool __list_del_entry_valid(struct list_head *entry)
41 prev = entry->prev; 42 prev = entry->prev;
42 next = entry->next; 43 next = entry->next;
43 44
44 CHECK_DATA_CORRUPTION(next == LIST_POISON1, 45 if (CHECK_DATA_CORRUPTION(next == LIST_POISON1,
45 "list_del corruption, %p->next is LIST_POISON1 (%p)\n", 46 "list_del corruption, %p->next is LIST_POISON1 (%p)\n",
46 entry, LIST_POISON1); 47 entry, LIST_POISON1) ||
47 CHECK_DATA_CORRUPTION(prev == LIST_POISON2, 48 CHECK_DATA_CORRUPTION(prev == LIST_POISON2,
48 "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", 49 "list_del corruption, %p->prev is LIST_POISON2 (%p)\n",
49 entry, LIST_POISON2); 50 entry, LIST_POISON2) ||
50 CHECK_DATA_CORRUPTION(prev->next != entry, 51 CHECK_DATA_CORRUPTION(prev->next != entry,
51 "list_del corruption. prev->next should be %p, but was %p\n", 52 "list_del corruption. prev->next should be %p, but was %p\n",
52 entry, prev->next); 53 entry, prev->next) ||
53 CHECK_DATA_CORRUPTION(next->prev != entry, 54 CHECK_DATA_CORRUPTION(next->prev != entry,
54 "list_del corruption. next->prev should be %p, but was %p\n", 55 "list_del corruption. next->prev should be %p, but was %p\n",
55 entry, next->prev); 56 entry, next->prev))
57 return false;
58
56 return true; 59 return true;
57 60
58} 61}