lkdtm: Add a test for function descriptors protection

Add WRITE_OPD to check that you can't modify function
descriptors.

Gives the following result when function descriptors are
not protected:

	lkdtm: Performing direct entry WRITE_OPD
	lkdtm: attempting bad 16 bytes write at c00000000269b358
	lkdtm: FAIL: survived bad write
	lkdtm: do_nothing was hijacked!

Looks like a standard compiler barrier() is not enough to force
GCC to use the modified function descriptor. Had to add a fake empty
inline assembly to force GCC to reload the function descriptor.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/7eeba50d16a35e9d799820e43304150225f20197.1644928018.git.christophe.leroy@csgroup.eu
This commit is contained in:
Christophe Leroy 2022-02-15 13:41:08 +01:00 committed by Michael Ellerman
parent 72a8643304
commit 5e5a6c5441
4 changed files with 25 additions and 0 deletions

View file

@ -149,6 +149,7 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(WRITE_RO),
CRASHTYPE(WRITE_RO_AFTER_INIT),
CRASHTYPE(WRITE_KERN),
CRASHTYPE(WRITE_OPD),
CRASHTYPE(REFCOUNT_INC_OVERFLOW),
CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),

View file

@ -106,6 +106,7 @@ void __init lkdtm_perms_init(void);
void lkdtm_WRITE_RO(void);
void lkdtm_WRITE_RO_AFTER_INIT(void);
void lkdtm_WRITE_KERN(void);
void lkdtm_WRITE_OPD(void);
void lkdtm_EXEC_DATA(void);
void lkdtm_EXEC_STACK(void);
void lkdtm_EXEC_KMALLOC(void);

View file

@ -44,6 +44,11 @@ static noinline void do_overwritten(void)
return;
}
static noinline void do_almost_nothing(void)
{
pr_info("do_nothing was hijacked!\n");
}
static void *setup_function_descriptor(func_desc_t *fdesc, void *dst)
{
if (!have_function_descriptors())
@ -144,6 +149,23 @@ void lkdtm_WRITE_KERN(void)
do_overwritten();
}
void lkdtm_WRITE_OPD(void)
{
size_t size = sizeof(func_desc_t);
void (*func)(void) = do_nothing;
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");
asm("" : "=m"(func));
func();
}
void lkdtm_EXEC_DATA(void)
{
execute_location(data_area, CODE_WRITE);

View file

@ -44,6 +44,7 @@ ACCESS_NULL
WRITE_RO
WRITE_RO_AFTER_INIT
WRITE_KERN
WRITE_OPD
REFCOUNT_INC_OVERFLOW
REFCOUNT_ADD_OVERFLOW
REFCOUNT_INC_NOT_ZERO_OVERFLOW