diff options
| -rw-r--r-- | mm/kasan/common.c | 116 | ||||
| -rw-r--r-- | mm/kasan/kasan.h | 8 | ||||
| -rw-r--r-- | mm/kasan/tags.c | 48 |
3 files changed, 153 insertions, 19 deletions
diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 7134e75447ff..27f0cae336c9 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c | |||
| @@ -140,6 +140,13 @@ void kasan_poison_shadow(const void *address, size_t size, u8 value) | |||
| 140 | { | 140 | { |
| 141 | void *shadow_start, *shadow_end; | 141 | void *shadow_start, *shadow_end; |
| 142 | 142 | ||
| 143 | /* | ||
| 144 | * Perform shadow offset calculation based on untagged address, as | ||
| 145 | * some of the callers (e.g. kasan_poison_object_data) pass tagged | ||
| 146 | * addresses to this function. | ||
| 147 | */ | ||
| 148 | address = reset_tag(address); | ||
| 149 | |||
| 143 | shadow_start = kasan_mem_to_shadow(address); | 150 | shadow_start = kasan_mem_to_shadow(address); |
| 144 | shadow_end = kasan_mem_to_shadow(address + size); | 151 | shadow_end = kasan_mem_to_shadow(address + size); |
| 145 | 152 | ||
| @@ -148,11 +155,24 @@ void kasan_poison_shadow(const void *address, size_t size, u8 value) | |||
| 148 | 155 | ||
| 149 | void kasan_unpoison_shadow(const void *address, size_t size) | 156 | void kasan_unpoison_shadow(const void *address, size_t size) |
| 150 | { | 157 | { |
| 151 | kasan_poison_shadow(address, size, 0); | 158 | u8 tag = get_tag(address); |
| 159 | |||
| 160 | /* | ||
| 161 | * Perform shadow offset calculation based on untagged address, as | ||
| 162 | * some of the callers (e.g. kasan_unpoison_object_data) pass tagged | ||
| 163 | * addresses to this function. | ||
| 164 | */ | ||
| 165 | address = reset_tag(address); | ||
| 166 | |||
| 167 | kasan_poison_shadow(address, size, tag); | ||
| 152 | 168 | ||
| 153 | if (size & KASAN_SHADOW_MASK) { | 169 | if (size & KASAN_SHADOW_MASK) { |
| 154 | u8 *shadow = (u8 *)kasan_mem_to_shadow(address + size); | 170 | u8 *shadow = (u8 *)kasan_mem_to_shadow(address + size); |
| 155 | *shadow = size & KASAN_SHADOW_MASK; | 171 | |
| 172 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | ||
| 173 | *shadow = tag; | ||
| 174 | else | ||
| 175 | *shadow = size & KASAN_SHADOW_MASK; | ||
| 156 | } | 176 | } |
| 157 | } | 177 | } |
| 158 | 178 | ||
| @@ -200,8 +220,9 @@ void kasan_unpoison_stack_above_sp_to(const void *watermark) | |||
| 200 | 220 | ||
| 201 | void kasan_alloc_pages(struct page *page, unsigned int order) | 221 | void kasan_alloc_pages(struct page *page, unsigned int order) |
| 202 | { | 222 | { |
| 203 | if (likely(!PageHighMem(page))) | 223 | if (unlikely(PageHighMem(page))) |
| 204 | kasan_unpoison_shadow(page_address(page), PAGE_SIZE << order); | 224 | return; |
| 225 | kasan_unpoison_shadow(page_address(page), PAGE_SIZE << order); | ||
| 205 | } | 226 | } |
| 206 | 227 | ||
| 207 | void kasan_free_pages(struct page *page, unsigned int order) | 228 | void kasan_free_pages(struct page *page, unsigned int order) |
| @@ -218,6 +239,9 @@ void kasan_free_pages(struct page *page, unsigned int order) | |||
| 218 | */ | 239 | */ |
| 219 | static inline unsigned int optimal_redzone(unsigned int object_size) | 240 | static inline unsigned int optimal_redzone(unsigned int object_size) |
| 220 | { | 241 | { |
| 242 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | ||
| 243 | return 0; | ||
| 244 | |||
| 221 | return | 245 | return |
| 222 | object_size <= 64 - 16 ? 16 : | 246 | object_size <= 64 - 16 ? 16 : |
| 223 | object_size <= 128 - 32 ? 32 : | 247 | object_size <= 128 - 32 ? 32 : |
| @@ -232,6 +256,7 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size, | |||
| 232 | slab_flags_t *flags) | 256 | slab_flags_t *flags) |
| 233 | { | 257 | { |
| 234 | unsigned int orig_size = *size; | 258 | unsigned int orig_size = *size; |
| 259 | unsigned int redzone_size; | ||
| 235 | int redzone_adjust; | 260 | int redzone_adjust; |
| 236 | 261 | ||
| 237 | /* Add alloc meta. */ | 262 | /* Add alloc meta. */ |
| @@ -239,20 +264,20 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size, | |||
| 239 | *size += sizeof(struct kasan_alloc_meta); | 264 | *size += sizeof(struct kasan_alloc_meta); |
| 240 | 265 | ||
| 241 | /* Add free meta. */ | 266 | /* Add free meta. */ |
| 242 | if (cache->flags & SLAB_TYPESAFE_BY_RCU || cache->ctor || | 267 | if (IS_ENABLED(CONFIG_KASAN_GENERIC) && |
| 243 | cache->object_size < sizeof(struct kasan_free_meta)) { | 268 | (cache->flags & SLAB_TYPESAFE_BY_RCU || cache->ctor || |
| 269 | cache->object_size < sizeof(struct kasan_free_meta))) { | ||
| 244 | cache->kasan_info.free_meta_offset = *size; | 270 | cache->kasan_info.free_meta_offset = *size; |
| 245 | *size += sizeof(struct kasan_free_meta); | 271 | *size += sizeof(struct kasan_free_meta); |
| 246 | } | 272 | } |
| 247 | redzone_adjust = optimal_redzone(cache->object_size) - | ||
| 248 | (*size - cache->object_size); | ||
| 249 | 273 | ||
| 274 | redzone_size = optimal_redzone(cache->object_size); | ||
| 275 | redzone_adjust = redzone_size - (*size - cache->object_size); | ||
| 250 | if (redzone_adjust > 0) | 276 | if (redzone_adjust > 0) |
| 251 | *size += redzone_adjust; | 277 | *size += redzone_adjust; |
| 252 | 278 | ||
| 253 | *size = min_t(unsigned int, KMALLOC_MAX_SIZE, | 279 | *size = min_t(unsigned int, KMALLOC_MAX_SIZE, |
| 254 | max(*size, cache->object_size + | 280 | max(*size, cache->object_size + redzone_size)); |
| 255 | optimal_redzone(cache->object_size))); | ||
| 256 | 281 | ||
| 257 | /* | 282 | /* |
| 258 | * If the metadata doesn't fit, don't enable KASAN at all. | 283 | * If the metadata doesn't fit, don't enable KASAN at all. |
| @@ -265,6 +290,8 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size, | |||
| 265 | return; | 290 | return; |
| 266 | } | 291 | } |
| 267 | 292 | ||
| 293 | cache->align = round_up(cache->align, KASAN_SHADOW_SCALE_SIZE); | ||
| 294 | |||
| 268 | *flags |= SLAB_KASAN; | 295 | *flags |= SLAB_KASAN; |
| 269 | } | 296 | } |
| 270 | 297 | ||
| @@ -309,6 +336,32 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object) | |||
| 309 | KASAN_KMALLOC_REDZONE); | 336 | KASAN_KMALLOC_REDZONE); |
| 310 | } | 337 | } |
| 311 | 338 | ||
| 339 | /* | ||
| 340 | * Since it's desirable to only call object contructors once during slab | ||
| 341 | * allocation, we preassign tags to all such objects. Also preassign tags for | ||
| 342 | * SLAB_TYPESAFE_BY_RCU slabs to avoid use-after-free reports. | ||
| 343 | * For SLAB allocator we can't preassign tags randomly since the freelist is | ||
| 344 | * stored as an array of indexes instead of a linked list. Assign tags based | ||
| 345 | * on objects indexes, so that objects that are next to each other get | ||
| 346 | * different tags. | ||
| 347 | * After a tag is assigned, the object always gets allocated with the same tag. | ||
| 348 | * The reason is that we can't change tags for objects with constructors on | ||
| 349 | * reallocation (even for non-SLAB_TYPESAFE_BY_RCU), because the constructor | ||
| 350 | * code can save the pointer to the object somewhere (e.g. in the object | ||
| 351 | * itself). Then if we retag it, the old saved pointer will become invalid. | ||
| 352 | */ | ||
| 353 | static u8 assign_tag(struct kmem_cache *cache, const void *object, bool new) | ||
| 354 | { | ||
| 355 | if (!cache->ctor && !(cache->flags & SLAB_TYPESAFE_BY_RCU)) | ||
| 356 | return new ? KASAN_TAG_KERNEL : random_tag(); | ||
| 357 | |||
| 358 | #ifdef CONFIG_SLAB | ||
| 359 | return (u8)obj_to_index(cache, virt_to_page(object), (void *)object); | ||
| 360 | #else | ||
| 361 | return new ? random_tag() : get_tag(object); | ||
| 362 | #endif | ||
| 363 | } | ||
| 364 | |||
| 312 | void *kasan_init_slab_obj(struct kmem_cache *cache, const void *object) | 365 | void *kasan_init_slab_obj(struct kmem_cache *cache, const void *object) |
| 313 | { | 366 | { |
| 314 | struct kasan_alloc_meta *alloc_info; | 367 | struct kasan_alloc_meta *alloc_info; |
| @@ -319,6 +372,9 @@ void *kasan_init_slab_obj(struct kmem_cache *cache, const void *object) | |||
| 319 | alloc_info = get_alloc_info(cache, object); | 372 | alloc_info = get_alloc_info(cache, object); |
| 320 | __memset(alloc_info, 0, sizeof(*alloc_info)); | 373 | __memset(alloc_info, 0, sizeof(*alloc_info)); |
| 321 | 374 | ||
| 375 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | ||
| 376 | object = set_tag(object, assign_tag(cache, object, true)); | ||
| 377 | |||
| 322 | return (void *)object; | 378 | return (void *)object; |
| 323 | } | 379 | } |
| 324 | 380 | ||
| @@ -327,15 +383,30 @@ void *kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags) | |||
| 327 | return kasan_kmalloc(cache, object, cache->object_size, flags); | 383 | return kasan_kmalloc(cache, object, cache->object_size, flags); |
| 328 | } | 384 | } |
| 329 | 385 | ||
| 386 | static inline bool shadow_invalid(u8 tag, s8 shadow_byte) | ||
| 387 | { | ||
| 388 | if (IS_ENABLED(CONFIG_KASAN_GENERIC)) | ||
| 389 | return shadow_byte < 0 || | ||
| 390 | shadow_byte >= KASAN_SHADOW_SCALE_SIZE; | ||
| 391 | else | ||
| 392 | return tag != (u8)shadow_byte; | ||
| 393 | } | ||
| 394 | |||
| 330 | static bool __kasan_slab_free(struct kmem_cache *cache, void *object, | 395 | static bool __kasan_slab_free(struct kmem_cache *cache, void *object, |
| 331 | unsigned long ip, bool quarantine) | 396 | unsigned long ip, bool quarantine) |
| 332 | { | 397 | { |
| 333 | s8 shadow_byte; | 398 | s8 shadow_byte; |
| 399 | u8 tag; | ||
| 400 | void *tagged_object; | ||
| 334 | unsigned long rounded_up_size; | 401 | unsigned long rounded_up_size; |
| 335 | 402 | ||
| 403 | tag = get_tag(object); | ||
| 404 | tagged_object = object; | ||
| 405 | object = reset_tag(object); | ||
| 406 | |||
| 336 | if (unlikely(nearest_obj(cache, virt_to_head_page(object), object) != | 407 | if (unlikely(nearest_obj(cache, virt_to_head_page(object), object) != |
| 337 | object)) { | 408 | object)) { |
| 338 | kasan_report_invalid_free(object, ip); | 409 | kasan_report_invalid_free(tagged_object, ip); |
| 339 | return true; | 410 | return true; |
| 340 | } | 411 | } |
| 341 | 412 | ||
| @@ -344,20 +415,22 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object, | |||
| 344 | return false; | 415 | return false; |
| 345 | 416 | ||
| 346 | shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object)); | 417 | shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object)); |
| 347 | if (shadow_byte < 0 || shadow_byte >= KASAN_SHADOW_SCALE_SIZE) { | 418 | if (shadow_invalid(tag, shadow_byte)) { |
| 348 | kasan_report_invalid_free(object, ip); | 419 | kasan_report_invalid_free(tagged_object, ip); |
| 349 | return true; | 420 | return true; |
| 350 | } | 421 | } |
| 351 | 422 | ||
| 352 | rounded_up_size = round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE); | 423 | rounded_up_size = round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE); |
| 353 | kasan_poison_shadow(object, rounded_up_size, KASAN_KMALLOC_FREE); | 424 | kasan_poison_shadow(object, rounded_up_size, KASAN_KMALLOC_FREE); |
| 354 | 425 | ||
| 355 | if (!quarantine || unlikely(!(cache->flags & SLAB_KASAN))) | 426 | if ((IS_ENABLED(CONFIG_KASAN_GENERIC) && !quarantine) || |
| 427 | unlikely(!(cache->flags & SLAB_KASAN))) | ||
| 356 | return false; | 428 | return false; |
| 357 | 429 | ||
| 358 | set_track(&get_alloc_info(cache, object)->free_track, GFP_NOWAIT); | 430 | set_track(&get_alloc_info(cache, object)->free_track, GFP_NOWAIT); |
| 359 | quarantine_put(get_free_info(cache, object), cache); | 431 | quarantine_put(get_free_info(cache, object), cache); |
| 360 | return true; | 432 | |
| 433 | return IS_ENABLED(CONFIG_KASAN_GENERIC); | ||
| 361 | } | 434 | } |
| 362 | 435 | ||
| 363 | bool kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip) | 436 | bool kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip) |
| @@ -370,6 +443,7 @@ void *kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, | |||
| 370 | { | 443 | { |
| 371 | unsigned long redzone_start; | 444 | unsigned long redzone_start; |
| 372 | unsigned long redzone_end; | 445 | unsigned long redzone_end; |
| 446 | u8 tag; | ||
| 373 | 447 | ||
| 374 | if (gfpflags_allow_blocking(flags)) | 448 | if (gfpflags_allow_blocking(flags)) |
| 375 | quarantine_reduce(); | 449 | quarantine_reduce(); |
| @@ -382,14 +456,18 @@ void *kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, | |||
| 382 | redzone_end = round_up((unsigned long)object + cache->object_size, | 456 | redzone_end = round_up((unsigned long)object + cache->object_size, |
| 383 | KASAN_SHADOW_SCALE_SIZE); | 457 | KASAN_SHADOW_SCALE_SIZE); |
| 384 | 458 | ||
| 385 | kasan_unpoison_shadow(object, size); | 459 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) |
| 460 | tag = assign_tag(cache, object, false); | ||
| 461 | |||
| 462 | /* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ | ||
| 463 | kasan_unpoison_shadow(set_tag(object, tag), size); | ||
| 386 | kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start, | 464 | kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start, |
| 387 | KASAN_KMALLOC_REDZONE); | 465 | KASAN_KMALLOC_REDZONE); |
| 388 | 466 | ||
| 389 | if (cache->flags & SLAB_KASAN) | 467 | if (cache->flags & SLAB_KASAN) |
| 390 | set_track(&get_alloc_info(cache, object)->alloc_track, flags); | 468 | set_track(&get_alloc_info(cache, object)->alloc_track, flags); |
| 391 | 469 | ||
| 392 | return (void *)object; | 470 | return set_tag(object, tag); |
| 393 | } | 471 | } |
| 394 | EXPORT_SYMBOL(kasan_kmalloc); | 472 | EXPORT_SYMBOL(kasan_kmalloc); |
| 395 | 473 | ||
| @@ -439,7 +517,7 @@ void kasan_poison_kfree(void *ptr, unsigned long ip) | |||
| 439 | page = virt_to_head_page(ptr); | 517 | page = virt_to_head_page(ptr); |
| 440 | 518 | ||
| 441 | if (unlikely(!PageSlab(page))) { | 519 | if (unlikely(!PageSlab(page))) { |
| 442 | if (ptr != page_address(page)) { | 520 | if (reset_tag(ptr) != page_address(page)) { |
| 443 | kasan_report_invalid_free(ptr, ip); | 521 | kasan_report_invalid_free(ptr, ip); |
| 444 | return; | 522 | return; |
| 445 | } | 523 | } |
| @@ -452,7 +530,7 @@ void kasan_poison_kfree(void *ptr, unsigned long ip) | |||
| 452 | 530 | ||
| 453 | void kasan_kfree_large(void *ptr, unsigned long ip) | 531 | void kasan_kfree_large(void *ptr, unsigned long ip) |
| 454 | { | 532 | { |
| 455 | if (ptr != page_address(virt_to_head_page(ptr))) | 533 | if (reset_tag(ptr) != page_address(virt_to_head_page(ptr))) |
| 456 | kasan_report_invalid_free(ptr, ip); | 534 | kasan_report_invalid_free(ptr, ip); |
| 457 | /* The object will be poisoned by page_alloc. */ | 535 | /* The object will be poisoned by page_alloc. */ |
| 458 | } | 536 | } |
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 82a23b23ff93..ea51b2d898ec 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h | |||
| @@ -12,10 +12,18 @@ | |||
| 12 | #define KASAN_TAG_INVALID 0xFE /* inaccessible memory tag */ | 12 | #define KASAN_TAG_INVALID 0xFE /* inaccessible memory tag */ |
| 13 | #define KASAN_TAG_MAX 0xFD /* maximum value for random tags */ | 13 | #define KASAN_TAG_MAX 0xFD /* maximum value for random tags */ |
| 14 | 14 | ||
| 15 | #ifdef CONFIG_KASAN_GENERIC | ||
| 15 | #define KASAN_FREE_PAGE 0xFF /* page was freed */ | 16 | #define KASAN_FREE_PAGE 0xFF /* page was freed */ |
| 16 | #define KASAN_PAGE_REDZONE 0xFE /* redzone for kmalloc_large allocations */ | 17 | #define KASAN_PAGE_REDZONE 0xFE /* redzone for kmalloc_large allocations */ |
| 17 | #define KASAN_KMALLOC_REDZONE 0xFC /* redzone inside slub object */ | 18 | #define KASAN_KMALLOC_REDZONE 0xFC /* redzone inside slub object */ |
| 18 | #define KASAN_KMALLOC_FREE 0xFB /* object was freed (kmem_cache_free/kfree) */ | 19 | #define KASAN_KMALLOC_FREE 0xFB /* object was freed (kmem_cache_free/kfree) */ |
| 20 | #else | ||
| 21 | #define KASAN_FREE_PAGE KASAN_TAG_INVALID | ||
| 22 | #define KASAN_PAGE_REDZONE KASAN_TAG_INVALID | ||
| 23 | #define KASAN_KMALLOC_REDZONE KASAN_TAG_INVALID | ||
| 24 | #define KASAN_KMALLOC_FREE KASAN_TAG_INVALID | ||
| 25 | #endif | ||
| 26 | |||
| 19 | #define KASAN_GLOBAL_REDZONE 0xFA /* redzone for global variable */ | 27 | #define KASAN_GLOBAL_REDZONE 0xFA /* redzone for global variable */ |
| 20 | 28 | ||
| 21 | /* | 29 | /* |
diff --git a/mm/kasan/tags.c b/mm/kasan/tags.c index 1c4e7ce2e6fe..1d1b79350e28 100644 --- a/mm/kasan/tags.c +++ b/mm/kasan/tags.c | |||
| @@ -78,15 +78,60 @@ void *kasan_reset_tag(const void *addr) | |||
| 78 | void check_memory_region(unsigned long addr, size_t size, bool write, | 78 | void check_memory_region(unsigned long addr, size_t size, bool write, |
| 79 | unsigned long ret_ip) | 79 | unsigned long ret_ip) |
| 80 | { | 80 | { |
| 81 | u8 tag; | ||
| 82 | u8 *shadow_first, *shadow_last, *shadow; | ||
| 83 | void *untagged_addr; | ||
| 84 | |||
| 85 | if (unlikely(size == 0)) | ||
| 86 | return; | ||
| 87 | |||
| 88 | tag = get_tag((const void *)addr); | ||
| 89 | |||
| 90 | /* | ||
| 91 | * Ignore accesses for pointers tagged with 0xff (native kernel | ||
| 92 | * pointer tag) to suppress false positives caused by kmap. | ||
| 93 | * | ||
| 94 | * Some kernel code was written to account for archs that don't keep | ||
| 95 | * high memory mapped all the time, but rather map and unmap particular | ||
| 96 | * pages when needed. Instead of storing a pointer to the kernel memory, | ||
| 97 | * this code saves the address of the page structure and offset within | ||
| 98 | * that page for later use. Those pages are then mapped and unmapped | ||
| 99 | * with kmap/kunmap when necessary and virt_to_page is used to get the | ||
| 100 | * virtual address of the page. For arm64 (that keeps the high memory | ||
| 101 | * mapped all the time), kmap is turned into a page_address call. | ||
| 102 | |||
| 103 | * The issue is that with use of the page_address + virt_to_page | ||
| 104 | * sequence the top byte value of the original pointer gets lost (gets | ||
| 105 | * set to KASAN_TAG_KERNEL (0xFF)). | ||
| 106 | */ | ||
| 107 | if (tag == KASAN_TAG_KERNEL) | ||
| 108 | return; | ||
| 109 | |||
| 110 | untagged_addr = reset_tag((const void *)addr); | ||
| 111 | if (unlikely(untagged_addr < | ||
| 112 | kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) { | ||
| 113 | kasan_report(addr, size, write, ret_ip); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | shadow_first = kasan_mem_to_shadow(untagged_addr); | ||
| 117 | shadow_last = kasan_mem_to_shadow(untagged_addr + size - 1); | ||
| 118 | for (shadow = shadow_first; shadow <= shadow_last; shadow++) { | ||
| 119 | if (*shadow != tag) { | ||
| 120 | kasan_report(addr, size, write, ret_ip); | ||
| 121 | return; | ||
| 122 | } | ||
| 123 | } | ||
| 81 | } | 124 | } |
| 82 | 125 | ||
| 83 | #define DEFINE_HWASAN_LOAD_STORE(size) \ | 126 | #define DEFINE_HWASAN_LOAD_STORE(size) \ |
| 84 | void __hwasan_load##size##_noabort(unsigned long addr) \ | 127 | void __hwasan_load##size##_noabort(unsigned long addr) \ |
| 85 | { \ | 128 | { \ |
| 129 | check_memory_region(addr, size, false, _RET_IP_); \ | ||
| 86 | } \ | 130 | } \ |
| 87 | EXPORT_SYMBOL(__hwasan_load##size##_noabort); \ | 131 | EXPORT_SYMBOL(__hwasan_load##size##_noabort); \ |
| 88 | void __hwasan_store##size##_noabort(unsigned long addr) \ | 132 | void __hwasan_store##size##_noabort(unsigned long addr) \ |
| 89 | { \ | 133 | { \ |
| 134 | check_memory_region(addr, size, true, _RET_IP_); \ | ||
| 90 | } \ | 135 | } \ |
| 91 | EXPORT_SYMBOL(__hwasan_store##size##_noabort) | 136 | EXPORT_SYMBOL(__hwasan_store##size##_noabort) |
| 92 | 137 | ||
| @@ -98,15 +143,18 @@ DEFINE_HWASAN_LOAD_STORE(16); | |||
| 98 | 143 | ||
| 99 | void __hwasan_loadN_noabort(unsigned long addr, unsigned long size) | 144 | void __hwasan_loadN_noabort(unsigned long addr, unsigned long size) |
| 100 | { | 145 | { |
| 146 | check_memory_region(addr, size, false, _RET_IP_); | ||
| 101 | } | 147 | } |
| 102 | EXPORT_SYMBOL(__hwasan_loadN_noabort); | 148 | EXPORT_SYMBOL(__hwasan_loadN_noabort); |
| 103 | 149 | ||
| 104 | void __hwasan_storeN_noabort(unsigned long addr, unsigned long size) | 150 | void __hwasan_storeN_noabort(unsigned long addr, unsigned long size) |
| 105 | { | 151 | { |
| 152 | check_memory_region(addr, size, true, _RET_IP_); | ||
| 106 | } | 153 | } |
| 107 | EXPORT_SYMBOL(__hwasan_storeN_noabort); | 154 | EXPORT_SYMBOL(__hwasan_storeN_noabort); |
| 108 | 155 | ||
| 109 | void __hwasan_tag_memory(unsigned long addr, u8 tag, unsigned long size) | 156 | void __hwasan_tag_memory(unsigned long addr, u8 tag, unsigned long size) |
| 110 | { | 157 | { |
| 158 | kasan_poison_shadow((void *)addr, size, tag); | ||
| 111 | } | 159 | } |
| 112 | EXPORT_SYMBOL(__hwasan_tag_memory); | 160 | EXPORT_SYMBOL(__hwasan_tag_memory); |
