linux/drivers/misc/lkdtm/heap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * This is for all the tests relating directly to heap memory, including
   4 * page allocation and slab allocations.
   5 */
   6#include "lkdtm.h"
   7#include <linux/slab.h>
   8#include <linux/vmalloc.h>
   9#include <linux/sched.h>
  10
  11static struct kmem_cache *double_free_cache;
  12static struct kmem_cache *a_cache;
  13static struct kmem_cache *b_cache;
  14
  15/*
  16 * If there aren't guard pages, it's likely that a consecutive allocation will
  17 * let us overflow into the second allocation without overwriting something real.
  18 */
  19void lkdtm_VMALLOC_LINEAR_OVERFLOW(void)
  20{
  21        char *one, *two;
  22
  23        one = vzalloc(PAGE_SIZE);
  24        two = vzalloc(PAGE_SIZE);
  25
  26        pr_info("Attempting vmalloc linear overflow ...\n");
  27        memset(one, 0xAA, PAGE_SIZE + 1);
  28
  29        vfree(two);
  30        vfree(one);
  31}
  32
  33/*
  34 * This tries to stay within the next largest power-of-2 kmalloc cache
  35 * to avoid actually overwriting anything important if it's not detected
  36 * correctly.
  37 */
  38void lkdtm_SLAB_LINEAR_OVERFLOW(void)
  39{
  40        size_t len = 1020;
  41        u32 *data = kmalloc(len, GFP_KERNEL);
  42        if (!data)
  43                return;
  44
  45        pr_info("Attempting slab linear overflow ...\n");
  46        data[1024 / sizeof(u32)] = 0x12345678;
  47        kfree(data);
  48}
  49
  50void lkdtm_WRITE_AFTER_FREE(void)
  51{
  52        int *base, *again;
  53        size_t len = 1024;
  54        /*
  55         * The slub allocator uses the first word to store the free
  56         * pointer in some configurations. Use the middle of the
  57         * allocation to avoid running into the freelist
  58         */
  59        size_t offset = (len / sizeof(*base)) / 2;
  60
  61        base = kmalloc(len, GFP_KERNEL);
  62        if (!base)
  63                return;
  64        pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]);
  65        pr_info("Attempting bad write to freed memory at %p\n",
  66                &base[offset]);
  67        kfree(base);
  68        base[offset] = 0x0abcdef0;
  69        /* Attempt to notice the overwrite. */
  70        again = kmalloc(len, GFP_KERNEL);
  71        kfree(again);
  72        if (again != base)
  73                pr_info("Hmm, didn't get the same memory range.\n");
  74}
  75
  76void lkdtm_READ_AFTER_FREE(void)
  77{
  78        int *base, *val, saw;
  79        size_t len = 1024;
  80        /*
  81         * The slub allocator will use the either the first word or
  82         * the middle of the allocation to store the free pointer,
  83         * depending on configurations. Store in the second word to
  84         * avoid running into the freelist.
  85         */
  86        size_t offset = sizeof(*base);
  87
  88        base = kmalloc(len, GFP_KERNEL);
  89        if (!base) {
  90                pr_info("Unable to allocate base memory.\n");
  91                return;
  92        }
  93
  94        val = kmalloc(len, GFP_KERNEL);
  95        if (!val) {
  96                pr_info("Unable to allocate val memory.\n");
  97                kfree(base);
  98                return;
  99        }
 100
 101        *val = 0x12345678;
 102        base[offset] = *val;
 103        pr_info("Value in memory before free: %x\n", base[offset]);
 104
 105        kfree(base);
 106
 107        pr_info("Attempting bad read from freed memory\n");
 108        saw = base[offset];
 109        if (saw != *val) {
 110                /* Good! Poisoning happened, so declare a win. */
 111                pr_info("Memory correctly poisoned (%x)\n", saw);
 112        } else {
 113                pr_err("FAIL: Memory was not poisoned!\n");
 114                pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free");
 115        }
 116
 117        kfree(val);
 118}
 119
 120void lkdtm_WRITE_BUDDY_AFTER_FREE(void)
 121{
 122        unsigned long p = __get_free_page(GFP_KERNEL);
 123        if (!p) {
 124                pr_info("Unable to allocate free page\n");
 125                return;
 126        }
 127
 128        pr_info("Writing to the buddy page before free\n");
 129        memset((void *)p, 0x3, PAGE_SIZE);
 130        free_page(p);
 131        schedule();
 132        pr_info("Attempting bad write to the buddy page after free\n");
 133        memset((void *)p, 0x78, PAGE_SIZE);
 134        /* Attempt to notice the overwrite. */
 135        p = __get_free_page(GFP_KERNEL);
 136        free_page(p);
 137        schedule();
 138}
 139
 140void lkdtm_READ_BUDDY_AFTER_FREE(void)
 141{
 142        unsigned long p = __get_free_page(GFP_KERNEL);
 143        int saw, *val;
 144        int *base;
 145
 146        if (!p) {
 147                pr_info("Unable to allocate free page\n");
 148                return;
 149        }
 150
 151        val = kmalloc(1024, GFP_KERNEL);
 152        if (!val) {
 153                pr_info("Unable to allocate val memory.\n");
 154                free_page(p);
 155                return;
 156        }
 157
 158        base = (int *)p;
 159
 160        *val = 0x12345678;
 161        base[0] = *val;
 162        pr_info("Value in memory before free: %x\n", base[0]);
 163        free_page(p);
 164        pr_info("Attempting to read from freed memory\n");
 165        saw = base[0];
 166        if (saw != *val) {
 167                /* Good! Poisoning happened, so declare a win. */
 168                pr_info("Memory correctly poisoned (%x)\n", saw);
 169        } else {
 170                pr_err("FAIL: Buddy page was not poisoned!\n");
 171                pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free");
 172        }
 173
 174        kfree(val);
 175}
 176
 177void lkdtm_SLAB_INIT_ON_ALLOC(void)
 178{
 179        u8 *first;
 180        u8 *val;
 181
 182        first = kmalloc(512, GFP_KERNEL);
 183        if (!first) {
 184                pr_info("Unable to allocate 512 bytes the first time.\n");
 185                return;
 186        }
 187
 188        memset(first, 0xAB, 512);
 189        kfree(first);
 190
 191        val = kmalloc(512, GFP_KERNEL);
 192        if (!val) {
 193                pr_info("Unable to allocate 512 bytes the second time.\n");
 194                return;
 195        }
 196        if (val != first) {
 197                pr_warn("Reallocation missed clobbered memory.\n");
 198        }
 199
 200        if (memchr(val, 0xAB, 512) == NULL) {
 201                pr_info("Memory appears initialized (%x, no earlier values)\n", *val);
 202        } else {
 203                pr_err("FAIL: Slab was not initialized\n");
 204                pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc");
 205        }
 206        kfree(val);
 207}
 208
 209void lkdtm_BUDDY_INIT_ON_ALLOC(void)
 210{
 211        u8 *first;
 212        u8 *val;
 213
 214        first = (u8 *)__get_free_page(GFP_KERNEL);
 215        if (!first) {
 216                pr_info("Unable to allocate first free page\n");
 217                return;
 218        }
 219
 220        memset(first, 0xAB, PAGE_SIZE);
 221        free_page((unsigned long)first);
 222
 223        val = (u8 *)__get_free_page(GFP_KERNEL);
 224        if (!val) {
 225                pr_info("Unable to allocate second free page\n");
 226                return;
 227        }
 228
 229        if (val != first) {
 230                pr_warn("Reallocation missed clobbered memory.\n");
 231        }
 232
 233        if (memchr(val, 0xAB, PAGE_SIZE) == NULL) {
 234                pr_info("Memory appears initialized (%x, no earlier values)\n", *val);
 235        } else {
 236                pr_err("FAIL: Slab was not initialized\n");
 237                pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc");
 238        }
 239        free_page((unsigned long)val);
 240}
 241
 242void lkdtm_SLAB_FREE_DOUBLE(void)
 243{
 244        int *val;
 245
 246        val = kmem_cache_alloc(double_free_cache, GFP_KERNEL);
 247        if (!val) {
 248                pr_info("Unable to allocate double_free_cache memory.\n");
 249                return;
 250        }
 251
 252        /* Just make sure we got real memory. */
 253        *val = 0x12345678;
 254        pr_info("Attempting double slab free ...\n");
 255        kmem_cache_free(double_free_cache, val);
 256        kmem_cache_free(double_free_cache, val);
 257}
 258
 259void lkdtm_SLAB_FREE_CROSS(void)
 260{
 261        int *val;
 262
 263        val = kmem_cache_alloc(a_cache, GFP_KERNEL);
 264        if (!val) {
 265                pr_info("Unable to allocate a_cache memory.\n");
 266                return;
 267        }
 268
 269        /* Just make sure we got real memory. */
 270        *val = 0x12345679;
 271        pr_info("Attempting cross-cache slab free ...\n");
 272        kmem_cache_free(b_cache, val);
 273}
 274
 275void lkdtm_SLAB_FREE_PAGE(void)
 276{
 277        unsigned long p = __get_free_page(GFP_KERNEL);
 278
 279        pr_info("Attempting non-Slab slab free ...\n");
 280        kmem_cache_free(NULL, (void *)p);
 281        free_page(p);
 282}
 283
 284/*
 285 * We have constructors to keep the caches distinctly separated without
 286 * needing to boot with "slab_nomerge".
 287 */
 288static void ctor_double_free(void *region)
 289{ }
 290static void ctor_a(void *region)
 291{ }
 292static void ctor_b(void *region)
 293{ }
 294
 295void __init lkdtm_heap_init(void)
 296{
 297        double_free_cache = kmem_cache_create("lkdtm-heap-double_free",
 298                                              64, 0, 0, ctor_double_free);
 299        a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a);
 300        b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b);
 301}
 302
 303void __exit lkdtm_heap_exit(void)
 304{
 305        kmem_cache_destroy(double_free_cache);
 306        kmem_cache_destroy(a_cache);
 307        kmem_cache_destroy(b_cache);
 308}
 309