Skip to content

Commit

Permalink
BACKPORT: lkdtm: Add tests for struct list corruption
Browse files Browse the repository at this point in the history
(cherry-picked from 6819d10)

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.

Change-Id: Iddf70c61b745342dd4f055dc9c1eb221ca779c2e
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>
Signed-off-by: Satya Tangirala <satyat@google.com>
  • Loading branch information
kees authored and Satya Tangirala committed Sep 21, 2018
1 parent a1c1aff commit 7e5f215
Showing 1 changed file with 70 additions and 0 deletions.
70 changes: 70 additions & 0 deletions drivers/misc/lkdtm.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,16 @@
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <asm/cacheflush.h>
#include <linux/list.h>

#ifdef CONFIG_IDE
#include <linux/ide.h>
#endif

struct lkdtm_list {
struct list_head node;
};

/*
* 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
Expand Down Expand Up @@ -88,6 +93,8 @@ enum ctype {
CT_EXCEPTION,
CT_LOOP,
CT_OVERFLOW,
CT_CORRUPT_LIST_ADD,
CT_CORRUPT_LIST_DEL,
CT_CORRUPT_STACK,
CT_UNALIGNED_LOAD_STORE_WRITE,
CT_OVERWRITE_ALLOCATION,
Expand Down Expand Up @@ -126,6 +133,8 @@ static char* cp_type[] = {
"EXCEPTION",
"LOOP",
"OVERFLOW",
"CORRUPT_LIST_ADD",
"CORRUPT_LIST_DEL",
"CORRUPT_STACK",
"UNALIGNED_LOAD_STORE_WRITE",
"OVERWRITE_ALLOCATION",
Expand Down Expand Up @@ -542,6 +551,67 @@ static void lkdtm_do_action(enum ctype which)
do_overwritten();
break;
}
case CT_CORRUPT_LIST_ADD: {
/*
* 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 = &target;

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");
break;
}
case CT_CORRUPT_LIST_DEL: {
LIST_HEAD(test_head);
struct lkdtm_list item;
void *target[2] = { };
void *redirection = &target;

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");
break;
}
case CT_NONE:
default:
break;
Expand Down

0 comments on commit 7e5f215

Please sign in to comment.