.. | .. |
---|
7 | 7 | #include <linux/slab.h> |
---|
8 | 8 | #include <linux/sched.h> |
---|
9 | 9 | |
---|
| 10 | +static struct kmem_cache *double_free_cache; |
---|
| 11 | +static struct kmem_cache *a_cache; |
---|
| 12 | +static struct kmem_cache *b_cache; |
---|
| 13 | + |
---|
10 | 14 | /* |
---|
11 | 15 | * This tries to stay within the next largest power-of-2 kmalloc cache |
---|
12 | 16 | * to avoid actually overwriting anything important if it's not detected |
---|
.. | .. |
---|
54 | 58 | int *base, *val, saw; |
---|
55 | 59 | size_t len = 1024; |
---|
56 | 60 | /* |
---|
57 | | - * The slub allocator uses the first word to store the free |
---|
58 | | - * pointer in some configurations. Use the middle of the |
---|
59 | | - * allocation to avoid running into the freelist |
---|
| 61 | + * The slub allocator will use the either the first word or |
---|
| 62 | + * the middle of the allocation to store the free pointer, |
---|
| 63 | + * depending on configurations. Store in the second word to |
---|
| 64 | + * avoid running into the freelist. |
---|
60 | 65 | */ |
---|
61 | | - size_t offset = (len / sizeof(*base)) / 2; |
---|
| 66 | + size_t offset = sizeof(*base); |
---|
62 | 67 | |
---|
63 | 68 | base = kmalloc(len, GFP_KERNEL); |
---|
64 | 69 | if (!base) { |
---|
.. | .. |
---|
146 | 151 | |
---|
147 | 152 | kfree(val); |
---|
148 | 153 | } |
---|
| 154 | + |
---|
| 155 | +void lkdtm_SLAB_FREE_DOUBLE(void) |
---|
| 156 | +{ |
---|
| 157 | + int *val; |
---|
| 158 | + |
---|
| 159 | + val = kmem_cache_alloc(double_free_cache, GFP_KERNEL); |
---|
| 160 | + if (!val) { |
---|
| 161 | + pr_info("Unable to allocate double_free_cache memory.\n"); |
---|
| 162 | + return; |
---|
| 163 | + } |
---|
| 164 | + |
---|
| 165 | + /* Just make sure we got real memory. */ |
---|
| 166 | + *val = 0x12345678; |
---|
| 167 | + pr_info("Attempting double slab free ...\n"); |
---|
| 168 | + kmem_cache_free(double_free_cache, val); |
---|
| 169 | + kmem_cache_free(double_free_cache, val); |
---|
| 170 | +} |
---|
| 171 | + |
---|
| 172 | +void lkdtm_SLAB_FREE_CROSS(void) |
---|
| 173 | +{ |
---|
| 174 | + int *val; |
---|
| 175 | + |
---|
| 176 | + val = kmem_cache_alloc(a_cache, GFP_KERNEL); |
---|
| 177 | + if (!val) { |
---|
| 178 | + pr_info("Unable to allocate a_cache memory.\n"); |
---|
| 179 | + return; |
---|
| 180 | + } |
---|
| 181 | + |
---|
| 182 | + /* Just make sure we got real memory. */ |
---|
| 183 | + *val = 0x12345679; |
---|
| 184 | + pr_info("Attempting cross-cache slab free ...\n"); |
---|
| 185 | + kmem_cache_free(b_cache, val); |
---|
| 186 | +} |
---|
| 187 | + |
---|
| 188 | +void lkdtm_SLAB_FREE_PAGE(void) |
---|
| 189 | +{ |
---|
| 190 | + unsigned long p = __get_free_page(GFP_KERNEL); |
---|
| 191 | + |
---|
| 192 | + pr_info("Attempting non-Slab slab free ...\n"); |
---|
| 193 | + kmem_cache_free(NULL, (void *)p); |
---|
| 194 | + free_page(p); |
---|
| 195 | +} |
---|
| 196 | + |
---|
| 197 | +/* |
---|
| 198 | + * We have constructors to keep the caches distinctly separated without |
---|
| 199 | + * needing to boot with "slab_nomerge". |
---|
| 200 | + */ |
---|
| 201 | +static void ctor_double_free(void *region) |
---|
| 202 | +{ } |
---|
| 203 | +static void ctor_a(void *region) |
---|
| 204 | +{ } |
---|
| 205 | +static void ctor_b(void *region) |
---|
| 206 | +{ } |
---|
| 207 | + |
---|
| 208 | +void __init lkdtm_heap_init(void) |
---|
| 209 | +{ |
---|
| 210 | + double_free_cache = kmem_cache_create("lkdtm-heap-double_free", |
---|
| 211 | + 64, 0, 0, ctor_double_free); |
---|
| 212 | + a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a); |
---|
| 213 | + b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b); |
---|
| 214 | +} |
---|
| 215 | + |
---|
| 216 | +void __exit lkdtm_heap_exit(void) |
---|
| 217 | +{ |
---|
| 218 | + kmem_cache_destroy(double_free_cache); |
---|
| 219 | + kmem_cache_destroy(a_cache); |
---|
| 220 | + kmem_cache_destroy(b_cache); |
---|
| 221 | +} |
---|