1#include <linux/kmemcheck.h> 2#include <linux/module.h> 3#include <linux/mm.h> 4 5#include <asm/page.h> 6#include <asm/pgtable.h> 7 8#include "pte.h" 9#include "shadow.h" 10 11/* 12 * Return the shadow address for the given address. Returns NULL if the 13 * address is not tracked. 14 * 15 * We need to be extremely careful not to follow any invalid pointers, 16 * because this function can be called for *any* possible address. 17 */ 18void *kmemcheck_shadow_lookup(unsigned long address) 19{ 20 pte_t *pte; 21 struct page *page; 22 23 if (!virt_addr_valid(address)) 24 return NULL; 25 26 pte = kmemcheck_pte_lookup(address); 27 if (!pte) 28 return NULL; 29 30 page = virt_to_page(address); 31 if (!page->shadow) 32 return NULL; 33 return page->shadow + (address & (PAGE_SIZE - 1)); 34} 35 36static void mark_shadow(void *address, unsigned int n, 37 enum kmemcheck_shadow status) 38{ 39 unsigned long addr = (unsigned long) address; 40 unsigned long last_addr = addr + n - 1; 41 unsigned long page = addr & PAGE_MASK; 42 unsigned long last_page = last_addr & PAGE_MASK; 43 unsigned int first_n; 44 void *shadow; 45 46 /* If the memory range crosses a page boundary, stop there. */ 47 if (page == last_page) 48 first_n = n; 49 else 50 first_n = page + PAGE_SIZE - addr; 51 52 shadow = kmemcheck_shadow_lookup(addr); 53 if (shadow) 54 memset(shadow, status, first_n); 55 56 addr += first_n; 57 n -= first_n; 58 59 /* Do full-page memset()s. */ 60 while (n >= PAGE_SIZE) { 61 shadow = kmemcheck_shadow_lookup(addr); 62 if (shadow) 63 memset(shadow, status, PAGE_SIZE); 64 65 addr += PAGE_SIZE; 66 n -= PAGE_SIZE; 67 } 68 69 /* Do the remaining page, if any. */ 70 if (n > 0) { 71 shadow = kmemcheck_shadow_lookup(addr); 72 if (shadow) 73 memset(shadow, status, n); 74 } 75} 76 77void kmemcheck_mark_unallocated(void *address, unsigned int n) 78{ 79 mark_shadow(address, n, KMEMCHECK_SHADOW_UNALLOCATED); 80} 81 82void kmemcheck_mark_uninitialized(void *address, unsigned int n) 83{ 84 mark_shadow(address, n, KMEMCHECK_SHADOW_UNINITIALIZED); 85} 86 87/* 88 * Fill the shadow memory of the given address such that the memory at that 89 * address is marked as being initialized. 90 */ 91void kmemcheck_mark_initialized(void *address, unsigned int n) 92{ 93 mark_shadow(address, n, KMEMCHECK_SHADOW_INITIALIZED); 94} 95EXPORT_SYMBOL_GPL(kmemcheck_mark_initialized); 96 97void kmemcheck_mark_freed(void *address, unsigned int n) 98{ 99 mark_shadow(address, n, KMEMCHECK_SHADOW_FREED); 100} 101 102void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n) 103{ 104 unsigned int i; 105 106 for (i = 0; i < n; ++i) 107 kmemcheck_mark_unallocated(page_address(&p[i]), PAGE_SIZE); 108} 109 110void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n) 111{ 112 unsigned int i; 113 114 for (i = 0; i < n; ++i) 115 kmemcheck_mark_uninitialized(page_address(&p[i]), PAGE_SIZE); 116} 117 118void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n) 119{ 120 unsigned int i; 121 122 for (i = 0; i < n; ++i) 123 kmemcheck_mark_initialized(page_address(&p[i]), PAGE_SIZE); 124} 125 126enum kmemcheck_shadow kmemcheck_shadow_test(void *shadow, unsigned int size) 127{ 128#ifdef CONFIG_KMEMCHECK_PARTIAL_OK 129 uint8_t *x; 130 unsigned int i; 131 132 x = shadow; 133 134 /* 135 * Make sure _some_ bytes are initialized. Gcc frequently generates 136 * code to access neighboring bytes. 137 */ 138 for (i = 0; i < size; ++i) { 139 if (x[i] == KMEMCHECK_SHADOW_INITIALIZED) 140 return x[i]; 141 } 142 143 return x[0]; 144#else 145 return kmemcheck_shadow_test_all(shadow, size); 146#endif 147} 148 149enum kmemcheck_shadow kmemcheck_shadow_test_all(void *shadow, unsigned int size) 150{ 151 uint8_t *x; 152 unsigned int i; 153 154 x = shadow; 155 156 /* All bytes must be initialized. */ 157 for (i = 0; i < size; ++i) { 158 if (x[i] != KMEMCHECK_SHADOW_INITIALIZED) 159 return x[i]; 160 } 161 162 return x[0]; 163} 164 165void kmemcheck_shadow_set(void *shadow, unsigned int size) 166{ 167 uint8_t *x; 168 unsigned int i; 169 170 x = shadow; 171 for (i = 0; i < size; ++i) 172 x[i] = KMEMCHECK_SHADOW_INITIALIZED; 173} 174