diff options
author | Kees Cook <keescook@chromium.org> | 2016-08-17 17:42:12 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2016-10-31 16:01:58 -0400 |
commit | 6819d101dd739dd4e8cbe60a98c9ebb224ecc992 (patch) | |
tree | 04823cf711bbe51cad6a4227b3ca14459fbb1336 /drivers/misc | |
parent | de54ebbe26bb371a6f1fbc0593372232f04e3107 (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.h | 2 | ||||
-rw-r--r-- | drivers/misc/lkdtm_bugs.c | 68 | ||||
-rw-r--r-- | drivers/misc/lkdtm_core.c | 2 |
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); | |||
21 | void lkdtm_HUNG_TASK(void); | 21 | void lkdtm_HUNG_TASK(void); |
22 | void lkdtm_ATOMIC_UNDERFLOW(void); | 22 | void lkdtm_ATOMIC_UNDERFLOW(void); |
23 | void lkdtm_ATOMIC_OVERFLOW(void); | 23 | void lkdtm_ATOMIC_OVERFLOW(void); |
24 | void lkdtm_CORRUPT_LIST_ADD(void); | ||
25 | void lkdtm_CORRUPT_LIST_DEL(void); | ||
24 | 26 | ||
25 | /* lkdtm_heap.c */ | 27 | /* lkdtm_heap.c */ |
26 | void lkdtm_OVERWRITE_ALLOCATION(void); | 28 | void 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 | ||
11 | struct 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 | |||
155 | void 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 = ⌖ | ||
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 | |||
193 | void lkdtm_CORRUPT_LIST_DEL(void) | ||
194 | { | ||
195 | LIST_HEAD(test_head); | ||
196 | struct lkdtm_list item; | ||
197 | void *target[2] = { }; | ||
198 | void *redirection = ⌖ | ||
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), |