linux/arch/x86/mm/kmemcheck/shadow.c
<<
>>
Prefs
   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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.