1*1d171f95SJens Wiklander /* 2*1d171f95SJens Wiklander * Copyright (c) 2016, Linaro Limited 3*1d171f95SJens Wiklander * All rights reserved. 4*1d171f95SJens Wiklander * 5*1d171f95SJens Wiklander * Redistribution and use in source and binary forms, with or without 6*1d171f95SJens Wiklander * modification, are permitted provided that the following conditions are met: 7*1d171f95SJens Wiklander * 8*1d171f95SJens Wiklander * 1. Redistributions of source code must retain the above copyright notice, 9*1d171f95SJens Wiklander * this list of conditions and the following disclaimer. 10*1d171f95SJens Wiklander * 11*1d171f95SJens Wiklander * 2. Redistributions in binary form must reproduce the above copyright notice, 12*1d171f95SJens Wiklander * this list of conditions and the following disclaimer in the documentation 13*1d171f95SJens Wiklander * and/or other materials provided with the distribution. 14*1d171f95SJens Wiklander * 15*1d171f95SJens Wiklander * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16*1d171f95SJens Wiklander * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*1d171f95SJens Wiklander * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*1d171f95SJens Wiklander * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19*1d171f95SJens Wiklander * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*1d171f95SJens Wiklander * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*1d171f95SJens Wiklander * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22*1d171f95SJens Wiklander * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23*1d171f95SJens Wiklander * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24*1d171f95SJens Wiklander * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25*1d171f95SJens Wiklander * POSSIBILITY OF SUCH DAMAGE. 26*1d171f95SJens Wiklander */ 27*1d171f95SJens Wiklander 28*1d171f95SJens Wiklander #include <assert.h> 29*1d171f95SJens Wiklander #include <compiler.h> 30*1d171f95SJens Wiklander #include <kernel/panic.h> 31*1d171f95SJens Wiklander #include <kernel/asan.h> 32*1d171f95SJens Wiklander #include <string.h> 33*1d171f95SJens Wiklander #include <types_ext.h> 34*1d171f95SJens Wiklander #include <util.h> 35*1d171f95SJens Wiklander #include <trace.h> 36*1d171f95SJens Wiklander 37*1d171f95SJens Wiklander struct asan_source_location { 38*1d171f95SJens Wiklander const char *file_name; 39*1d171f95SJens Wiklander int line_no; 40*1d171f95SJens Wiklander int column_no; 41*1d171f95SJens Wiklander }; 42*1d171f95SJens Wiklander 43*1d171f95SJens Wiklander struct asan_global { 44*1d171f95SJens Wiklander uintptr_t beg; 45*1d171f95SJens Wiklander uintptr_t size; 46*1d171f95SJens Wiklander uintptr_t size_with_redzone; 47*1d171f95SJens Wiklander const char *name; 48*1d171f95SJens Wiklander const char *module_name; 49*1d171f95SJens Wiklander uintptr_t has_dynamic_init; 50*1d171f95SJens Wiklander struct asan_source_location *location; 51*1d171f95SJens Wiklander }; 52*1d171f95SJens Wiklander 53*1d171f95SJens Wiklander static vaddr_t asan_va_base; 54*1d171f95SJens Wiklander static size_t asan_va_size; 55*1d171f95SJens Wiklander static bool asan_active; 56*1d171f95SJens Wiklander 57*1d171f95SJens Wiklander static int8_t *va_to_shadow(void *va) 58*1d171f95SJens Wiklander { 59*1d171f95SJens Wiklander vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) + CFG_ASAN_SHADOW_OFFSET; 60*1d171f95SJens Wiklander 61*1d171f95SJens Wiklander return (int8_t *)sa; 62*1d171f95SJens Wiklander } 63*1d171f95SJens Wiklander 64*1d171f95SJens Wiklander static size_t va_range_to_shadow_size(void *begin, void *end) 65*1d171f95SJens Wiklander { 66*1d171f95SJens Wiklander return ((vaddr_t)end - (vaddr_t)begin) / ASAN_BLOCK_SIZE; 67*1d171f95SJens Wiklander } 68*1d171f95SJens Wiklander 69*1d171f95SJens Wiklander static bool va_range_inside_shadow(void *begin, void *end) 70*1d171f95SJens Wiklander { 71*1d171f95SJens Wiklander vaddr_t b = (vaddr_t)begin; 72*1d171f95SJens Wiklander vaddr_t e = (vaddr_t)end; 73*1d171f95SJens Wiklander 74*1d171f95SJens Wiklander if (b >= e) 75*1d171f95SJens Wiklander return false; 76*1d171f95SJens Wiklander return (b >= asan_va_base) && (e <= (asan_va_base + asan_va_size)); 77*1d171f95SJens Wiklander } 78*1d171f95SJens Wiklander 79*1d171f95SJens Wiklander static bool va_range_outside_shadow(void *begin, void *end) 80*1d171f95SJens Wiklander { 81*1d171f95SJens Wiklander vaddr_t b = (vaddr_t)begin; 82*1d171f95SJens Wiklander vaddr_t e = (vaddr_t)end; 83*1d171f95SJens Wiklander 84*1d171f95SJens Wiklander if (b >= e) 85*1d171f95SJens Wiklander return false; 86*1d171f95SJens Wiklander return (e <= asan_va_base) || (b >= (asan_va_base + asan_va_size)); 87*1d171f95SJens Wiklander } 88*1d171f95SJens Wiklander 89*1d171f95SJens Wiklander static size_t va_misalignment(void *va) 90*1d171f95SJens Wiklander { 91*1d171f95SJens Wiklander return (vaddr_t)va & ASAN_BLOCK_MASK; 92*1d171f95SJens Wiklander } 93*1d171f95SJens Wiklander 94*1d171f95SJens Wiklander static bool va_is_well_aligned(void *va) 95*1d171f95SJens Wiklander { 96*1d171f95SJens Wiklander return !va_misalignment(va); 97*1d171f95SJens Wiklander } 98*1d171f95SJens Wiklander 99*1d171f95SJens Wiklander void asan_set_shadowed(void *begin, void *end) 100*1d171f95SJens Wiklander { 101*1d171f95SJens Wiklander vaddr_t b = (vaddr_t)begin; 102*1d171f95SJens Wiklander vaddr_t e = (vaddr_t)end; 103*1d171f95SJens Wiklander 104*1d171f95SJens Wiklander assert(!asan_va_base); 105*1d171f95SJens Wiklander assert(va_is_well_aligned(begin)); 106*1d171f95SJens Wiklander assert(va_is_well_aligned(end)); 107*1d171f95SJens Wiklander assert(b < e); 108*1d171f95SJens Wiklander 109*1d171f95SJens Wiklander asan_va_base = b; 110*1d171f95SJens Wiklander asan_va_size = e - b; 111*1d171f95SJens Wiklander } 112*1d171f95SJens Wiklander 113*1d171f95SJens Wiklander void asan_tag_no_access(void *begin, void *end) 114*1d171f95SJens Wiklander { 115*1d171f95SJens Wiklander assert(va_is_well_aligned(begin)); 116*1d171f95SJens Wiklander assert(va_is_well_aligned(end)); 117*1d171f95SJens Wiklander assert(va_range_inside_shadow(begin, end)); 118*1d171f95SJens Wiklander 119*1d171f95SJens Wiklander memset(va_to_shadow(begin), ASAN_DATA_RED_ZONE, 120*1d171f95SJens Wiklander va_range_to_shadow_size(begin, end)); 121*1d171f95SJens Wiklander } 122*1d171f95SJens Wiklander 123*1d171f95SJens Wiklander void asan_tag_access(void *begin, void *end) 124*1d171f95SJens Wiklander { 125*1d171f95SJens Wiklander if (!asan_va_base) 126*1d171f95SJens Wiklander return; 127*1d171f95SJens Wiklander 128*1d171f95SJens Wiklander assert(va_range_inside_shadow(begin, end)); 129*1d171f95SJens Wiklander assert(va_is_well_aligned(begin)); 130*1d171f95SJens Wiklander 131*1d171f95SJens Wiklander memset(va_to_shadow(begin), 0, va_range_to_shadow_size(begin, end)); 132*1d171f95SJens Wiklander if (!va_is_well_aligned(end)) 133*1d171f95SJens Wiklander *va_to_shadow(end) = ASAN_BLOCK_SIZE - va_misalignment(end); 134*1d171f95SJens Wiklander } 135*1d171f95SJens Wiklander 136*1d171f95SJens Wiklander void asan_tag_heap_free(void *begin, void *end) 137*1d171f95SJens Wiklander { 138*1d171f95SJens Wiklander if (!asan_va_base) 139*1d171f95SJens Wiklander return; 140*1d171f95SJens Wiklander 141*1d171f95SJens Wiklander assert(va_range_inside_shadow(begin, end)); 142*1d171f95SJens Wiklander assert(va_is_well_aligned(begin)); 143*1d171f95SJens Wiklander assert(va_is_well_aligned(end)); 144*1d171f95SJens Wiklander 145*1d171f95SJens Wiklander memset(va_to_shadow(begin), ASAN_HEAP_RED_ZONE, 146*1d171f95SJens Wiklander va_range_to_shadow_size(begin, end)); 147*1d171f95SJens Wiklander } 148*1d171f95SJens Wiklander 149*1d171f95SJens Wiklander void asan_start(void) 150*1d171f95SJens Wiklander { 151*1d171f95SJens Wiklander assert(asan_va_base && !asan_active); 152*1d171f95SJens Wiklander asan_active = true; 153*1d171f95SJens Wiklander } 154*1d171f95SJens Wiklander 155*1d171f95SJens Wiklander static void check_access(vaddr_t addr, size_t size) 156*1d171f95SJens Wiklander { 157*1d171f95SJens Wiklander void *begin = (void *)addr; 158*1d171f95SJens Wiklander void *end = (void *)(addr + size); 159*1d171f95SJens Wiklander int8_t *a; 160*1d171f95SJens Wiklander int8_t *e; 161*1d171f95SJens Wiklander 162*1d171f95SJens Wiklander if (!asan_active || !size) 163*1d171f95SJens Wiklander return; 164*1d171f95SJens Wiklander if (va_range_outside_shadow(begin, end)) 165*1d171f95SJens Wiklander return; 166*1d171f95SJens Wiklander /* 167*1d171f95SJens Wiklander * If it isn't outside it has to be completely inside or there's a 168*1d171f95SJens Wiklander * problem. 169*1d171f95SJens Wiklander */ 170*1d171f95SJens Wiklander if (!va_range_inside_shadow(begin, end)) 171*1d171f95SJens Wiklander panic(); 172*1d171f95SJens Wiklander 173*1d171f95SJens Wiklander e = va_to_shadow(end); 174*1d171f95SJens Wiklander for (a = va_to_shadow(begin); a != e; a++) 175*1d171f95SJens Wiklander if (*a < 0) 176*1d171f95SJens Wiklander panic(); 177*1d171f95SJens Wiklander 178*1d171f95SJens Wiklander if (!va_is_well_aligned(end) && 179*1d171f95SJens Wiklander va_misalignment(end) > (size_t)(*e - ASAN_BLOCK_SIZE)) 180*1d171f95SJens Wiklander panic(); 181*1d171f95SJens Wiklander } 182*1d171f95SJens Wiklander 183*1d171f95SJens Wiklander static void check_load(vaddr_t addr, size_t size) 184*1d171f95SJens Wiklander { 185*1d171f95SJens Wiklander check_access(addr, size); 186*1d171f95SJens Wiklander } 187*1d171f95SJens Wiklander 188*1d171f95SJens Wiklander static void check_store(vaddr_t addr, size_t size) 189*1d171f95SJens Wiklander { 190*1d171f95SJens Wiklander check_access(addr, size); 191*1d171f95SJens Wiklander } 192*1d171f95SJens Wiklander 193*1d171f95SJens Wiklander static void __noreturn report_load(vaddr_t addr __unused, size_t size __unused) 194*1d171f95SJens Wiklander { 195*1d171f95SJens Wiklander panic(); 196*1d171f95SJens Wiklander } 197*1d171f95SJens Wiklander 198*1d171f95SJens Wiklander static void __noreturn report_store(vaddr_t addr __unused, size_t size __unused) 199*1d171f95SJens Wiklander { 200*1d171f95SJens Wiklander panic(); 201*1d171f95SJens Wiklander } 202*1d171f95SJens Wiklander 203*1d171f95SJens Wiklander 204*1d171f95SJens Wiklander 205*1d171f95SJens Wiklander #define DEFINE_ASAN_FUNC(type, size) \ 206*1d171f95SJens Wiklander void __asan_##type##size(vaddr_t addr); \ 207*1d171f95SJens Wiklander void __asan_##type##size(vaddr_t addr) \ 208*1d171f95SJens Wiklander { check_##type(addr, size); } \ 209*1d171f95SJens Wiklander void __asan_##type##size##_noabort(vaddr_t addr); \ 210*1d171f95SJens Wiklander void __asan_##type##size##_noabort(vaddr_t addr) \ 211*1d171f95SJens Wiklander { check_##type(addr, size); } \ 212*1d171f95SJens Wiklander void __asan_report_##type##size##_noabort(vaddr_t addr);\ 213*1d171f95SJens Wiklander void __noreturn __asan_report_##type##size##_noabort(vaddr_t addr) \ 214*1d171f95SJens Wiklander { report_##type(addr, size); } 215*1d171f95SJens Wiklander 216*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 1) 217*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 2) 218*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 4) 219*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 8) 220*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 16) 221*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 1) 222*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 2) 223*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 4) 224*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 8) 225*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 16) 226*1d171f95SJens Wiklander 227*1d171f95SJens Wiklander void __asan_loadN_noabort(vaddr_t addr, size_t size); 228*1d171f95SJens Wiklander void __asan_loadN_noabort(vaddr_t addr, size_t size) 229*1d171f95SJens Wiklander { 230*1d171f95SJens Wiklander check_load(addr, size); 231*1d171f95SJens Wiklander } 232*1d171f95SJens Wiklander 233*1d171f95SJens Wiklander void __asan_storeN_noabort(vaddr_t addr, size_t size); 234*1d171f95SJens Wiklander void __asan_storeN_noabort(vaddr_t addr, size_t size) 235*1d171f95SJens Wiklander { 236*1d171f95SJens Wiklander check_store(addr, size); 237*1d171f95SJens Wiklander } 238*1d171f95SJens Wiklander 239*1d171f95SJens Wiklander void __asan_report_load_n_noabort(vaddr_t addr, size_t size); 240*1d171f95SJens Wiklander void __noreturn __asan_report_load_n_noabort(vaddr_t addr, size_t size) 241*1d171f95SJens Wiklander { 242*1d171f95SJens Wiklander report_load(addr, size); 243*1d171f95SJens Wiklander } 244*1d171f95SJens Wiklander 245*1d171f95SJens Wiklander void __asan_report_store_n_noabort(vaddr_t addr, size_t size); 246*1d171f95SJens Wiklander void __noreturn __asan_report_store_n_noabort(vaddr_t addr, size_t size) 247*1d171f95SJens Wiklander { 248*1d171f95SJens Wiklander report_store(addr, size); 249*1d171f95SJens Wiklander } 250*1d171f95SJens Wiklander 251*1d171f95SJens Wiklander void __asan_handle_no_return(void); 252*1d171f95SJens Wiklander void __noreturn __asan_handle_no_return(void) 253*1d171f95SJens Wiklander { 254*1d171f95SJens Wiklander panic(); 255*1d171f95SJens Wiklander } 256*1d171f95SJens Wiklander 257*1d171f95SJens Wiklander void __asan_register_globals(struct asan_global *globals, size_t size); 258*1d171f95SJens Wiklander void __asan_register_globals(struct asan_global *globals, size_t size) 259*1d171f95SJens Wiklander { 260*1d171f95SJens Wiklander size_t n; 261*1d171f95SJens Wiklander 262*1d171f95SJens Wiklander for (n = 0; n < size; n++) 263*1d171f95SJens Wiklander asan_tag_access((void *)globals[n].beg, 264*1d171f95SJens Wiklander (void *)(globals[n].beg + globals[n].size)); 265*1d171f95SJens Wiklander } 266*1d171f95SJens Wiklander 267*1d171f95SJens Wiklander void __asan_unregister_globals(struct asan_global *globals, size_t size); 268*1d171f95SJens Wiklander void __asan_unregister_globals(struct asan_global *globals __unused, 269*1d171f95SJens Wiklander size_t size __unused) 270*1d171f95SJens Wiklander { 271*1d171f95SJens Wiklander } 272