1f80be457SAlexander Potapenko // SPDX-License-Identifier: GPL-2.0
2f80be457SAlexander Potapenko /*
3f80be457SAlexander Potapenko * KMSAN runtime library.
4f80be457SAlexander Potapenko *
5f80be457SAlexander Potapenko * Copyright (C) 2017-2022 Google LLC
6f80be457SAlexander Potapenko * Author: Alexander Potapenko <glider@google.com>
7f80be457SAlexander Potapenko *
8f80be457SAlexander Potapenko */
9f80be457SAlexander Potapenko
10f80be457SAlexander Potapenko #include <asm/page.h>
11f80be457SAlexander Potapenko #include <linux/compiler.h>
12f80be457SAlexander Potapenko #include <linux/export.h>
13f80be457SAlexander Potapenko #include <linux/highmem.h>
14f80be457SAlexander Potapenko #include <linux/interrupt.h>
15f80be457SAlexander Potapenko #include <linux/kernel.h>
16f80be457SAlexander Potapenko #include <linux/kmsan_types.h>
17f80be457SAlexander Potapenko #include <linux/memory.h>
18f80be457SAlexander Potapenko #include <linux/mm.h>
19f80be457SAlexander Potapenko #include <linux/mm_types.h>
20f80be457SAlexander Potapenko #include <linux/mmzone.h>
21f80be457SAlexander Potapenko #include <linux/percpu-defs.h>
22f80be457SAlexander Potapenko #include <linux/preempt.h>
23f80be457SAlexander Potapenko #include <linux/slab.h>
24f80be457SAlexander Potapenko #include <linux/stackdepot.h>
25f80be457SAlexander Potapenko #include <linux/stacktrace.h>
26f80be457SAlexander Potapenko #include <linux/types.h>
27f80be457SAlexander Potapenko #include <linux/vmalloc.h>
28f80be457SAlexander Potapenko
29f80be457SAlexander Potapenko #include "../slab.h"
30f80be457SAlexander Potapenko #include "kmsan.h"
31f80be457SAlexander Potapenko
32f80be457SAlexander Potapenko bool kmsan_enabled __read_mostly;
33f80be457SAlexander Potapenko
34f80be457SAlexander Potapenko /*
35f80be457SAlexander Potapenko * Per-CPU KMSAN context to be used in interrupts, where current->kmsan is
36f80be457SAlexander Potapenko * unavaliable.
37f80be457SAlexander Potapenko */
38f80be457SAlexander Potapenko DEFINE_PER_CPU(struct kmsan_ctx, kmsan_percpu_ctx);
39f80be457SAlexander Potapenko
kmsan_internal_task_create(struct task_struct * task)4050b5e49cSAlexander Potapenko void kmsan_internal_task_create(struct task_struct *task)
4150b5e49cSAlexander Potapenko {
4250b5e49cSAlexander Potapenko struct kmsan_ctx *ctx = &task->kmsan_ctx;
4350b5e49cSAlexander Potapenko struct thread_info *info = current_thread_info();
4450b5e49cSAlexander Potapenko
4550b5e49cSAlexander Potapenko __memset(ctx, 0, sizeof(*ctx));
4650b5e49cSAlexander Potapenko ctx->allow_reporting = true;
4750b5e49cSAlexander Potapenko kmsan_internal_unpoison_memory(info, sizeof(*info), false);
4850b5e49cSAlexander Potapenko }
4950b5e49cSAlexander Potapenko
kmsan_internal_poison_memory(void * address,size_t size,gfp_t flags,unsigned int poison_flags)50f80be457SAlexander Potapenko void kmsan_internal_poison_memory(void *address, size_t size, gfp_t flags,
51f80be457SAlexander Potapenko unsigned int poison_flags)
52f80be457SAlexander Potapenko {
53f80be457SAlexander Potapenko u32 extra_bits =
54f80be457SAlexander Potapenko kmsan_extra_bits(/*depth*/ 0, poison_flags & KMSAN_POISON_FREE);
55f80be457SAlexander Potapenko bool checked = poison_flags & KMSAN_POISON_CHECK;
56f80be457SAlexander Potapenko depot_stack_handle_t handle;
57f80be457SAlexander Potapenko
58f80be457SAlexander Potapenko handle = kmsan_save_stack_with_flags(flags, extra_bits);
59f80be457SAlexander Potapenko kmsan_internal_set_shadow_origin(address, size, -1, handle, checked);
60f80be457SAlexander Potapenko }
61f80be457SAlexander Potapenko
kmsan_internal_unpoison_memory(void * address,size_t size,bool checked)62f80be457SAlexander Potapenko void kmsan_internal_unpoison_memory(void *address, size_t size, bool checked)
63f80be457SAlexander Potapenko {
64f80be457SAlexander Potapenko kmsan_internal_set_shadow_origin(address, size, 0, 0, checked);
65f80be457SAlexander Potapenko }
66f80be457SAlexander Potapenko
kmsan_save_stack_with_flags(gfp_t flags,unsigned int extra)67f80be457SAlexander Potapenko depot_stack_handle_t kmsan_save_stack_with_flags(gfp_t flags,
68f80be457SAlexander Potapenko unsigned int extra)
69f80be457SAlexander Potapenko {
70f80be457SAlexander Potapenko unsigned long entries[KMSAN_STACK_DEPTH];
71f80be457SAlexander Potapenko unsigned int nr_entries;
7236aa1e67SAndrey Konovalov depot_stack_handle_t handle;
73f80be457SAlexander Potapenko
74f80be457SAlexander Potapenko nr_entries = stack_trace_save(entries, KMSAN_STACK_DEPTH, 0);
75f80be457SAlexander Potapenko
76e961cc56SZhen Lei /* Don't sleep. */
77726ccdbaSTetsuo Handa flags &= ~(__GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM);
78f80be457SAlexander Potapenko
7936aa1e67SAndrey Konovalov handle = __stack_depot_save(entries, nr_entries, flags, true);
8036aa1e67SAndrey Konovalov return stack_depot_set_extra_bits(handle, extra);
81f80be457SAlexander Potapenko }
82f80be457SAlexander Potapenko
83f80be457SAlexander Potapenko /* Copy the metadata following the memmove() behavior. */
kmsan_internal_memmove_metadata(void * dst,void * src,size_t n)84f80be457SAlexander Potapenko void kmsan_internal_memmove_metadata(void *dst, void *src, size_t n)
85f80be457SAlexander Potapenko {
86f80be457SAlexander Potapenko depot_stack_handle_t old_origin = 0, new_origin = 0;
87f80be457SAlexander Potapenko int src_slots, dst_slots, i, iter, step, skip_bits;
88f80be457SAlexander Potapenko depot_stack_handle_t *origin_src, *origin_dst;
89f80be457SAlexander Potapenko void *shadow_src, *shadow_dst;
90f80be457SAlexander Potapenko u32 *align_shadow_src, shadow;
91f80be457SAlexander Potapenko bool backwards;
92f80be457SAlexander Potapenko
93f80be457SAlexander Potapenko shadow_dst = kmsan_get_metadata(dst, KMSAN_META_SHADOW);
94f80be457SAlexander Potapenko if (!shadow_dst)
95f80be457SAlexander Potapenko return;
96f80be457SAlexander Potapenko KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(dst, n));
97f80be457SAlexander Potapenko
98f80be457SAlexander Potapenko shadow_src = kmsan_get_metadata(src, KMSAN_META_SHADOW);
99f80be457SAlexander Potapenko if (!shadow_src) {
100f80be457SAlexander Potapenko /*
101f80be457SAlexander Potapenko * @src is untracked: zero out destination shadow, ignore the
102f80be457SAlexander Potapenko * origins, we're done.
103f80be457SAlexander Potapenko */
104f80be457SAlexander Potapenko __memset(shadow_dst, 0, n);
105f80be457SAlexander Potapenko return;
106f80be457SAlexander Potapenko }
107f80be457SAlexander Potapenko KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(src, n));
108f80be457SAlexander Potapenko
109f80be457SAlexander Potapenko __memmove(shadow_dst, shadow_src, n);
110f80be457SAlexander Potapenko
111f80be457SAlexander Potapenko origin_dst = kmsan_get_metadata(dst, KMSAN_META_ORIGIN);
112f80be457SAlexander Potapenko origin_src = kmsan_get_metadata(src, KMSAN_META_ORIGIN);
113f80be457SAlexander Potapenko KMSAN_WARN_ON(!origin_dst || !origin_src);
114f80be457SAlexander Potapenko src_slots = (ALIGN((u64)src + n, KMSAN_ORIGIN_SIZE) -
115f80be457SAlexander Potapenko ALIGN_DOWN((u64)src, KMSAN_ORIGIN_SIZE)) /
116f80be457SAlexander Potapenko KMSAN_ORIGIN_SIZE;
117f80be457SAlexander Potapenko dst_slots = (ALIGN((u64)dst + n, KMSAN_ORIGIN_SIZE) -
118f80be457SAlexander Potapenko ALIGN_DOWN((u64)dst, KMSAN_ORIGIN_SIZE)) /
119f80be457SAlexander Potapenko KMSAN_ORIGIN_SIZE;
120f80be457SAlexander Potapenko KMSAN_WARN_ON((src_slots < 1) || (dst_slots < 1));
121f80be457SAlexander Potapenko KMSAN_WARN_ON((src_slots - dst_slots > 1) ||
122f80be457SAlexander Potapenko (dst_slots - src_slots < -1));
123f80be457SAlexander Potapenko
124f80be457SAlexander Potapenko backwards = dst > src;
125f80be457SAlexander Potapenko i = backwards ? min(src_slots, dst_slots) - 1 : 0;
126f80be457SAlexander Potapenko iter = backwards ? -1 : 1;
127f80be457SAlexander Potapenko
128f80be457SAlexander Potapenko align_shadow_src =
129f80be457SAlexander Potapenko (u32 *)ALIGN_DOWN((u64)shadow_src, KMSAN_ORIGIN_SIZE);
130f80be457SAlexander Potapenko for (step = 0; step < min(src_slots, dst_slots); step++, i += iter) {
131f80be457SAlexander Potapenko KMSAN_WARN_ON(i < 0);
132f80be457SAlexander Potapenko shadow = align_shadow_src[i];
133f80be457SAlexander Potapenko if (i == 0) {
134f80be457SAlexander Potapenko /*
135f80be457SAlexander Potapenko * If @src isn't aligned on KMSAN_ORIGIN_SIZE, don't
136f80be457SAlexander Potapenko * look at the first @src % KMSAN_ORIGIN_SIZE bytes
137f80be457SAlexander Potapenko * of the first shadow slot.
138f80be457SAlexander Potapenko */
139f80be457SAlexander Potapenko skip_bits = ((u64)src % KMSAN_ORIGIN_SIZE) * 8;
140f80be457SAlexander Potapenko shadow = (shadow >> skip_bits) << skip_bits;
141f80be457SAlexander Potapenko }
142f80be457SAlexander Potapenko if (i == src_slots - 1) {
143f80be457SAlexander Potapenko /*
144f80be457SAlexander Potapenko * If @src + n isn't aligned on
145f80be457SAlexander Potapenko * KMSAN_ORIGIN_SIZE, don't look at the last
146f80be457SAlexander Potapenko * (@src + n) % KMSAN_ORIGIN_SIZE bytes of the
147f80be457SAlexander Potapenko * last shadow slot.
148f80be457SAlexander Potapenko */
149f80be457SAlexander Potapenko skip_bits = (((u64)src + n) % KMSAN_ORIGIN_SIZE) * 8;
150f80be457SAlexander Potapenko shadow = (shadow << skip_bits) >> skip_bits;
151f80be457SAlexander Potapenko }
152f80be457SAlexander Potapenko /*
153f80be457SAlexander Potapenko * Overwrite the origin only if the corresponding
154f80be457SAlexander Potapenko * shadow is nonempty.
155f80be457SAlexander Potapenko */
156f80be457SAlexander Potapenko if (origin_src[i] && (origin_src[i] != old_origin) && shadow) {
157f80be457SAlexander Potapenko old_origin = origin_src[i];
158f80be457SAlexander Potapenko new_origin = kmsan_internal_chain_origin(old_origin);
159f80be457SAlexander Potapenko /*
160f80be457SAlexander Potapenko * kmsan_internal_chain_origin() may return
161f80be457SAlexander Potapenko * NULL, but we don't want to lose the previous
162f80be457SAlexander Potapenko * origin value.
163f80be457SAlexander Potapenko */
164f80be457SAlexander Potapenko if (!new_origin)
165f80be457SAlexander Potapenko new_origin = old_origin;
166f80be457SAlexander Potapenko }
167f80be457SAlexander Potapenko if (shadow)
168f80be457SAlexander Potapenko origin_dst[i] = new_origin;
169f80be457SAlexander Potapenko else
170f80be457SAlexander Potapenko origin_dst[i] = 0;
171f80be457SAlexander Potapenko }
172f80be457SAlexander Potapenko /*
173f80be457SAlexander Potapenko * If dst_slots is greater than src_slots (i.e.
174f80be457SAlexander Potapenko * dst_slots == src_slots + 1), there is an extra origin slot at the
175f80be457SAlexander Potapenko * beginning or end of the destination buffer, for which we take the
176f80be457SAlexander Potapenko * origin from the previous slot.
177f80be457SAlexander Potapenko * This is only done if the part of the source shadow corresponding to
178f80be457SAlexander Potapenko * slot is non-zero.
179f80be457SAlexander Potapenko *
180f80be457SAlexander Potapenko * E.g. if we copy 8 aligned bytes that are marked as uninitialized
181f80be457SAlexander Potapenko * and have origins o111 and o222, to an unaligned buffer with offset 1,
182f80be457SAlexander Potapenko * these two origins are copied to three origin slots, so one of then
183f80be457SAlexander Potapenko * needs to be duplicated, depending on the copy direction (@backwards)
184f80be457SAlexander Potapenko *
185f80be457SAlexander Potapenko * src shadow: |uuuu|uuuu|....|
186f80be457SAlexander Potapenko * src origin: |o111|o222|....|
187f80be457SAlexander Potapenko *
188f80be457SAlexander Potapenko * backwards = 0:
189f80be457SAlexander Potapenko * dst shadow: |.uuu|uuuu|u...|
190f80be457SAlexander Potapenko * dst origin: |....|o111|o222| - fill the empty slot with o111
191f80be457SAlexander Potapenko * backwards = 1:
192f80be457SAlexander Potapenko * dst shadow: |.uuu|uuuu|u...|
193f80be457SAlexander Potapenko * dst origin: |o111|o222|....| - fill the empty slot with o222
194f80be457SAlexander Potapenko */
195f80be457SAlexander Potapenko if (src_slots < dst_slots) {
196f80be457SAlexander Potapenko if (backwards) {
197f80be457SAlexander Potapenko shadow = align_shadow_src[src_slots - 1];
198f80be457SAlexander Potapenko skip_bits = (((u64)dst + n) % KMSAN_ORIGIN_SIZE) * 8;
199f80be457SAlexander Potapenko shadow = (shadow << skip_bits) >> skip_bits;
200f80be457SAlexander Potapenko if (shadow)
201f80be457SAlexander Potapenko /* src_slots > 0, therefore dst_slots is at least 2 */
202f80be457SAlexander Potapenko origin_dst[dst_slots - 1] =
203f80be457SAlexander Potapenko origin_dst[dst_slots - 2];
204f80be457SAlexander Potapenko } else {
205f80be457SAlexander Potapenko shadow = align_shadow_src[0];
206f80be457SAlexander Potapenko skip_bits = ((u64)dst % KMSAN_ORIGIN_SIZE) * 8;
207f80be457SAlexander Potapenko shadow = (shadow >> skip_bits) << skip_bits;
208f80be457SAlexander Potapenko if (shadow)
209f80be457SAlexander Potapenko origin_dst[0] = origin_dst[1];
210f80be457SAlexander Potapenko }
211f80be457SAlexander Potapenko }
212f80be457SAlexander Potapenko }
213f80be457SAlexander Potapenko
kmsan_internal_chain_origin(depot_stack_handle_t id)214f80be457SAlexander Potapenko depot_stack_handle_t kmsan_internal_chain_origin(depot_stack_handle_t id)
215f80be457SAlexander Potapenko {
216f80be457SAlexander Potapenko unsigned long entries[3];
217f80be457SAlexander Potapenko u32 extra_bits;
218f80be457SAlexander Potapenko int depth;
219f80be457SAlexander Potapenko bool uaf;
22036aa1e67SAndrey Konovalov depot_stack_handle_t handle;
221f80be457SAlexander Potapenko
222f80be457SAlexander Potapenko if (!id)
223f80be457SAlexander Potapenko return id;
224f80be457SAlexander Potapenko /*
225f80be457SAlexander Potapenko * Make sure we have enough spare bits in @id to hold the UAF bit and
226f80be457SAlexander Potapenko * the chain depth.
227f80be457SAlexander Potapenko */
228f80be457SAlexander Potapenko BUILD_BUG_ON(
229f80be457SAlexander Potapenko (1 << STACK_DEPOT_EXTRA_BITS) <= (KMSAN_MAX_ORIGIN_DEPTH << 1));
230f80be457SAlexander Potapenko
231f80be457SAlexander Potapenko extra_bits = stack_depot_get_extra_bits(id);
232f80be457SAlexander Potapenko depth = kmsan_depth_from_eb(extra_bits);
233f80be457SAlexander Potapenko uaf = kmsan_uaf_from_eb(extra_bits);
234f80be457SAlexander Potapenko
235f80be457SAlexander Potapenko /*
236f80be457SAlexander Potapenko * Stop chaining origins once the depth reached KMSAN_MAX_ORIGIN_DEPTH.
237f80be457SAlexander Potapenko * This mostly happens in the case structures with uninitialized padding
238f80be457SAlexander Potapenko * are copied around many times. Origin chains for such structures are
239f80be457SAlexander Potapenko * usually periodic, and it does not make sense to fully store them.
240f80be457SAlexander Potapenko */
241f80be457SAlexander Potapenko if (depth == KMSAN_MAX_ORIGIN_DEPTH)
242f80be457SAlexander Potapenko return id;
243f80be457SAlexander Potapenko
244f80be457SAlexander Potapenko depth++;
245f80be457SAlexander Potapenko extra_bits = kmsan_extra_bits(depth, uaf);
246f80be457SAlexander Potapenko
247f80be457SAlexander Potapenko entries[0] = KMSAN_CHAIN_MAGIC_ORIGIN;
248726ccdbaSTetsuo Handa entries[1] = kmsan_save_stack_with_flags(__GFP_HIGH, 0);
249f80be457SAlexander Potapenko entries[2] = id;
250f80be457SAlexander Potapenko /*
251f80be457SAlexander Potapenko * @entries is a local var in non-instrumented code, so KMSAN does not
252f80be457SAlexander Potapenko * know it is initialized. Explicitly unpoison it to avoid false
253f80be457SAlexander Potapenko * positives when __stack_depot_save() passes it to instrumented code.
254f80be457SAlexander Potapenko */
255f80be457SAlexander Potapenko kmsan_internal_unpoison_memory(entries, sizeof(entries), false);
256726ccdbaSTetsuo Handa handle = __stack_depot_save(entries, ARRAY_SIZE(entries), __GFP_HIGH,
25736aa1e67SAndrey Konovalov true);
25836aa1e67SAndrey Konovalov return stack_depot_set_extra_bits(handle, extra_bits);
259f80be457SAlexander Potapenko }
260f80be457SAlexander Potapenko
kmsan_internal_set_shadow_origin(void * addr,size_t size,int b,u32 origin,bool checked)261f80be457SAlexander Potapenko void kmsan_internal_set_shadow_origin(void *addr, size_t size, int b,
262f80be457SAlexander Potapenko u32 origin, bool checked)
263f80be457SAlexander Potapenko {
264f80be457SAlexander Potapenko u64 address = (u64)addr;
265*19e85d93SAlexander Potapenko u32 *shadow_start, *origin_start;
266f80be457SAlexander Potapenko size_t pad = 0;
267f80be457SAlexander Potapenko
268f80be457SAlexander Potapenko KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(addr, size));
269f80be457SAlexander Potapenko shadow_start = kmsan_get_metadata(addr, KMSAN_META_SHADOW);
270f80be457SAlexander Potapenko if (!shadow_start) {
271f80be457SAlexander Potapenko /*
272f80be457SAlexander Potapenko * kmsan_metadata_is_contiguous() is true, so either all shadow
273f80be457SAlexander Potapenko * and origin pages are NULL, or all are non-NULL.
274f80be457SAlexander Potapenko */
275f80be457SAlexander Potapenko if (checked) {
276f80be457SAlexander Potapenko pr_err("%s: not memsetting %ld bytes starting at %px, because the shadow is NULL\n",
277f80be457SAlexander Potapenko __func__, size, addr);
278f80be457SAlexander Potapenko KMSAN_WARN_ON(true);
279f80be457SAlexander Potapenko }
280f80be457SAlexander Potapenko return;
281f80be457SAlexander Potapenko }
282f80be457SAlexander Potapenko __memset(shadow_start, b, size);
283f80be457SAlexander Potapenko
284f80be457SAlexander Potapenko if (!IS_ALIGNED(address, KMSAN_ORIGIN_SIZE)) {
285f80be457SAlexander Potapenko pad = address % KMSAN_ORIGIN_SIZE;
286f80be457SAlexander Potapenko address -= pad;
287f80be457SAlexander Potapenko size += pad;
288f80be457SAlexander Potapenko }
289f80be457SAlexander Potapenko size = ALIGN(size, KMSAN_ORIGIN_SIZE);
290f80be457SAlexander Potapenko origin_start =
291f80be457SAlexander Potapenko (u32 *)kmsan_get_metadata((void *)address, KMSAN_META_ORIGIN);
292f80be457SAlexander Potapenko
293*19e85d93SAlexander Potapenko /*
294*19e85d93SAlexander Potapenko * If the new origin is non-zero, assume that the shadow byte is also non-zero,
295*19e85d93SAlexander Potapenko * and unconditionally overwrite the old origin slot.
296*19e85d93SAlexander Potapenko * If the new origin is zero, overwrite the old origin slot iff the
297*19e85d93SAlexander Potapenko * corresponding shadow slot is zero.
298*19e85d93SAlexander Potapenko */
299*19e85d93SAlexander Potapenko for (int i = 0; i < size / KMSAN_ORIGIN_SIZE; i++) {
300*19e85d93SAlexander Potapenko if (origin || !shadow_start[i])
301f80be457SAlexander Potapenko origin_start[i] = origin;
302f80be457SAlexander Potapenko }
303*19e85d93SAlexander Potapenko }
304f80be457SAlexander Potapenko
kmsan_vmalloc_to_page_or_null(void * vaddr)305f80be457SAlexander Potapenko struct page *kmsan_vmalloc_to_page_or_null(void *vaddr)
306f80be457SAlexander Potapenko {
307f80be457SAlexander Potapenko struct page *page;
308f80be457SAlexander Potapenko
309f80be457SAlexander Potapenko if (!kmsan_internal_is_vmalloc_addr(vaddr) &&
310f80be457SAlexander Potapenko !kmsan_internal_is_module_addr(vaddr))
311f80be457SAlexander Potapenko return NULL;
312f80be457SAlexander Potapenko page = vmalloc_to_page(vaddr);
313f80be457SAlexander Potapenko if (pfn_valid(page_to_pfn(page)))
314f80be457SAlexander Potapenko return page;
315f80be457SAlexander Potapenko else
316f80be457SAlexander Potapenko return NULL;
317f80be457SAlexander Potapenko }
318f80be457SAlexander Potapenko
kmsan_internal_check_memory(void * addr,size_t size,const void * user_addr,int reason)319f80be457SAlexander Potapenko void kmsan_internal_check_memory(void *addr, size_t size, const void *user_addr,
320f80be457SAlexander Potapenko int reason)
321f80be457SAlexander Potapenko {
322f80be457SAlexander Potapenko depot_stack_handle_t cur_origin = 0, new_origin = 0;
323f80be457SAlexander Potapenko unsigned long addr64 = (unsigned long)addr;
324f80be457SAlexander Potapenko depot_stack_handle_t *origin = NULL;
325f80be457SAlexander Potapenko unsigned char *shadow = NULL;
326f80be457SAlexander Potapenko int cur_off_start = -1;
327f80be457SAlexander Potapenko int chunk_size;
328f80be457SAlexander Potapenko size_t pos = 0;
329f80be457SAlexander Potapenko
330f80be457SAlexander Potapenko if (!size)
331f80be457SAlexander Potapenko return;
332f80be457SAlexander Potapenko KMSAN_WARN_ON(!kmsan_metadata_is_contiguous(addr, size));
333f80be457SAlexander Potapenko while (pos < size) {
334f80be457SAlexander Potapenko chunk_size = min(size - pos,
335f80be457SAlexander Potapenko PAGE_SIZE - ((addr64 + pos) % PAGE_SIZE));
336f80be457SAlexander Potapenko shadow = kmsan_get_metadata((void *)(addr64 + pos),
337f80be457SAlexander Potapenko KMSAN_META_SHADOW);
338f80be457SAlexander Potapenko if (!shadow) {
339f80be457SAlexander Potapenko /*
340f80be457SAlexander Potapenko * This page is untracked. If there were uninitialized
341f80be457SAlexander Potapenko * bytes before, report them.
342f80be457SAlexander Potapenko */
343f80be457SAlexander Potapenko if (cur_origin) {
344f80be457SAlexander Potapenko kmsan_enter_runtime();
345f80be457SAlexander Potapenko kmsan_report(cur_origin, addr, size,
346f80be457SAlexander Potapenko cur_off_start, pos - 1, user_addr,
347f80be457SAlexander Potapenko reason);
348f80be457SAlexander Potapenko kmsan_leave_runtime();
349f80be457SAlexander Potapenko }
350f80be457SAlexander Potapenko cur_origin = 0;
351f80be457SAlexander Potapenko cur_off_start = -1;
352f80be457SAlexander Potapenko pos += chunk_size;
353f80be457SAlexander Potapenko continue;
354f80be457SAlexander Potapenko }
355f80be457SAlexander Potapenko for (int i = 0; i < chunk_size; i++) {
356f80be457SAlexander Potapenko if (!shadow[i]) {
357f80be457SAlexander Potapenko /*
358f80be457SAlexander Potapenko * This byte is unpoisoned. If there were
359f80be457SAlexander Potapenko * poisoned bytes before, report them.
360f80be457SAlexander Potapenko */
361f80be457SAlexander Potapenko if (cur_origin) {
362f80be457SAlexander Potapenko kmsan_enter_runtime();
363f80be457SAlexander Potapenko kmsan_report(cur_origin, addr, size,
364f80be457SAlexander Potapenko cur_off_start, pos + i - 1,
365f80be457SAlexander Potapenko user_addr, reason);
366f80be457SAlexander Potapenko kmsan_leave_runtime();
367f80be457SAlexander Potapenko }
368f80be457SAlexander Potapenko cur_origin = 0;
369f80be457SAlexander Potapenko cur_off_start = -1;
370f80be457SAlexander Potapenko continue;
371f80be457SAlexander Potapenko }
372f80be457SAlexander Potapenko origin = kmsan_get_metadata((void *)(addr64 + pos + i),
373f80be457SAlexander Potapenko KMSAN_META_ORIGIN);
374f80be457SAlexander Potapenko KMSAN_WARN_ON(!origin);
375f80be457SAlexander Potapenko new_origin = *origin;
376f80be457SAlexander Potapenko /*
377f80be457SAlexander Potapenko * Encountered new origin - report the previous
378f80be457SAlexander Potapenko * uninitialized range.
379f80be457SAlexander Potapenko */
380f80be457SAlexander Potapenko if (cur_origin != new_origin) {
381f80be457SAlexander Potapenko if (cur_origin) {
382f80be457SAlexander Potapenko kmsan_enter_runtime();
383f80be457SAlexander Potapenko kmsan_report(cur_origin, addr, size,
384f80be457SAlexander Potapenko cur_off_start, pos + i - 1,
385f80be457SAlexander Potapenko user_addr, reason);
386f80be457SAlexander Potapenko kmsan_leave_runtime();
387f80be457SAlexander Potapenko }
388f80be457SAlexander Potapenko cur_origin = new_origin;
389f80be457SAlexander Potapenko cur_off_start = pos + i;
390f80be457SAlexander Potapenko }
391f80be457SAlexander Potapenko }
392f80be457SAlexander Potapenko pos += chunk_size;
393f80be457SAlexander Potapenko }
394f80be457SAlexander Potapenko KMSAN_WARN_ON(pos != size);
395f80be457SAlexander Potapenko if (cur_origin) {
396f80be457SAlexander Potapenko kmsan_enter_runtime();
397f80be457SAlexander Potapenko kmsan_report(cur_origin, addr, size, cur_off_start, pos - 1,
398f80be457SAlexander Potapenko user_addr, reason);
399f80be457SAlexander Potapenko kmsan_leave_runtime();
400f80be457SAlexander Potapenko }
401f80be457SAlexander Potapenko }
402f80be457SAlexander Potapenko
kmsan_metadata_is_contiguous(void * addr,size_t size)403f80be457SAlexander Potapenko bool kmsan_metadata_is_contiguous(void *addr, size_t size)
404f80be457SAlexander Potapenko {
405f80be457SAlexander Potapenko char *cur_shadow = NULL, *next_shadow = NULL, *cur_origin = NULL,
406f80be457SAlexander Potapenko *next_origin = NULL;
407f80be457SAlexander Potapenko u64 cur_addr = (u64)addr, next_addr = cur_addr + PAGE_SIZE;
408f80be457SAlexander Potapenko depot_stack_handle_t *origin_p;
409f80be457SAlexander Potapenko bool all_untracked = false;
410f80be457SAlexander Potapenko
411f80be457SAlexander Potapenko if (!size)
412f80be457SAlexander Potapenko return true;
413f80be457SAlexander Potapenko
414f80be457SAlexander Potapenko /* The whole range belongs to the same page. */
415f80be457SAlexander Potapenko if (ALIGN_DOWN(cur_addr + size - 1, PAGE_SIZE) ==
416f80be457SAlexander Potapenko ALIGN_DOWN(cur_addr, PAGE_SIZE))
417f80be457SAlexander Potapenko return true;
418f80be457SAlexander Potapenko
419f80be457SAlexander Potapenko cur_shadow = kmsan_get_metadata((void *)cur_addr, /*is_origin*/ false);
420f80be457SAlexander Potapenko if (!cur_shadow)
421f80be457SAlexander Potapenko all_untracked = true;
422f80be457SAlexander Potapenko cur_origin = kmsan_get_metadata((void *)cur_addr, /*is_origin*/ true);
423f80be457SAlexander Potapenko if (all_untracked && cur_origin)
424f80be457SAlexander Potapenko goto report;
425f80be457SAlexander Potapenko
426f80be457SAlexander Potapenko for (; next_addr < (u64)addr + size;
427f80be457SAlexander Potapenko cur_addr = next_addr, cur_shadow = next_shadow,
428f80be457SAlexander Potapenko cur_origin = next_origin, next_addr += PAGE_SIZE) {
429f80be457SAlexander Potapenko next_shadow = kmsan_get_metadata((void *)next_addr, false);
430f80be457SAlexander Potapenko next_origin = kmsan_get_metadata((void *)next_addr, true);
431f80be457SAlexander Potapenko if (all_untracked) {
432f80be457SAlexander Potapenko if (next_shadow || next_origin)
433f80be457SAlexander Potapenko goto report;
434f80be457SAlexander Potapenko if (!next_shadow && !next_origin)
435f80be457SAlexander Potapenko continue;
436f80be457SAlexander Potapenko }
437f80be457SAlexander Potapenko if (((u64)cur_shadow == ((u64)next_shadow - PAGE_SIZE)) &&
438f80be457SAlexander Potapenko ((u64)cur_origin == ((u64)next_origin - PAGE_SIZE)))
439f80be457SAlexander Potapenko continue;
440f80be457SAlexander Potapenko goto report;
441f80be457SAlexander Potapenko }
442f80be457SAlexander Potapenko return true;
443f80be457SAlexander Potapenko
444f80be457SAlexander Potapenko report:
445f80be457SAlexander Potapenko pr_err("%s: attempting to access two shadow page ranges.\n", __func__);
446f80be457SAlexander Potapenko pr_err("Access of size %ld at %px.\n", size, addr);
447f80be457SAlexander Potapenko pr_err("Addresses belonging to different ranges: %px and %px\n",
448f80be457SAlexander Potapenko (void *)cur_addr, (void *)next_addr);
449f80be457SAlexander Potapenko pr_err("page[0].shadow: %px, page[1].shadow: %px\n", cur_shadow,
450f80be457SAlexander Potapenko next_shadow);
451f80be457SAlexander Potapenko pr_err("page[0].origin: %px, page[1].origin: %px\n", cur_origin,
452f80be457SAlexander Potapenko next_origin);
453f80be457SAlexander Potapenko origin_p = kmsan_get_metadata(addr, KMSAN_META_ORIGIN);
454f80be457SAlexander Potapenko if (origin_p) {
455f80be457SAlexander Potapenko pr_err("Origin: %08x\n", *origin_p);
456f80be457SAlexander Potapenko kmsan_print_origin(*origin_p);
457f80be457SAlexander Potapenko } else {
458f80be457SAlexander Potapenko pr_err("Origin: unavailable\n");
459f80be457SAlexander Potapenko }
460f80be457SAlexander Potapenko return false;
461f80be457SAlexander Potapenko }
462