linux/drivers/misc/lkdtm/perms.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * This is for all the tests related to validating kernel memory
   4 * permissions: non-executable regions, non-writable regions, and
   5 * even non-readable regions.
   6 */
   7#include "lkdtm.h"
   8#include <linux/slab.h>
   9#include <linux/vmalloc.h>
  10#include <linux/mman.h>
  11#include <linux/uaccess.h>
  12#include <asm/cacheflush.h>
  13
  14/* Whether or not to fill the target memory area with do_nothing(). */
  15#define CODE_WRITE      true
  16#define CODE_AS_IS      false
  17
  18/* How many bytes to copy to be sure we've copied enough of do_nothing(). */
  19#define EXEC_SIZE 64
  20
  21/* This is non-const, so it will end up in the .data section. */
  22static u8 data_area[EXEC_SIZE];
  23
  24/* This is cost, so it will end up in the .rodata section. */
  25static const unsigned long rodata = 0xAA55AA55;
  26
  27/* This is marked __ro_after_init, so it should ultimately be .rodata. */
  28static unsigned long ro_after_init __ro_after_init = 0x55AA5500;
  29
  30/*
  31 * This just returns to the caller. It is designed to be copied into
  32 * non-executable memory regions.
  33 */
  34static void do_nothing(void)
  35{
  36        return;
  37}
  38
  39/* Must immediately follow do_nothing for size calculuations to work out. */
  40static void do_overwritten(void)
  41{
  42        pr_info("do_overwritten wasn't overwritten!\n");
  43        return;
  44}
  45
  46static noinline void execute_location(void *dst, bool write)
  47{
  48        void (*func)(void) = dst;
  49
  50        pr_info("attempting ok execution at %px\n", do_nothing);
  51        do_nothing();
  52
  53        if (write == CODE_WRITE) {
  54                memcpy(dst, do_nothing, EXEC_SIZE);
  55                flush_icache_range((unsigned long)dst,
  56                                   (unsigned long)dst + EXEC_SIZE);
  57        }
  58        pr_info("attempting bad execution at %px\n", func);
  59        func();
  60        pr_err("FAIL: func returned\n");
  61}
  62
  63static void execute_user_location(void *dst)
  64{
  65        int copied;
  66
  67        /* Intentionally crossing kernel/user memory boundary. */
  68        void (*func)(void) = dst;
  69
  70        pr_info("attempting ok execution at %px\n", do_nothing);
  71        do_nothing();
  72
  73        copied = access_process_vm(current, (unsigned long)dst, do_nothing,
  74                                   EXEC_SIZE, FOLL_WRITE);
  75        if (copied < EXEC_SIZE)
  76                return;
  77        pr_info("attempting bad execution at %px\n", func);
  78        func();
  79        pr_err("FAIL: func returned\n");
  80}
  81
  82void lkdtm_WRITE_RO(void)
  83{
  84        /* Explicitly cast away "const" for the test and make volatile. */
  85        volatile unsigned long *ptr = (unsigned long *)&rodata;
  86
  87        pr_info("attempting bad rodata write at %px\n", ptr);
  88        *ptr ^= 0xabcd1234;
  89        pr_err("FAIL: survived bad write\n");
  90}
  91
  92void lkdtm_WRITE_RO_AFTER_INIT(void)
  93{
  94        volatile unsigned long *ptr = &ro_after_init;
  95
  96        /*
  97         * Verify we were written to during init. Since an Oops
  98         * is considered a "success", a failure is to just skip the
  99         * real test.
 100         */
 101        if ((*ptr & 0xAA) != 0xAA) {
 102                pr_info("%p was NOT written during init!?\n", ptr);
 103                return;
 104        }
 105
 106        pr_info("attempting bad ro_after_init write at %px\n", ptr);
 107        *ptr ^= 0xabcd1234;
 108        pr_err("FAIL: survived bad write\n");
 109}
 110
 111void lkdtm_WRITE_KERN(void)
 112{
 113        size_t size;
 114        volatile unsigned char *ptr;
 115
 116        size = (unsigned long)do_overwritten - (unsigned long)do_nothing;
 117        ptr = (unsigned char *)do_overwritten;
 118
 119        pr_info("attempting bad %zu byte write at %px\n", size, ptr);
 120        memcpy((void *)ptr, (unsigned char *)do_nothing, size);
 121        flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size));
 122        pr_err("FAIL: survived bad write\n");
 123
 124        do_overwritten();
 125}
 126
 127void lkdtm_EXEC_DATA(void)
 128{
 129        execute_location(data_area, CODE_WRITE);
 130}
 131
 132void lkdtm_EXEC_STACK(void)
 133{
 134        u8 stack_area[EXEC_SIZE];
 135        execute_location(stack_area, CODE_WRITE);
 136}
 137
 138void lkdtm_EXEC_KMALLOC(void)
 139{
 140        u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL);
 141        execute_location(kmalloc_area, CODE_WRITE);
 142        kfree(kmalloc_area);
 143}
 144
 145void lkdtm_EXEC_VMALLOC(void)
 146{
 147        u32 *vmalloc_area = vmalloc(EXEC_SIZE);
 148        execute_location(vmalloc_area, CODE_WRITE);
 149        vfree(vmalloc_area);
 150}
 151
 152void lkdtm_EXEC_RODATA(void)
 153{
 154        execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS);
 155}
 156
 157void lkdtm_EXEC_USERSPACE(void)
 158{
 159        unsigned long user_addr;
 160
 161        user_addr = vm_mmap(NULL, 0, PAGE_SIZE,
 162                            PROT_READ | PROT_WRITE | PROT_EXEC,
 163                            MAP_ANONYMOUS | MAP_PRIVATE, 0);
 164        if (user_addr >= TASK_SIZE) {
 165                pr_warn("Failed to allocate user memory\n");
 166                return;
 167        }
 168        execute_user_location((void *)user_addr);
 169        vm_munmap(user_addr, PAGE_SIZE);
 170}
 171
 172void lkdtm_EXEC_NULL(void)
 173{
 174        execute_location(NULL, CODE_AS_IS);
 175}
 176
 177void lkdtm_ACCESS_USERSPACE(void)
 178{
 179        unsigned long user_addr, tmp = 0;
 180        unsigned long *ptr;
 181
 182        user_addr = vm_mmap(NULL, 0, PAGE_SIZE,
 183                            PROT_READ | PROT_WRITE | PROT_EXEC,
 184                            MAP_ANONYMOUS | MAP_PRIVATE, 0);
 185        if (user_addr >= TASK_SIZE) {
 186                pr_warn("Failed to allocate user memory\n");
 187                return;
 188        }
 189
 190        if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) {
 191                pr_warn("copy_to_user failed\n");
 192                vm_munmap(user_addr, PAGE_SIZE);
 193                return;
 194        }
 195
 196        ptr = (unsigned long *)user_addr;
 197
 198        pr_info("attempting bad read at %px\n", ptr);
 199        tmp = *ptr;
 200        tmp += 0xc0dec0de;
 201        pr_err("FAIL: survived bad read\n");
 202
 203        pr_info("attempting bad write at %px\n", ptr);
 204        *ptr = tmp;
 205        pr_err("FAIL: survived bad write\n");
 206
 207        vm_munmap(user_addr, PAGE_SIZE);
 208}
 209
 210void lkdtm_ACCESS_NULL(void)
 211{
 212        unsigned long tmp;
 213        volatile unsigned long *ptr = (unsigned long *)NULL;
 214
 215        pr_info("attempting bad read at %px\n", ptr);
 216        tmp = *ptr;
 217        tmp += 0xc0dec0de;
 218        pr_err("FAIL: survived bad read\n");
 219
 220        pr_info("attempting bad write at %px\n", ptr);
 221        *ptr = tmp;
 222        pr_err("FAIL: survived bad write\n");
 223}
 224
 225void __init lkdtm_perms_init(void)
 226{
 227        /* Make sure we can write to __ro_after_init values during __init */
 228        ro_after_init |= 0xAA;
 229}
 230