aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2016-08-17 17:42:12 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2016-10-31 16:01:58 -0400
commit6819d101dd739dd4e8cbe60a98c9ebb224ecc992 (patch)
tree04823cf711bbe51cad6a4227b3ca14459fbb1336 /drivers/misc
parentde54ebbe26bb371a6f1fbc0593372232f04e3107 (diff)
lkdtm: Add tests for struct list corruption
When building under CONFIG_DEBUG_LIST, list addition and removal will be sanity-checked. This validates that the check is working as expected by setting up classic corruption attacks against list manipulations, available with the new lkdtm tests CORRUPT_LIST_ADD and CORRUPT_LIST_DEL. 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 'drivers/misc')
-rw-r--r--drivers/misc/lkdtm.h2
-rw-r--r--drivers/misc/lkdtm_bugs.c68
-rw-r--r--drivers/misc/lkdtm_core.c2
3 files changed, 72 insertions, 0 deletions
diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h
index fdf954c2107f..cfa1039c62e7 100644
--- a/drivers/misc/lkdtm.h
+++ b/drivers/misc/lkdtm.h
@@ -21,6 +21,8 @@ void lkdtm_SPINLOCKUP(void);
21void lkdtm_HUNG_TASK(void); 21void lkdtm_HUNG_TASK(void);
22void lkdtm_ATOMIC_UNDERFLOW(void); 22void lkdtm_ATOMIC_UNDERFLOW(void);
23void lkdtm_ATOMIC_OVERFLOW(void); 23void lkdtm_ATOMIC_OVERFLOW(void);
24void lkdtm_CORRUPT_LIST_ADD(void);
25void lkdtm_CORRUPT_LIST_DEL(void);
24 26
25/* lkdtm_heap.c */ 27/* lkdtm_heap.c */
26void lkdtm_OVERWRITE_ALLOCATION(void); 28void lkdtm_OVERWRITE_ALLOCATION(void);
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c
index 182ae1894b32..f336206d4b1f 100644
--- a/drivers/misc/lkdtm_bugs.c
+++ b/drivers/misc/lkdtm_bugs.c
@@ -5,8 +5,13 @@
5 * test source files. 5 * test source files.
6 */ 6 */
7#include "lkdtm.h" 7#include "lkdtm.h"
8#include <linux/list.h>
8#include <linux/sched.h> 9#include <linux/sched.h>
9 10
11struct lkdtm_list {
12 struct list_head node;
13};
14
10/* 15/*
11 * Make sure our attempts to over run the kernel stack doesn't trigger 16 * Make sure our attempts to over run the kernel stack doesn't trigger
12 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we 17 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
@@ -146,3 +151,66 @@ void lkdtm_ATOMIC_OVERFLOW(void)
146 pr_info("attempting bad atomic overflow\n"); 151 pr_info("attempting bad atomic overflow\n");
147 atomic_inc(&over); 152 atomic_inc(&over);
148} 153}
154
155void lkdtm_CORRUPT_LIST_ADD(void)
156{
157 /*
158 * Initially, an empty list via LIST_HEAD:
159 * test_head.next = &test_head
160 * test_head.prev = &test_head
161 */
162 LIST_HEAD(test_head);
163 struct lkdtm_list good, bad;
164 void *target[2] = { };
165 void *redirection = &target;
166
167 pr_info("attempting good list addition\n");
168
169 /*
170 * Adding to the list performs these actions:
171 * test_head.next->prev = &good.node
172 * good.node.next = test_head.next
173 * good.node.prev = test_head
174 * test_head.next = good.node
175 */
176 list_add(&good.node, &test_head);
177
178 pr_info("attempting corrupted list addition\n");
179 /*
180 * In simulating this "write what where" primitive, the "what" is
181 * the address of &bad.node, and the "where" is the address held
182 * by "redirection".
183 */
184 test_head.next = redirection;
185 list_add(&bad.node, &test_head);
186
187 if (target[0] == NULL && target[1] == NULL)
188 pr_err("Overwrite did not happen, but no BUG?!\n");
189 else
190 pr_err("list_add() corruption not detected!\n");
191}
192
193void lkdtm_CORRUPT_LIST_DEL(void)
194{
195 LIST_HEAD(test_head);
196 struct lkdtm_list item;
197 void *target[2] = { };
198 void *redirection = &target;
199
200 list_add(&item.node, &test_head);
201
202 pr_info("attempting good list removal\n");
203 list_del(&item.node);
204
205 pr_info("attempting corrupted list removal\n");
206 list_add(&item.node, &test_head);
207
208 /* As with the list_add() test above, this corrupts "next". */
209 item.node.next = redirection;
210 list_del(&item.node);
211
212 if (target[0] == NULL && target[1] == NULL)
213 pr_err("Overwrite did not happen, but no BUG?!\n");
214 else
215 pr_err("list_del() corruption not detected!\n");
216}
diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c
index f9154b8d67f6..7eeb71a75549 100644
--- a/drivers/misc/lkdtm_core.c
+++ b/drivers/misc/lkdtm_core.c
@@ -197,6 +197,8 @@ struct crashtype crashtypes[] = {
197 CRASHTYPE(EXCEPTION), 197 CRASHTYPE(EXCEPTION),
198 CRASHTYPE(LOOP), 198 CRASHTYPE(LOOP),
199 CRASHTYPE(OVERFLOW), 199 CRASHTYPE(OVERFLOW),
200 CRASHTYPE(CORRUPT_LIST_ADD),
201 CRASHTYPE(CORRUPT_LIST_DEL),
200 CRASHTYPE(CORRUPT_STACK), 202 CRASHTYPE(CORRUPT_STACK),
201 CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), 203 CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
202 CRASHTYPE(OVERWRITE_ALLOCATION), 204 CRASHTYPE(OVERWRITE_ALLOCATION),