162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * KMSAN runtime library. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017-2022 Google LLC 662306a36Sopenharmony_ci * Author: Alexander Potapenko <glider@google.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/page.h> 1162306a36Sopenharmony_ci#include <linux/compiler.h> 1262306a36Sopenharmony_ci#include <linux/export.h> 1362306a36Sopenharmony_ci#include <linux/highmem.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/kmsan_types.h> 1762306a36Sopenharmony_ci#include <linux/memory.h> 1862306a36Sopenharmony_ci#include <linux/mm.h> 1962306a36Sopenharmony_ci#include <linux/mm_types.h> 2062306a36Sopenharmony_ci#include <linux/mmzone.h> 2162306a36Sopenharmony_ci#include <linux/percpu-defs.h> 2262306a36Sopenharmony_ci#include <linux/preempt.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/stackdepot.h> 2562306a36Sopenharmony_ci#include <linux/stacktrace.h> 2662306a36Sopenharmony_ci#include <linux/types.h> 2762306a36Sopenharmony_ci#include <linux/vmalloc.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "../slab.h" 3062306a36Sopenharmony_ci#include "kmsan.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cibool kmsan_enabled __read_mostly; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Per-CPU KMSAN context to be used in interrupts, where current->kmsan is 3662306a36Sopenharmony_ci * unavaliable. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ciDEFINE_PER_CPU(struct kmsan_ctx, kmsan_percpu_ctx); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid kmsan_internal_task_create(struct task_struct *task) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct kmsan_ctx *ctx = &task->kmsan_ctx; 4362306a36Sopenharmony_ci struct thread_info *info = current_thread_info(); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci __memset(ctx, 0, sizeof(*ctx)); 4662306a36Sopenharmony_ci ctx->allow_reporting = true; 4762306a36Sopenharmony_ci kmsan_internal_unpoison_memory(info, sizeof(*info), false); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid kmsan_internal_poison_memory(void *address, size_t size, gfp_t flags, 5162306a36Sopenharmony_ci unsigned int poison_flags) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci u32 extra_bits = 5462306a36Sopenharmony_ci kmsan_extra_bits(/*depth*/ 0, poison_flags & KMSAN_POISON_FREE); 5562306a36Sopenharmony_ci bool checked = poison_flags & KMSAN_POISON_CHECK; 5662306a36Sopenharmony_ci depot_stack_handle_t handle; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci handle = kmsan_save_stack_with_flags(flags, extra_bits); 5962306a36Sopenharmony_ci kmsan_internal_set_shadow_origin(address, size, -1, handle, checked); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_civoid kmsan_internal_unpoison_memory(void *address, size_t size, bool checked) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci kmsan_internal_set_shadow_origin(address, size, 0, 0, checked); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cidepot_stack_handle_t kmsan_save_stack_with_flags(gfp_t flags, 6862306a36Sopenharmony_ci unsigned int extra) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci unsigned long entries[KMSAN_STACK_DEPTH]; 7162306a36Sopenharmony_ci unsigned int nr_entries; 7262306a36Sopenharmony_ci depot_stack_handle_t handle; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci nr_entries = stack_trace_save(entries, KMSAN_STACK_DEPTH, 0); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* Don't sleep. */ 7762306a36Sopenharmony_ci flags &= ~(__GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci handle = __stack_depot_save(entries, nr_entries, flags, true); 8062306a36Sopenharmony_ci return stack_depot_set_extra_bits(handle, extra); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Copy the metadata following the memmove() behavior. */ 8462306a36Sopenharmony_civoid kmsan_internal_memmove_metadata(void *dst, void *src, size_t n) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci depot_stack_handle_t old_origin = 0, new_origin = 0; 8762306a36Sopenharmony_ci int src_slots, dst_slots, i, iter, step, skip_bits; 8862306a36Sopenharmony_ci depot_stack_handle_t *origin_src, *origin_dst; 8962306a36Sopenharmony_ci void *shadow_src, *shadow_dst; 9062306a36Sopenharmony_ci u32 *align_shadow_src, shadow; 9162306a36Sopenharmony_ci bool backwards; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci shadow_dst = kmsan_get_metadata(dst, KMSAN_META_SHADOW); 9462306a36Sopenharmony_ci if (!shadow_dst) 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(dst, n)); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci shadow_src = kmsan_get_metadata(src, KMSAN_META_SHADOW); 9962306a36Sopenharmony_ci if (!shadow_src) { 10062306a36Sopenharmony_ci /* 10162306a36Sopenharmony_ci * @src is untracked: zero out destination shadow, ignore the 10262306a36Sopenharmony_ci * origins, we're done. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci __memset(shadow_dst, 0, n); 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(src, n)); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci __memmove(shadow_dst, shadow_src, n); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci origin_dst = kmsan_get_metadata(dst, KMSAN_META_ORIGIN); 11262306a36Sopenharmony_ci origin_src = kmsan_get_metadata(src, KMSAN_META_ORIGIN); 11362306a36Sopenharmony_ci KMSAN_WARN_ON(!origin_dst || !origin_src); 11462306a36Sopenharmony_ci src_slots = (ALIGN((u64)src + n, KMSAN_ORIGIN_SIZE) - 11562306a36Sopenharmony_ci ALIGN_DOWN((u64)src, KMSAN_ORIGIN_SIZE)) / 11662306a36Sopenharmony_ci KMSAN_ORIGIN_SIZE; 11762306a36Sopenharmony_ci dst_slots = (ALIGN((u64)dst + n, KMSAN_ORIGIN_SIZE) - 11862306a36Sopenharmony_ci ALIGN_DOWN((u64)dst, KMSAN_ORIGIN_SIZE)) / 11962306a36Sopenharmony_ci KMSAN_ORIGIN_SIZE; 12062306a36Sopenharmony_ci KMSAN_WARN_ON((src_slots < 1) || (dst_slots < 1)); 12162306a36Sopenharmony_ci KMSAN_WARN_ON((src_slots - dst_slots > 1) || 12262306a36Sopenharmony_ci (dst_slots - src_slots < -1)); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci backwards = dst > src; 12562306a36Sopenharmony_ci i = backwards ? min(src_slots, dst_slots) - 1 : 0; 12662306a36Sopenharmony_ci iter = backwards ? -1 : 1; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci align_shadow_src = 12962306a36Sopenharmony_ci (u32 *)ALIGN_DOWN((u64)shadow_src, KMSAN_ORIGIN_SIZE); 13062306a36Sopenharmony_ci for (step = 0; step < min(src_slots, dst_slots); step++, i += iter) { 13162306a36Sopenharmony_ci KMSAN_WARN_ON(i < 0); 13262306a36Sopenharmony_ci shadow = align_shadow_src[i]; 13362306a36Sopenharmony_ci if (i == 0) { 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * If @src isn't aligned on KMSAN_ORIGIN_SIZE, don't 13662306a36Sopenharmony_ci * look at the first @src % KMSAN_ORIGIN_SIZE bytes 13762306a36Sopenharmony_ci * of the first shadow slot. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci skip_bits = ((u64)src % KMSAN_ORIGIN_SIZE) * 8; 14062306a36Sopenharmony_ci shadow = (shadow >> skip_bits) << skip_bits; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci if (i == src_slots - 1) { 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * If @src + n isn't aligned on 14562306a36Sopenharmony_ci * KMSAN_ORIGIN_SIZE, don't look at the last 14662306a36Sopenharmony_ci * (@src + n) % KMSAN_ORIGIN_SIZE bytes of the 14762306a36Sopenharmony_ci * last shadow slot. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci skip_bits = (((u64)src + n) % KMSAN_ORIGIN_SIZE) * 8; 15062306a36Sopenharmony_ci shadow = (shadow << skip_bits) >> skip_bits; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci /* 15362306a36Sopenharmony_ci * Overwrite the origin only if the corresponding 15462306a36Sopenharmony_ci * shadow is nonempty. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (origin_src[i] && (origin_src[i] != old_origin) && shadow) { 15762306a36Sopenharmony_ci old_origin = origin_src[i]; 15862306a36Sopenharmony_ci new_origin = kmsan_internal_chain_origin(old_origin); 15962306a36Sopenharmony_ci /* 16062306a36Sopenharmony_ci * kmsan_internal_chain_origin() may return 16162306a36Sopenharmony_ci * NULL, but we don't want to lose the previous 16262306a36Sopenharmony_ci * origin value. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci if (!new_origin) 16562306a36Sopenharmony_ci new_origin = old_origin; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci if (shadow) 16862306a36Sopenharmony_ci origin_dst[i] = new_origin; 16962306a36Sopenharmony_ci else 17062306a36Sopenharmony_ci origin_dst[i] = 0; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * If dst_slots is greater than src_slots (i.e. 17462306a36Sopenharmony_ci * dst_slots == src_slots + 1), there is an extra origin slot at the 17562306a36Sopenharmony_ci * beginning or end of the destination buffer, for which we take the 17662306a36Sopenharmony_ci * origin from the previous slot. 17762306a36Sopenharmony_ci * This is only done if the part of the source shadow corresponding to 17862306a36Sopenharmony_ci * slot is non-zero. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * E.g. if we copy 8 aligned bytes that are marked as uninitialized 18162306a36Sopenharmony_ci * and have origins o111 and o222, to an unaligned buffer with offset 1, 18262306a36Sopenharmony_ci * these two origins are copied to three origin slots, so one of then 18362306a36Sopenharmony_ci * needs to be duplicated, depending on the copy direction (@backwards) 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * src shadow: |uuuu|uuuu|....| 18662306a36Sopenharmony_ci * src origin: |o111|o222|....| 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * backwards = 0: 18962306a36Sopenharmony_ci * dst shadow: |.uuu|uuuu|u...| 19062306a36Sopenharmony_ci * dst origin: |....|o111|o222| - fill the empty slot with o111 19162306a36Sopenharmony_ci * backwards = 1: 19262306a36Sopenharmony_ci * dst shadow: |.uuu|uuuu|u...| 19362306a36Sopenharmony_ci * dst origin: |o111|o222|....| - fill the empty slot with o222 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci if (src_slots < dst_slots) { 19662306a36Sopenharmony_ci if (backwards) { 19762306a36Sopenharmony_ci shadow = align_shadow_src[src_slots - 1]; 19862306a36Sopenharmony_ci skip_bits = (((u64)dst + n) % KMSAN_ORIGIN_SIZE) * 8; 19962306a36Sopenharmony_ci shadow = (shadow << skip_bits) >> skip_bits; 20062306a36Sopenharmony_ci if (shadow) 20162306a36Sopenharmony_ci /* src_slots > 0, therefore dst_slots is at least 2 */ 20262306a36Sopenharmony_ci origin_dst[dst_slots - 1] = 20362306a36Sopenharmony_ci origin_dst[dst_slots - 2]; 20462306a36Sopenharmony_ci } else { 20562306a36Sopenharmony_ci shadow = align_shadow_src[0]; 20662306a36Sopenharmony_ci skip_bits = ((u64)dst % KMSAN_ORIGIN_SIZE) * 8; 20762306a36Sopenharmony_ci shadow = (shadow >> skip_bits) << skip_bits; 20862306a36Sopenharmony_ci if (shadow) 20962306a36Sopenharmony_ci origin_dst[0] = origin_dst[1]; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cidepot_stack_handle_t kmsan_internal_chain_origin(depot_stack_handle_t id) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci unsigned long entries[3]; 21762306a36Sopenharmony_ci u32 extra_bits; 21862306a36Sopenharmony_ci int depth; 21962306a36Sopenharmony_ci bool uaf; 22062306a36Sopenharmony_ci depot_stack_handle_t handle; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!id) 22362306a36Sopenharmony_ci return id; 22462306a36Sopenharmony_ci /* 22562306a36Sopenharmony_ci * Make sure we have enough spare bits in @id to hold the UAF bit and 22662306a36Sopenharmony_ci * the chain depth. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci BUILD_BUG_ON( 22962306a36Sopenharmony_ci (1 << STACK_DEPOT_EXTRA_BITS) <= (KMSAN_MAX_ORIGIN_DEPTH << 1)); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci extra_bits = stack_depot_get_extra_bits(id); 23262306a36Sopenharmony_ci depth = kmsan_depth_from_eb(extra_bits); 23362306a36Sopenharmony_ci uaf = kmsan_uaf_from_eb(extra_bits); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * Stop chaining origins once the depth reached KMSAN_MAX_ORIGIN_DEPTH. 23762306a36Sopenharmony_ci * This mostly happens in the case structures with uninitialized padding 23862306a36Sopenharmony_ci * are copied around many times. Origin chains for such structures are 23962306a36Sopenharmony_ci * usually periodic, and it does not make sense to fully store them. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci if (depth == KMSAN_MAX_ORIGIN_DEPTH) 24262306a36Sopenharmony_ci return id; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci depth++; 24562306a36Sopenharmony_ci extra_bits = kmsan_extra_bits(depth, uaf); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci entries[0] = KMSAN_CHAIN_MAGIC_ORIGIN; 24862306a36Sopenharmony_ci entries[1] = kmsan_save_stack_with_flags(__GFP_HIGH, 0); 24962306a36Sopenharmony_ci entries[2] = id; 25062306a36Sopenharmony_ci /* 25162306a36Sopenharmony_ci * @entries is a local var in non-instrumented code, so KMSAN does not 25262306a36Sopenharmony_ci * know it is initialized. Explicitly unpoison it to avoid false 25362306a36Sopenharmony_ci * positives when __stack_depot_save() passes it to instrumented code. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci kmsan_internal_unpoison_memory(entries, sizeof(entries), false); 25662306a36Sopenharmony_ci handle = __stack_depot_save(entries, ARRAY_SIZE(entries), __GFP_HIGH, 25762306a36Sopenharmony_ci true); 25862306a36Sopenharmony_ci return stack_depot_set_extra_bits(handle, extra_bits); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_civoid kmsan_internal_set_shadow_origin(void *addr, size_t size, int b, 26262306a36Sopenharmony_ci u32 origin, bool checked) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci u64 address = (u64)addr; 26562306a36Sopenharmony_ci void *shadow_start; 26662306a36Sopenharmony_ci u32 *origin_start; 26762306a36Sopenharmony_ci size_t pad = 0; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(addr, size)); 27062306a36Sopenharmony_ci shadow_start = kmsan_get_metadata(addr, KMSAN_META_SHADOW); 27162306a36Sopenharmony_ci if (!shadow_start) { 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * kmsan_metadata_is_contiguous() is true, so either all shadow 27462306a36Sopenharmony_ci * and origin pages are NULL, or all are non-NULL. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci if (checked) { 27762306a36Sopenharmony_ci pr_err("%s: not memsetting %ld bytes starting at %px, because the shadow is NULL\n", 27862306a36Sopenharmony_ci __func__, size, addr); 27962306a36Sopenharmony_ci KMSAN_WARN_ON(true); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci return; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci __memset(shadow_start, b, size); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!IS_ALIGNED(address, KMSAN_ORIGIN_SIZE)) { 28662306a36Sopenharmony_ci pad = address % KMSAN_ORIGIN_SIZE; 28762306a36Sopenharmony_ci address -= pad; 28862306a36Sopenharmony_ci size += pad; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci size = ALIGN(size, KMSAN_ORIGIN_SIZE); 29162306a36Sopenharmony_ci origin_start = 29262306a36Sopenharmony_ci (u32 *)kmsan_get_metadata((void *)address, KMSAN_META_ORIGIN); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (int i = 0; i < size / KMSAN_ORIGIN_SIZE; i++) 29562306a36Sopenharmony_ci origin_start[i] = origin; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistruct page *kmsan_vmalloc_to_page_or_null(void *vaddr) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct page *page; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (!kmsan_internal_is_vmalloc_addr(vaddr) && 30362306a36Sopenharmony_ci !kmsan_internal_is_module_addr(vaddr)) 30462306a36Sopenharmony_ci return NULL; 30562306a36Sopenharmony_ci page = vmalloc_to_page(vaddr); 30662306a36Sopenharmony_ci if (pfn_valid(page_to_pfn(page))) 30762306a36Sopenharmony_ci return page; 30862306a36Sopenharmony_ci else 30962306a36Sopenharmony_ci return NULL; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_civoid kmsan_internal_check_memory(void *addr, size_t size, const void *user_addr, 31362306a36Sopenharmony_ci int reason) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci depot_stack_handle_t cur_origin = 0, new_origin = 0; 31662306a36Sopenharmony_ci unsigned long addr64 = (unsigned long)addr; 31762306a36Sopenharmony_ci depot_stack_handle_t *origin = NULL; 31862306a36Sopenharmony_ci unsigned char *shadow = NULL; 31962306a36Sopenharmony_ci int cur_off_start = -1; 32062306a36Sopenharmony_ci int chunk_size; 32162306a36Sopenharmony_ci size_t pos = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (!size) 32462306a36Sopenharmony_ci return; 32562306a36Sopenharmony_ci KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(addr, size)); 32662306a36Sopenharmony_ci while (pos < size) { 32762306a36Sopenharmony_ci chunk_size = min(size - pos, 32862306a36Sopenharmony_ci PAGE_SIZE - ((addr64 + pos) % PAGE_SIZE)); 32962306a36Sopenharmony_ci shadow = kmsan_get_metadata((void *)(addr64 + pos), 33062306a36Sopenharmony_ci KMSAN_META_SHADOW); 33162306a36Sopenharmony_ci if (!shadow) { 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * This page is untracked. If there were uninitialized 33462306a36Sopenharmony_ci * bytes before, report them. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if (cur_origin) { 33762306a36Sopenharmony_ci kmsan_enter_runtime(); 33862306a36Sopenharmony_ci kmsan_report(cur_origin, addr, size, 33962306a36Sopenharmony_ci cur_off_start, pos - 1, user_addr, 34062306a36Sopenharmony_ci reason); 34162306a36Sopenharmony_ci kmsan_leave_runtime(); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci cur_origin = 0; 34462306a36Sopenharmony_ci cur_off_start = -1; 34562306a36Sopenharmony_ci pos += chunk_size; 34662306a36Sopenharmony_ci continue; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci for (int i = 0; i < chunk_size; i++) { 34962306a36Sopenharmony_ci if (!shadow[i]) { 35062306a36Sopenharmony_ci /* 35162306a36Sopenharmony_ci * This byte is unpoisoned. If there were 35262306a36Sopenharmony_ci * poisoned bytes before, report them. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci if (cur_origin) { 35562306a36Sopenharmony_ci kmsan_enter_runtime(); 35662306a36Sopenharmony_ci kmsan_report(cur_origin, addr, size, 35762306a36Sopenharmony_ci cur_off_start, pos + i - 1, 35862306a36Sopenharmony_ci user_addr, reason); 35962306a36Sopenharmony_ci kmsan_leave_runtime(); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci cur_origin = 0; 36262306a36Sopenharmony_ci cur_off_start = -1; 36362306a36Sopenharmony_ci continue; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci origin = kmsan_get_metadata((void *)(addr64 + pos + i), 36662306a36Sopenharmony_ci KMSAN_META_ORIGIN); 36762306a36Sopenharmony_ci KMSAN_WARN_ON(!origin); 36862306a36Sopenharmony_ci new_origin = *origin; 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Encountered new origin - report the previous 37162306a36Sopenharmony_ci * uninitialized range. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci if (cur_origin != new_origin) { 37462306a36Sopenharmony_ci if (cur_origin) { 37562306a36Sopenharmony_ci kmsan_enter_runtime(); 37662306a36Sopenharmony_ci kmsan_report(cur_origin, addr, size, 37762306a36Sopenharmony_ci cur_off_start, pos + i - 1, 37862306a36Sopenharmony_ci user_addr, reason); 37962306a36Sopenharmony_ci kmsan_leave_runtime(); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci cur_origin = new_origin; 38262306a36Sopenharmony_ci cur_off_start = pos + i; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci pos += chunk_size; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci KMSAN_WARN_ON(pos != size); 38862306a36Sopenharmony_ci if (cur_origin) { 38962306a36Sopenharmony_ci kmsan_enter_runtime(); 39062306a36Sopenharmony_ci kmsan_report(cur_origin, addr, size, cur_off_start, pos - 1, 39162306a36Sopenharmony_ci user_addr, reason); 39262306a36Sopenharmony_ci kmsan_leave_runtime(); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cibool kmsan_metadata_is_contiguous(void *addr, size_t size) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci char *cur_shadow = NULL, *next_shadow = NULL, *cur_origin = NULL, 39962306a36Sopenharmony_ci *next_origin = NULL; 40062306a36Sopenharmony_ci u64 cur_addr = (u64)addr, next_addr = cur_addr + PAGE_SIZE; 40162306a36Sopenharmony_ci depot_stack_handle_t *origin_p; 40262306a36Sopenharmony_ci bool all_untracked = false; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!size) 40562306a36Sopenharmony_ci return true; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* The whole range belongs to the same page. */ 40862306a36Sopenharmony_ci if (ALIGN_DOWN(cur_addr + size - 1, PAGE_SIZE) == 40962306a36Sopenharmony_ci ALIGN_DOWN(cur_addr, PAGE_SIZE)) 41062306a36Sopenharmony_ci return true; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci cur_shadow = kmsan_get_metadata((void *)cur_addr, /*is_origin*/ false); 41362306a36Sopenharmony_ci if (!cur_shadow) 41462306a36Sopenharmony_ci all_untracked = true; 41562306a36Sopenharmony_ci cur_origin = kmsan_get_metadata((void *)cur_addr, /*is_origin*/ true); 41662306a36Sopenharmony_ci if (all_untracked && cur_origin) 41762306a36Sopenharmony_ci goto report; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci for (; next_addr < (u64)addr + size; 42062306a36Sopenharmony_ci cur_addr = next_addr, cur_shadow = next_shadow, 42162306a36Sopenharmony_ci cur_origin = next_origin, next_addr += PAGE_SIZE) { 42262306a36Sopenharmony_ci next_shadow = kmsan_get_metadata((void *)next_addr, false); 42362306a36Sopenharmony_ci next_origin = kmsan_get_metadata((void *)next_addr, true); 42462306a36Sopenharmony_ci if (all_untracked) { 42562306a36Sopenharmony_ci if (next_shadow || next_origin) 42662306a36Sopenharmony_ci goto report; 42762306a36Sopenharmony_ci if (!next_shadow && !next_origin) 42862306a36Sopenharmony_ci continue; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci if (((u64)cur_shadow == ((u64)next_shadow - PAGE_SIZE)) && 43162306a36Sopenharmony_ci ((u64)cur_origin == ((u64)next_origin - PAGE_SIZE))) 43262306a36Sopenharmony_ci continue; 43362306a36Sopenharmony_ci goto report; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci return true; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cireport: 43862306a36Sopenharmony_ci pr_err("%s: attempting to access two shadow page ranges.\n", __func__); 43962306a36Sopenharmony_ci pr_err("Access of size %ld at %px.\n", size, addr); 44062306a36Sopenharmony_ci pr_err("Addresses belonging to different ranges: %px and %px\n", 44162306a36Sopenharmony_ci (void *)cur_addr, (void *)next_addr); 44262306a36Sopenharmony_ci pr_err("page[0].shadow: %px, page[1].shadow: %px\n", cur_shadow, 44362306a36Sopenharmony_ci next_shadow); 44462306a36Sopenharmony_ci pr_err("page[0].origin: %px, page[1].origin: %px\n", cur_origin, 44562306a36Sopenharmony_ci next_origin); 44662306a36Sopenharmony_ci origin_p = kmsan_get_metadata(addr, KMSAN_META_ORIGIN); 44762306a36Sopenharmony_ci if (origin_p) { 44862306a36Sopenharmony_ci pr_err("Origin: %08x\n", *origin_p); 44962306a36Sopenharmony_ci kmsan_print_origin(*origin_p); 45062306a36Sopenharmony_ci } else { 45162306a36Sopenharmony_ci pr_err("Origin: unavailable\n"); 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci return false; 45462306a36Sopenharmony_ci} 455