Thread (55 messages) 55 messages, 7 authors, 2018-09-19

[PATCH v6 14/18] khwasan: add hooks implementation

From: Andrey Konovalov <hidden>
Date: 2018-09-19 11:54:27
Also in: linux-doc, linux-kbuild, linux-mm, lkml

On Wed, Sep 12, 2018 at 8:30 PM, Dmitry Vyukov [off-list ref] wrote:
On Wed, Aug 29, 2018 at 1:35 PM, Andrey Konovalov [off-list ref] wrote:
quoted
 void kasan_unpoison_shadow(const void *address, size_t size)
 {
-       kasan_poison_shadow(address, size, 0);
+       u8 tag = get_tag(address);
+
+       /* Perform shadow offset calculation based on untagged address */
The comment is not super-useful. It would be more useful to say why we
need to do this.
Most callers explicitly untag pointer passed to this function, for
some it's unclear if the pointer contains tag or not.
For example, __hwasan_tag_memory -- what does it accept? Tagged or untagged?
There are some callers that pass tagged pointers to this functions,
e.g. ksize or kasan_unpoison_object_data. I'll expand the comment.
quoted
+       address = reset_tag(address);
+
+       kasan_poison_shadow(address, size, tag);

        if (size & KASAN_SHADOW_MASK) {
                u8 *shadow = (u8 *)kasan_mem_to_shadow(address + size);
-               *shadow = size & KASAN_SHADOW_MASK;
+
+               if (IS_ENABLED(CONFIG_KASAN_HW))
+                       *shadow = tag;
+               else
+                       *shadow = size & KASAN_SHADOW_MASK;
        }
 }

It seems that this function is just different for kasan and khwasan.
Currently for kasan we have:

kasan_poison_shadow(address, size, tag);
if (size & KASAN_SHADOW_MASK) {
        u8 *shadow = (u8 *)kasan_mem_to_shadow(address + size);
        *shadow = size & KASAN_SHADOW_MASK;
}

But what we want to say for khwasan is:

kasan_poison_shadow(address, round_up(size, KASAN_SHADOW_SCALE_SIZE),
get_tag(address));

Not sure if we want to keep a common implementation or just have
separate implementations...
As per offline discussion leaving as is.

quoted
 void kasan_free_pages(struct page *page, unsigned int order)
@@ -235,6 +248,7 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size,
                        slab_flags_t *flags)
 {
        unsigned int orig_size = *size;
+       unsigned int redzone_size = 0;
This variable seems to be always initialized below. We don't general
initialize local variables in this case.
Will fix in v7.
quoted
 void check_memory_region(unsigned long addr, size_t size, bool write,
                                unsigned long ret_ip)
 {
+       u8 tag;
+       u8 *shadow_first, *shadow_last, *shadow;
+       void *untagged_addr;
+
+       tag = get_tag((const void *)addr);
+
+       /* Ignore accesses for pointers tagged with 0xff (native kernel
/* on a separate line
Will fix in v7.
quoted
+        * pointer tag) to suppress false positives caused by kmap.
+        *
+        * Some kernel code was written to account for archs that don't keep
+        * high memory mapped all the time, but rather map and unmap particular
+        * pages when needed. Instead of storing a pointer to the kernel memory,
+        * this code saves the address of the page structure and offset within
+        * that page for later use. Those pages are then mapped and unmapped
+        * with kmap/kunmap when necessary and virt_to_page is used to get the
+        * virtual address of the page. For arm64 (that keeps the high memory
+        * mapped all the time), kmap is turned into a page_address call.
+
+        * The issue is that with use of the page_address + virt_to_page
+        * sequence the top byte value of the original pointer gets lost (gets
+        * set to KHWASAN_TAG_KERNEL (0xFF).
Missed closing bracket.
Will fix in v7.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help