LCOV - code coverage report
Current view: top level - mm/kasan - generic.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 77 141 54.6 %
Date: 2021-04-22 12:43:58 Functions: 7 31 22.6 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * This file contains core generic KASAN code.
       4             :  *
       5             :  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
       6             :  * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
       7             :  *
       8             :  * Some code borrowed from https://github.com/xairy/kasan-prototype by
       9             :  *        Andrey Konovalov <andreyknvl@gmail.com>
      10             :  */
      11             : 
      12             : #include <linux/export.h>
      13             : #include <linux/interrupt.h>
      14             : #include <linux/init.h>
      15             : #include <linux/kasan.h>
      16             : #include <linux/kernel.h>
      17             : #include <linux/kfence.h>
      18             : #include <linux/kmemleak.h>
      19             : #include <linux/linkage.h>
      20             : #include <linux/memblock.h>
      21             : #include <linux/memory.h>
      22             : #include <linux/mm.h>
      23             : #include <linux/module.h>
      24             : #include <linux/printk.h>
      25             : #include <linux/sched.h>
      26             : #include <linux/sched/task_stack.h>
      27             : #include <linux/slab.h>
      28             : #include <linux/stacktrace.h>
      29             : #include <linux/string.h>
      30             : #include <linux/types.h>
      31             : #include <linux/vmalloc.h>
      32             : #include <linux/bug.h>
      33             : 
      34             : #include "kasan.h"
      35             : #include "../slab.h"
      36             : 
      37             : /*
      38             :  * All functions below always inlined so compiler could
      39             :  * perform better optimizations in each of __asan_loadX/__assn_storeX
      40             :  * depending on memory access size X.
      41             :  */
      42             : 
      43           0 : static __always_inline bool memory_is_poisoned_1(unsigned long addr)
      44             : {
      45           0 :         s8 shadow_value = *(s8 *)kasan_mem_to_shadow((void *)addr);
      46             : 
      47           0 :         if (unlikely(shadow_value)) {
      48           0 :                 s8 last_accessible_byte = addr & KASAN_GRANULE_MASK;
      49           0 :                 return unlikely(last_accessible_byte >= shadow_value);
      50             :         }
      51             : 
      52             :         return false;
      53             : }
      54             : 
      55           0 : static __always_inline bool memory_is_poisoned_2_4_8(unsigned long addr,
      56             :                                                 unsigned long size)
      57             : {
      58           0 :         u8 *shadow_addr = (u8 *)kasan_mem_to_shadow((void *)addr);
      59             : 
      60             :         /*
      61             :          * Access crosses 8(shadow size)-byte boundary. Such access maps
      62             :          * into 2 shadow bytes, so we need to check them both.
      63             :          */
      64           0 :         if (unlikely(((addr + size - 1) & KASAN_GRANULE_MASK) < size - 1))
      65           0 :                 return *shadow_addr || memory_is_poisoned_1(addr + size - 1);
      66             : 
      67           0 :         return memory_is_poisoned_1(addr + size - 1);
      68             : }
      69             : 
      70           0 : static __always_inline bool memory_is_poisoned_16(unsigned long addr)
      71             : {
      72           0 :         u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr);
      73             : 
      74             :         /* Unaligned 16-bytes access maps into 3 shadow bytes. */
      75           0 :         if (unlikely(!IS_ALIGNED(addr, KASAN_GRANULE_SIZE)))
      76           0 :                 return *shadow_addr || memory_is_poisoned_1(addr + 15);
      77             : 
      78           0 :         return *shadow_addr;
      79             : }
      80             : 
      81   328584864 : static __always_inline unsigned long bytes_is_nonzero(const u8 *start,
      82             :                                         size_t size)
      83             : {
      84   688492729 :         while (size) {
      85   373392651 :                 if (unlikely(*start))
      86    13484901 :                         return (unsigned long)start;
      87   359907750 :                 start++;
      88   359907750 :                 size--;
      89             :         }
      90             : 
      91             :         return 0;
      92             : }
      93             : 
      94   327299663 : static __always_inline unsigned long memory_is_nonzero(const void *start,
      95             :                                                 const void *end)
      96             : {
      97   327299663 :         unsigned int words;
      98   327299663 :         unsigned long ret;
      99   327299663 :         unsigned int prefix = (unsigned long)start % 8;
     100             : 
     101   327299663 :         if (end - start <= 16)
     102   325937290 :                 return bytes_is_nonzero(start, end - start);
     103             : 
     104     1362373 :         if (prefix) {
     105     1285320 :                 prefix = 8 - prefix;
     106     1285320 :                 ret = bytes_is_nonzero(start, prefix);
     107     1285320 :                 if (unlikely(ret))
     108             :                         return ret;
     109     1285316 :                 start += prefix;
     110             :         }
     111             : 
     112     1362369 :         words = (end - start) / 8;
     113    11630513 :         while (words) {
     114    10268259 :                 if (unlikely(*(u64 *)start))
     115             :                         return bytes_is_nonzero(start, 8);
     116    10268144 :                 start += 8;
     117    10268144 :                 words--;
     118             :         }
     119             : 
     120     1362254 :         return bytes_is_nonzero(start, (end - start) % 8);
     121             : }
     122             : 
     123   327299663 : static __always_inline bool memory_is_poisoned_n(unsigned long addr,
     124             :                                                 size_t size)
     125             : {
     126   327299663 :         unsigned long ret;
     127             : 
     128   654599326 :         ret = memory_is_nonzero(kasan_mem_to_shadow((void *)addr),
     129   327299663 :                         kasan_mem_to_shadow((void *)addr + size - 1) + 1);
     130             : 
     131   327299663 :         if (unlikely(ret)) {
     132    13491567 :                 unsigned long last_byte = addr + size - 1;
     133    13491567 :                 s8 *last_shadow = (s8 *)kasan_mem_to_shadow((void *)last_byte);
     134             : 
     135    13491567 :                 if (unlikely(ret != (unsigned long)last_shadow ||
     136             :                         ((long)(last_byte & KASAN_GRANULE_MASK) >= *last_shadow)))
     137        7807 :                         return true;
     138             :         }
     139             :         return false;
     140             : }
     141             : 
     142   327299663 : static __always_inline bool memory_is_poisoned(unsigned long addr, size_t size)
     143             : {
     144   327299663 :         if (__builtin_constant_p(size)) {
     145           0 :                 switch (size) {
     146             :                 case 1:
     147           0 :                         return memory_is_poisoned_1(addr);
     148             :                 case 2:
     149             :                 case 4:
     150             :                 case 8:
     151           0 :                         return memory_is_poisoned_2_4_8(addr, size);
     152             :                 case 16:
     153           0 :                         return memory_is_poisoned_16(addr);
     154             :                 default:
     155           0 :                         BUILD_BUG();
     156             :                 }
     157             :         }
     158             : 
     159   327299663 :         return memory_is_poisoned_n(addr, size);
     160             : }
     161             : 
     162   327307365 : static __always_inline bool check_region_inline(unsigned long addr,
     163             :                                                 size_t size, bool write,
     164             :                                                 unsigned long ret_ip)
     165             : {
     166   327307365 :         if (unlikely(size == 0))
     167             :                 return true;
     168             : 
     169   327299777 :         if (unlikely(addr + size < addr))
     170           0 :                 return !kasan_report(addr, size, write, ret_ip);
     171             : 
     172   327299777 :         if (unlikely((void *)addr <
     173             :                 kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) {
     174         114 :                 return !kasan_report(addr, size, write, ret_ip);
     175             :         }
     176             : 
     177   654599326 :         if (likely(!memory_is_poisoned(addr, size)))
     178             :                 return true;
     179             : 
     180        7807 :         return !kasan_report(addr, size, write, ret_ip);
     181             : }
     182             : 
     183   327307365 : bool kasan_check_range(unsigned long addr, size_t size, bool write,
     184             :                                         unsigned long ret_ip)
     185             : {
     186   327307365 :         return check_region_inline(addr, size, write, ret_ip);
     187             : }
     188             : 
     189     1280688 : bool kasan_byte_accessible(const void *addr)
     190             : {
     191     1280688 :         s8 shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(addr));
     192             : 
     193     1280688 :         return shadow_byte >= 0 && shadow_byte < KASAN_GRANULE_SIZE;
     194             : }
     195             : 
     196           0 : void kasan_cache_shrink(struct kmem_cache *cache)
     197             : {
     198           0 :         kasan_quarantine_remove_cache(cache);
     199           0 : }
     200             : 
     201           0 : void kasan_cache_shutdown(struct kmem_cache *cache)
     202             : {
     203           0 :         if (!__kmem_cache_empty(cache))
     204           0 :                 kasan_quarantine_remove_cache(cache);
     205           0 : }
     206             : 
     207       98764 : static void register_global(struct kasan_global *global)
     208             : {
     209       98764 :         size_t aligned_size = round_up(global->size, KASAN_GRANULE_SIZE);
     210             : 
     211       98764 :         kasan_unpoison(global->beg, global->size);
     212             : 
     213       98764 :         kasan_poison(global->beg + aligned_size,
     214       98764 :                      global->size_with_redzone - aligned_size,
     215             :                      KASAN_GLOBAL_REDZONE);
     216       98764 : }
     217             : 
     218         946 : void __asan_register_globals(struct kasan_global *globals, size_t size)
     219             : {
     220         946 :         int i;
     221             : 
     222       99710 :         for (i = 0; i < size; i++)
     223       98764 :                 register_global(&globals[i]);
     224         946 : }
     225             : EXPORT_SYMBOL(__asan_register_globals);
     226             : 
     227           0 : void __asan_unregister_globals(struct kasan_global *globals, size_t size)
     228             : {
     229           0 : }
     230             : EXPORT_SYMBOL(__asan_unregister_globals);
     231             : 
     232             : #define DEFINE_ASAN_LOAD_STORE(size)                                    \
     233             :         void __asan_load##size(unsigned long addr)                      \
     234             :         {                                                               \
     235             :                 check_region_inline(addr, size, false, _RET_IP_);       \
     236             :         }                                                               \
     237             :         EXPORT_SYMBOL(__asan_load##size);                               \
     238             :         __alias(__asan_load##size)                                      \
     239             :         void __asan_load##size##_noabort(unsigned long);                \
     240             :         EXPORT_SYMBOL(__asan_load##size##_noabort);                     \
     241             :         void __asan_store##size(unsigned long addr)                     \
     242             :         {                                                               \
     243             :                 check_region_inline(addr, size, true, _RET_IP_);        \
     244             :         }                                                               \
     245             :         EXPORT_SYMBOL(__asan_store##size);                              \
     246             :         __alias(__asan_store##size)                                     \
     247             :         void __asan_store##size##_noabort(unsigned long);               \
     248             :         EXPORT_SYMBOL(__asan_store##size##_noabort)
     249             : 
     250           0 : DEFINE_ASAN_LOAD_STORE(1);
     251           0 : DEFINE_ASAN_LOAD_STORE(2);
     252           0 : DEFINE_ASAN_LOAD_STORE(4);
     253           0 : DEFINE_ASAN_LOAD_STORE(8);
     254           0 : DEFINE_ASAN_LOAD_STORE(16);
     255             : 
     256           0 : void __asan_loadN(unsigned long addr, size_t size)
     257             : {
     258           0 :         kasan_check_range(addr, size, false, _RET_IP_);
     259           0 : }
     260             : EXPORT_SYMBOL(__asan_loadN);
     261             : 
     262             : __alias(__asan_loadN)
     263             : void __asan_loadN_noabort(unsigned long, size_t);
     264             : EXPORT_SYMBOL(__asan_loadN_noabort);
     265             : 
     266           0 : void __asan_storeN(unsigned long addr, size_t size)
     267             : {
     268           0 :         kasan_check_range(addr, size, true, _RET_IP_);
     269           0 : }
     270             : EXPORT_SYMBOL(__asan_storeN);
     271             : 
     272             : __alias(__asan_storeN)
     273             : void __asan_storeN_noabort(unsigned long, size_t);
     274             : EXPORT_SYMBOL(__asan_storeN_noabort);
     275             : 
     276             : /* to shut up compiler complaints */
     277        5082 : void __asan_handle_no_return(void) {}
     278             : EXPORT_SYMBOL(__asan_handle_no_return);
     279             : 
     280             : /* Emitted by compiler to poison alloca()ed objects. */
     281           0 : void __asan_alloca_poison(unsigned long addr, size_t size)
     282             : {
     283           0 :         size_t rounded_up_size = round_up(size, KASAN_GRANULE_SIZE);
     284           0 :         size_t padding_size = round_up(size, KASAN_ALLOCA_REDZONE_SIZE) -
     285             :                         rounded_up_size;
     286           0 :         size_t rounded_down_size = round_down(size, KASAN_GRANULE_SIZE);
     287             : 
     288           0 :         const void *left_redzone = (const void *)(addr -
     289             :                         KASAN_ALLOCA_REDZONE_SIZE);
     290           0 :         const void *right_redzone = (const void *)(addr + rounded_up_size);
     291             : 
     292           0 :         WARN_ON(!IS_ALIGNED(addr, KASAN_ALLOCA_REDZONE_SIZE));
     293             : 
     294           0 :         kasan_unpoison((const void *)(addr + rounded_down_size),
     295             :                         size - rounded_down_size);
     296           0 :         kasan_poison(left_redzone, KASAN_ALLOCA_REDZONE_SIZE,
     297             :                      KASAN_ALLOCA_LEFT);
     298           0 :         kasan_poison(right_redzone, padding_size + KASAN_ALLOCA_REDZONE_SIZE,
     299             :                      KASAN_ALLOCA_RIGHT);
     300           0 : }
     301             : EXPORT_SYMBOL(__asan_alloca_poison);
     302             : 
     303             : /* Emitted by compiler to unpoison alloca()ed areas when the stack unwinds. */
     304           0 : void __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom)
     305             : {
     306           0 :         if (unlikely(!stack_top || stack_top > stack_bottom))
     307             :                 return;
     308             : 
     309           0 :         kasan_unpoison(stack_top, stack_bottom - stack_top);
     310             : }
     311             : EXPORT_SYMBOL(__asan_allocas_unpoison);
     312             : 
     313             : /* Emitted by the compiler to [un]poison local variables. */
     314             : #define DEFINE_ASAN_SET_SHADOW(byte) \
     315             :         void __asan_set_shadow_##byte(const void *addr, size_t size)    \
     316             :         {                                                               \
     317             :                 __memset((void *)addr, 0x##byte, size);                 \
     318             :         }                                                               \
     319             :         EXPORT_SYMBOL(__asan_set_shadow_##byte)
     320             : 
     321           0 : DEFINE_ASAN_SET_SHADOW(00);
     322           0 : DEFINE_ASAN_SET_SHADOW(f1);
     323           0 : DEFINE_ASAN_SET_SHADOW(f2);
     324           0 : DEFINE_ASAN_SET_SHADOW(f3);
     325           0 : DEFINE_ASAN_SET_SHADOW(f5);
     326           0 : DEFINE_ASAN_SET_SHADOW(f8);
     327             : 
     328      736162 : void kasan_record_aux_stack(void *addr)
     329             : {
     330      736162 :         struct page *page = kasan_addr_to_page(addr);
     331      736388 :         struct kmem_cache *cache;
     332      736388 :         struct kasan_alloc_meta *alloc_meta;
     333      736388 :         void *object;
     334             : 
     335     1472174 :         if (is_kfence_address(addr) || !(page && PageSlab(page)))
     336             :                 return;
     337             : 
     338      729699 :         cache = page->slab_cache;
     339      729699 :         object = nearest_obj(cache, page, addr);
     340      729583 :         alloc_meta = kasan_get_alloc_meta(cache, object);
     341      729764 :         if (!alloc_meta)
     342             :                 return;
     343             : 
     344      729764 :         alloc_meta->aux_stack[1] = alloc_meta->aux_stack[0];
     345      729764 :         alloc_meta->aux_stack[0] = kasan_save_stack(GFP_NOWAIT);
     346             : }
     347             : 
     348     1269673 : void kasan_set_free_info(struct kmem_cache *cache,
     349             :                                 void *object, u8 tag)
     350             : {
     351     1269673 :         struct kasan_free_meta *free_meta;
     352             : 
     353     1269673 :         free_meta = kasan_get_free_meta(cache, object);
     354     1269509 :         if (!free_meta)
     355             :                 return;
     356             : 
     357     1269509 :         kasan_set_track(&free_meta->free_track, GFP_NOWAIT);
     358             :         /* The object was freed and has free track set. */
     359     1271402 :         *(u8 *)kasan_mem_to_shadow(object) = KASAN_KMALLOC_FREETRACK;
     360             : }
     361             : 
     362           0 : struct kasan_track *kasan_get_free_track(struct kmem_cache *cache,
     363             :                                 void *object, u8 tag)
     364             : {
     365           0 :         if (*(u8 *)kasan_mem_to_shadow(object) != KASAN_KMALLOC_FREETRACK)
     366             :                 return NULL;
     367             :         /* Free meta must be present with KASAN_KMALLOC_FREETRACK. */
     368           0 :         return &kasan_get_free_meta(cache, object)->free_track;
     369             : }

Generated by: LCOV version 1.14