lkdtm: Add READ_AFTER_FREE test
In a similar manner to WRITE_AFTER_FREE, add a READ_AFTER_FREE test to test free poisoning features. Sample output when no sanitization is present: # echo READ_AFTER_FREE > /sys/kernel/debug/provoke-crash/DIRECT [ 17.542473] lkdtm: Performing direct entry READ_AFTER_FREE [ 17.543866] lkdtm: Value in memory before free: 12345678 [ 17.545212] lkdtm: Attempting bad read from freed memory [ 17.546542] lkdtm: Memory was not poisoned with slub_debug=P: # echo READ_AFTER_FREE > /sys/kernel/debug/provoke-crash/DIRECT [ 22.415531] lkdtm: Performing direct entry READ_AFTER_FREE [ 22.416366] lkdtm: Value in memory before free: 12345678 [ 22.417137] lkdtm: Attempting bad read from freed memory [ 22.417897] lkdtm: Memory correctly poisoned, calling BUG Signed-off-by: Laura Abbott <labbott@fedoraproject.org> Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
@@ -92,6 +92,7 @@ enum ctype {
|
|||||||
CT_UNALIGNED_LOAD_STORE_WRITE,
|
CT_UNALIGNED_LOAD_STORE_WRITE,
|
||||||
CT_OVERWRITE_ALLOCATION,
|
CT_OVERWRITE_ALLOCATION,
|
||||||
CT_WRITE_AFTER_FREE,
|
CT_WRITE_AFTER_FREE,
|
||||||
|
CT_READ_AFTER_FREE,
|
||||||
CT_SOFTLOCKUP,
|
CT_SOFTLOCKUP,
|
||||||
CT_HARDLOCKUP,
|
CT_HARDLOCKUP,
|
||||||
CT_SPINLOCKUP,
|
CT_SPINLOCKUP,
|
||||||
@@ -129,6 +130,7 @@ static char* cp_type[] = {
|
|||||||
"UNALIGNED_LOAD_STORE_WRITE",
|
"UNALIGNED_LOAD_STORE_WRITE",
|
||||||
"OVERWRITE_ALLOCATION",
|
"OVERWRITE_ALLOCATION",
|
||||||
"WRITE_AFTER_FREE",
|
"WRITE_AFTER_FREE",
|
||||||
|
"READ_AFTER_FREE",
|
||||||
"SOFTLOCKUP",
|
"SOFTLOCKUP",
|
||||||
"HARDLOCKUP",
|
"HARDLOCKUP",
|
||||||
"SPINLOCKUP",
|
"SPINLOCKUP",
|
||||||
@@ -417,6 +419,42 @@ static void lkdtm_do_action(enum ctype which)
|
|||||||
memset(data, 0x78, len);
|
memset(data, 0x78, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CT_READ_AFTER_FREE: {
|
||||||
|
int *base, *val, saw;
|
||||||
|
size_t len = 1024;
|
||||||
|
/*
|
||||||
|
* The slub allocator uses the first word to store the free
|
||||||
|
* pointer in some configurations. Use the middle of the
|
||||||
|
* allocation to avoid running into the freelist
|
||||||
|
*/
|
||||||
|
size_t offset = (len / sizeof(*base)) / 2;
|
||||||
|
|
||||||
|
base = kmalloc(len, GFP_KERNEL);
|
||||||
|
if (!base)
|
||||||
|
break;
|
||||||
|
|
||||||
|
val = kmalloc(len, GFP_KERNEL);
|
||||||
|
if (!val)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*val = 0x12345678;
|
||||||
|
base[offset] = *val;
|
||||||
|
pr_info("Value in memory before free: %x\n", base[offset]);
|
||||||
|
|
||||||
|
kfree(base);
|
||||||
|
|
||||||
|
pr_info("Attempting bad read from freed memory\n");
|
||||||
|
saw = base[offset];
|
||||||
|
if (saw != *val) {
|
||||||
|
/* Good! Poisoning happened, so declare a win. */
|
||||||
|
pr_info("Memory correctly poisoned, calling BUG\n");
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
pr_info("Memory was not poisoned\n");
|
||||||
|
|
||||||
|
kfree(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CT_SOFTLOCKUP:
|
case CT_SOFTLOCKUP:
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
for (;;)
|
for (;;)
|
||||||
|
|||||||
Reference in New Issue
Block a user