1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * This file contains hardware tag-based KASAN specific error reporting code. |
4 | * |
5 | * Copyright (c) 2020 Google, Inc. |
6 | * Author: Andrey Konovalov <andreyknvl@google.com> |
7 | */ |
8 | |
9 | #include <linux/kasan.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/memory.h> |
12 | #include <linux/mm.h> |
13 | #include <linux/string.h> |
14 | #include <linux/types.h> |
15 | |
16 | #include "kasan.h" |
17 | |
18 | const void *kasan_find_first_bad_addr(const void *addr, size_t size) |
19 | { |
20 | /* |
21 | * Hardware Tag-Based KASAN only calls this function for normal memory |
22 | * accesses, and thus addr points precisely to the first bad address |
23 | * with an invalid (and present) memory tag. Therefore: |
24 | * 1. Return the address as is without walking memory tags. |
25 | * 2. Skip the addr_has_metadata check. |
26 | */ |
27 | return kasan_reset_tag(addr); |
28 | } |
29 | |
30 | size_t kasan_get_alloc_size(void *object, struct kmem_cache *cache) |
31 | { |
32 | size_t size = 0; |
33 | int i = 0; |
34 | u8 memory_tag; |
35 | |
36 | /* |
37 | * Skip the addr_has_metadata check, as this function only operates on |
38 | * slab memory, which must have metadata. |
39 | */ |
40 | |
41 | /* |
42 | * The loop below returns 0 for freed objects, for which KASAN cannot |
43 | * calculate the allocation size based on the metadata. |
44 | */ |
45 | while (size < cache->object_size) { |
46 | memory_tag = hw_get_mem_tag(object + i * KASAN_GRANULE_SIZE); |
47 | if (memory_tag != KASAN_TAG_INVALID) |
48 | size += KASAN_GRANULE_SIZE; |
49 | else |
50 | return size; |
51 | i++; |
52 | } |
53 | |
54 | return cache->object_size; |
55 | } |
56 | |
57 | void kasan_metadata_fetch_row(char *buffer, void *row) |
58 | { |
59 | int i; |
60 | |
61 | for (i = 0; i < META_BYTES_PER_ROW; i++) |
62 | buffer[i] = hw_get_mem_tag(row + i * KASAN_GRANULE_SIZE); |
63 | } |
64 | |
65 | void kasan_print_tags(u8 addr_tag, const void *addr) |
66 | { |
67 | u8 memory_tag = hw_get_mem_tag((void *)addr); |
68 | |
69 | pr_err("Pointer tag: [%02x], memory tag: [%02x]\n" , |
70 | addr_tag, memory_tag); |
71 | } |
72 | |