Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c318e77 authored by Kees Cook's avatar Kees Cook Committed by Satya Tangirala
Browse files

BACKPORT: lkdtm: Add tests for struct list corruption



(cherry-picked from 6819d101dd739dd4e8cbe60a98c9ebb224ecc992)

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: default avatarKees Cook <keescook@chromium.org>
Acked-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: default avatarRik van Riel <riel@redhat.com>
Signed-off-by: default avatarSatya Tangirala <satyat@google.com>
parent 7514f972
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -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
@@ -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,
@@ -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",
@@ -548,6 +557,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;