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>
This commit is contained in:
parent
de54ebbe26
commit
6819d101dd
@ -21,6 +21,8 @@ void lkdtm_SPINLOCKUP(void);
|
|||||||
void lkdtm_HUNG_TASK(void);
|
void lkdtm_HUNG_TASK(void);
|
||||||
void lkdtm_ATOMIC_UNDERFLOW(void);
|
void lkdtm_ATOMIC_UNDERFLOW(void);
|
||||||
void lkdtm_ATOMIC_OVERFLOW(void);
|
void lkdtm_ATOMIC_OVERFLOW(void);
|
||||||
|
void lkdtm_CORRUPT_LIST_ADD(void);
|
||||||
|
void lkdtm_CORRUPT_LIST_DEL(void);
|
||||||
|
|
||||||
/* lkdtm_heap.c */
|
/* lkdtm_heap.c */
|
||||||
void lkdtm_OVERWRITE_ALLOCATION(void);
|
void lkdtm_OVERWRITE_ALLOCATION(void);
|
||||||
|
@ -5,8 +5,13 @@
|
|||||||
* test source files.
|
* test source files.
|
||||||
*/
|
*/
|
||||||
#include "lkdtm.h"
|
#include "lkdtm.h"
|
||||||
|
#include <linux/list.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
|
struct lkdtm_list {
|
||||||
|
struct list_head node;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure our attempts to over run the kernel stack doesn't trigger
|
* Make sure our attempts to over run the kernel stack doesn't trigger
|
||||||
* a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
|
* a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
|
||||||
@ -146,3 +151,66 @@ void lkdtm_ATOMIC_OVERFLOW(void)
|
|||||||
pr_info("attempting bad atomic overflow\n");
|
pr_info("attempting bad atomic overflow\n");
|
||||||
atomic_inc(&over);
|
atomic_inc(&over);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lkdtm_CORRUPT_LIST_ADD(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Initially, an empty list via LIST_HEAD:
|
||||||
|
* test_head.next = &test_head
|
||||||
|
* test_head.prev = &test_head
|
||||||
|
*/
|
||||||
|
LIST_HEAD(test_head);
|
||||||
|
struct lkdtm_list good, bad;
|
||||||
|
void *target[2] = { };
|
||||||
|
void *redirection = ⌖
|
||||||
|
|
||||||
|
pr_info("attempting good list addition\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adding to the list performs these actions:
|
||||||
|
* test_head.next->prev = &good.node
|
||||||
|
* good.node.next = test_head.next
|
||||||
|
* good.node.prev = test_head
|
||||||
|
* test_head.next = good.node
|
||||||
|
*/
|
||||||
|
list_add(&good.node, &test_head);
|
||||||
|
|
||||||
|
pr_info("attempting corrupted list addition\n");
|
||||||
|
/*
|
||||||
|
* In simulating this "write what where" primitive, the "what" is
|
||||||
|
* the address of &bad.node, and the "where" is the address held
|
||||||
|
* by "redirection".
|
||||||
|
*/
|
||||||
|
test_head.next = redirection;
|
||||||
|
list_add(&bad.node, &test_head);
|
||||||
|
|
||||||
|
if (target[0] == NULL && target[1] == NULL)
|
||||||
|
pr_err("Overwrite did not happen, but no BUG?!\n");
|
||||||
|
else
|
||||||
|
pr_err("list_add() corruption not detected!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void lkdtm_CORRUPT_LIST_DEL(void)
|
||||||
|
{
|
||||||
|
LIST_HEAD(test_head);
|
||||||
|
struct lkdtm_list item;
|
||||||
|
void *target[2] = { };
|
||||||
|
void *redirection = ⌖
|
||||||
|
|
||||||
|
list_add(&item.node, &test_head);
|
||||||
|
|
||||||
|
pr_info("attempting good list removal\n");
|
||||||
|
list_del(&item.node);
|
||||||
|
|
||||||
|
pr_info("attempting corrupted list removal\n");
|
||||||
|
list_add(&item.node, &test_head);
|
||||||
|
|
||||||
|
/* As with the list_add() test above, this corrupts "next". */
|
||||||
|
item.node.next = redirection;
|
||||||
|
list_del(&item.node);
|
||||||
|
|
||||||
|
if (target[0] == NULL && target[1] == NULL)
|
||||||
|
pr_err("Overwrite did not happen, but no BUG?!\n");
|
||||||
|
else
|
||||||
|
pr_err("list_del() corruption not detected!\n");
|
||||||
|
}
|
||||||
|
@ -197,6 +197,8 @@ struct crashtype crashtypes[] = {
|
|||||||
CRASHTYPE(EXCEPTION),
|
CRASHTYPE(EXCEPTION),
|
||||||
CRASHTYPE(LOOP),
|
CRASHTYPE(LOOP),
|
||||||
CRASHTYPE(OVERFLOW),
|
CRASHTYPE(OVERFLOW),
|
||||||
|
CRASHTYPE(CORRUPT_LIST_ADD),
|
||||||
|
CRASHTYPE(CORRUPT_LIST_DEL),
|
||||||
CRASHTYPE(CORRUPT_STACK),
|
CRASHTYPE(CORRUPT_STACK),
|
||||||
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
|
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
|
||||||
CRASHTYPE(OVERWRITE_ALLOCATION),
|
CRASHTYPE(OVERWRITE_ALLOCATION),
|
||||||
|
Loading…
Reference in New Issue
Block a user