// SPDX-License-Identifier: GPL-2.0 /* * This is for all the tests related to validating kernel memory * permissions: non-executable regions, non-writable regions, and * even non-readable regions.
*/ #include"lkdtm.h" #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/mman.h> #include <linux/uaccess.h> #include <asm/cacheflush.h> #include <asm/sections.h>
/* Whether or not to fill the target memory area with do_nothing(). */ #define CODE_WRITE true #define CODE_AS_IS false
/* How many bytes to copy to be sure we've copied enough of do_nothing(). */ #define EXEC_SIZE 64
/* This is non-const, so it will end up in the .data section. */ static u8 data_area[EXEC_SIZE];
/* This is const, so it will end up in the .rodata section. */ staticconstunsignedlong rodata = 0xAA55AA55;
/* This is marked __ro_after_init, so it should ultimately be .rodata. */ staticunsignedlong ro_after_init __ro_after_init = 0x55AA5500;
/* * This is a pointer to do_nothing() which is initialized at runtime rather * than build time to avoid objtool IBT validation warnings caused by an * inlined unrolled memcpy() in execute_location().
*/ staticvoid __ro_after_init *do_nothing_ptr;
/* * This just returns to the caller. It is designed to be copied into * non-executable memory regions.
*/ static noinline void do_nothing(void)
{ return;
}
/* Must immediately follow do_nothing for size calculuations to work out. */ static noinline void do_overwritten(void)
{
pr_info("do_overwritten wasn't overwritten!\n"); return;
}
static noinline void do_almost_nothing(void)
{
pr_info("do_nothing was hijacked!\n");
}
staticvoid *setup_function_descriptor(func_desc_t *fdesc, void *dst)
{ if (!have_function_descriptors()) return dst;
pr_info("attempting ok execution at %px\n", do_nothing_text);
do_nothing();
copied = access_process_vm(current, (unsignedlong)dst, do_nothing_text,
EXEC_SIZE, FOLL_WRITE); if (copied < EXEC_SIZE) return;
pr_info("attempting bad execution at %px\n", dst);
func = setup_function_descriptor(&fdesc, dst);
func();
pr_err("FAIL: func returned\n");
}
staticvoid lkdtm_WRITE_RO(void)
{ /* Explicitly cast away "const" for the test and make volatile. */ volatileunsignedlong *ptr = (unsignedlong *)&rodata;
pr_info("attempting bad rodata write at %px\n", ptr);
*ptr ^= 0xabcd1234;
pr_err("FAIL: survived bad write\n");
}
/* * Verify we were written to during init. Since an Oops * is considered a "success", a failure is to just skip the * real test.
*/ if ((*ptr & 0xAA) != 0xAA) {
pr_info("%p was NOT written during init!?\n", ptr); return;
}
pr_info("attempting bad ro_after_init write at %px\n", ptr);
*ptr ^= 0xabcd1234;
pr_err("FAIL: survived bad write\n");
}
if (!have_function_descriptors()) {
pr_info("XFAIL: Platform doesn't use function descriptors.\n"); return;
}
pr_info("attempting bad %zu bytes write at %px\n", size, do_nothing);
memcpy(do_nothing, do_almost_nothing, size);
pr_err("FAIL: survived bad write\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.