KSPP / linux

Linux kernel source tree (Kernel Self Protection Project)
https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Project
Other
81 stars 5 forks source link

lkdtm WRITE_KERN and related tests do not work on systems using function descriptors #165

Closed chleroy closed 2 years ago

chleroy commented 2 years ago

First problem: the code expects do_overwritten() to be immediately after do_nothing(), but allthough they are consecutive in the source file, in the kernel image they are not:

c0502f18 T lkdtm_SLAB_FREE_PAGE
c0502f6c t do_nothing
c0502f70 T lkdtm_EXEC_KMALLOC
c0502fb8 T lkdtm_EXEC_VMALLOC
c0502ff4 T lkdtm_EXEC_USERSPACE
c05030cc T lkdtm_ACCESS_USERSPACE
c05031b0 t do_overwritten
c05031bc t execute_location
c050324c T lkdtm_WRITE_RO

Second problem: GCC inlines do_overwritten() inside lkdtm_WRITE_KERN(), so when surviving bad write you get do_overwritten wasn't overwritten!

Third problem: On ppc64 (and likely on parisc and ia64), lkdtm_WRITE_KERN() overwrites the function descriptor instead of overwritting the function text, because call to dereference_function_descriptor() has been forgotten.

chleroy commented 2 years ago

Second and third problem fixed by patch https://patchwork.ozlabs.org/project/linuxppc-dev/patch/624940395e5d81967246f911a65740b9a15b5a70.1633964380.git.christophe.leroy@csgroup.eu/

First problem I don't know what to do about it.

kees commented 2 years ago

I thought I had a new horrible hack for problem 1, but this only works on GCC:

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

void __attribute__((__noinline__)) do_thing(unsigned long *end)
{
    static void *array[] = { &&label_start, &&label_end, };

label_start:
    if (end)
        *end = (unsigned long)array[1] - (unsigned long)do_thing;

    printf("do_thing: %p\n", do_thing);
    printf("labels: %zu\n", sizeof(array) / sizeof(array[0]));
    printf("first label: %lx\n", (size_t)array[0]);
    printf("final label: %lx\n", (size_t)array[1]);

    puts("done");
    return;
label_end:
    ;
}

int main(void)
{
    unsigned long size;

    do_thing(&size);
    printf("size of do_thing(): %zu\n", size);
    return 0;
}
chleroy commented 2 years ago

I'm not an expert with Makefiles and Kconfig, can we use some post-processing and get the function size from the object file with objdump ?

kees commented 2 years ago

Commit 69b420ed8fd3917ac7073256b4929aa246b6fe31 Commit b64913394f123e819bffabc79a0e48f98e78dc5d (v5.18)