diff options
Diffstat (limited to 'drivers/misc/lkdtm/bugs.c')
| -rw-r--r-- | drivers/misc/lkdtm/bugs.c | 111 | 
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index de87693cf557..886459e0ddd9 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -11,6 +11,7 @@  #include <linux/sched/signal.h>  #include <linux/sched/task_stack.h>  #include <linux/uaccess.h> +#include <linux/slab.h>  #ifdef CONFIG_X86_32  #include <asm/desc.h> @@ -175,6 +176,80 @@ void lkdtm_HUNG_TASK(void)  	schedule();  } +volatile unsigned int huge = INT_MAX - 2; +volatile unsigned int ignored; + +void lkdtm_OVERFLOW_SIGNED(void) +{ +	int value; + +	value = huge; +	pr_info("Normal signed addition ...\n"); +	value += 1; +	ignored = value; + +	pr_info("Overflowing signed addition ...\n"); +	value += 4; +	ignored = value; +} + + +void lkdtm_OVERFLOW_UNSIGNED(void) +{ +	unsigned int value; + +	value = huge; +	pr_info("Normal unsigned addition ...\n"); +	value += 1; +	ignored = value; + +	pr_info("Overflowing unsigned addition ...\n"); +	value += 4; +	ignored = value; +} + +/* Intentially using old-style flex array definition of 1 byte. */ +struct array_bounds_flex_array { +	int one; +	int two; +	char data[1]; +}; + +struct array_bounds { +	int one; +	int two; +	char data[8]; +	int three; +}; + +void lkdtm_ARRAY_BOUNDS(void) +{ +	struct array_bounds_flex_array *not_checked; +	struct array_bounds *checked; +	volatile int i; + +	not_checked = kmalloc(sizeof(*not_checked) * 2, GFP_KERNEL); +	checked = kmalloc(sizeof(*checked) * 2, GFP_KERNEL); + +	pr_info("Array access within bounds ...\n"); +	/* For both, touch all bytes in the actual member size. */ +	for (i = 0; i < sizeof(checked->data); i++) +		checked->data[i] = 'A'; +	/* +	 * For the uninstrumented flex array member, also touch 1 byte +	 * beyond to verify it is correctly uninstrumented. +	 */ +	for (i = 0; i < sizeof(not_checked->data) + 1; i++) +		not_checked->data[i] = 'A'; + +	pr_info("Array access beyond bounds ...\n"); +	for (i = 0; i < sizeof(checked->data) + 1; i++) +		checked->data[i] = 'B'; + +	kfree(not_checked); +	kfree(checked); +} +  void lkdtm_CORRUPT_LIST_ADD(void)  {  	/* @@ -378,3 +453,39 @@ void lkdtm_DOUBLE_FAULT(void)  	pr_err("XFAIL: this test is ia32-only\n");  #endif  } + +#ifdef CONFIG_ARM64_PTR_AUTH +static noinline void change_pac_parameters(void) +{ +	/* Reset the keys of current task */ +	ptrauth_thread_init_kernel(current); +	ptrauth_thread_switch_kernel(current); +} + +#define CORRUPT_PAC_ITERATE	10 +noinline void lkdtm_CORRUPT_PAC(void) +{ +	int i; + +	if (!system_supports_address_auth()) { +		pr_err("FAIL: arm64 pointer authentication feature not present\n"); +		return; +	} + +	pr_info("Change the PAC parameters to force function return failure\n"); +	/* +	 * Pac is a hash value computed from input keys, return address and +	 * stack pointer. As pac has fewer bits so there is a chance of +	 * collision, so iterate few times to reduce the collision probability. +	 */ +	for (i = 0; i < CORRUPT_PAC_ITERATE; i++) +		change_pac_parameters(); + +	pr_err("FAIL: %s test failed. Kernel may be unstable from here\n", __func__); +} +#else /* !CONFIG_ARM64_PTR_AUTH */ +noinline void lkdtm_CORRUPT_PAC(void) +{ +	pr_err("FAIL: arm64 pointer authentication config disabled\n"); +} +#endif  |