162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Functions used by the KMSAN runtime.
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#ifndef __MM_KMSAN_KMSAN_H
1162306a36Sopenharmony_ci#define __MM_KMSAN_KMSAN_H
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <asm/pgtable_64_types.h>
1462306a36Sopenharmony_ci#include <linux/irqflags.h>
1562306a36Sopenharmony_ci#include <linux/sched.h>
1662306a36Sopenharmony_ci#include <linux/stackdepot.h>
1762306a36Sopenharmony_ci#include <linux/stacktrace.h>
1862306a36Sopenharmony_ci#include <linux/nmi.h>
1962306a36Sopenharmony_ci#include <linux/mm.h>
2062306a36Sopenharmony_ci#include <linux/printk.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define KMSAN_ALLOCA_MAGIC_ORIGIN 0xabcd0100
2362306a36Sopenharmony_ci#define KMSAN_CHAIN_MAGIC_ORIGIN 0xabcd0200
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define KMSAN_POISON_NOCHECK 0x0
2662306a36Sopenharmony_ci#define KMSAN_POISON_CHECK 0x1
2762306a36Sopenharmony_ci#define KMSAN_POISON_FREE 0x2
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define KMSAN_ORIGIN_SIZE 4
3062306a36Sopenharmony_ci#define KMSAN_MAX_ORIGIN_DEPTH 7
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define KMSAN_STACK_DEPTH 64
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define KMSAN_META_SHADOW (false)
3562306a36Sopenharmony_ci#define KMSAN_META_ORIGIN (true)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciextern bool kmsan_enabled;
3862306a36Sopenharmony_ciextern int panic_on_kmsan;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * KMSAN performs a lot of consistency checks that are currently enabled by
4262306a36Sopenharmony_ci * default. BUG_ON is normally discouraged in the kernel, unless used for
4362306a36Sopenharmony_ci * debugging, but KMSAN itself is a debugging tool, so it makes little sense to
4462306a36Sopenharmony_ci * recover if something goes wrong.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ci#define KMSAN_WARN_ON(cond)                                           \
4762306a36Sopenharmony_ci	({                                                            \
4862306a36Sopenharmony_ci		const bool __cond = WARN_ON(cond);                    \
4962306a36Sopenharmony_ci		if (unlikely(__cond)) {                               \
5062306a36Sopenharmony_ci			WRITE_ONCE(kmsan_enabled, false);             \
5162306a36Sopenharmony_ci			if (panic_on_kmsan) {                         \
5262306a36Sopenharmony_ci				/* Can't call panic() here because */ \
5362306a36Sopenharmony_ci				/* of uaccess checks. */              \
5462306a36Sopenharmony_ci				BUG();                                \
5562306a36Sopenharmony_ci			}                                             \
5662306a36Sopenharmony_ci		}                                                     \
5762306a36Sopenharmony_ci		__cond;                                               \
5862306a36Sopenharmony_ci	})
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*
6162306a36Sopenharmony_ci * A pair of metadata pointers to be returned by the instrumentation functions.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistruct shadow_origin_ptr {
6462306a36Sopenharmony_ci	void *shadow, *origin;
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct shadow_origin_ptr kmsan_get_shadow_origin_ptr(void *addr, u64 size,
6862306a36Sopenharmony_ci						     bool store);
6962306a36Sopenharmony_civoid *kmsan_get_metadata(void *addr, bool is_origin);
7062306a36Sopenharmony_civoid __init kmsan_init_alloc_meta_for_range(void *start, void *end);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cienum kmsan_bug_reason {
7362306a36Sopenharmony_ci	REASON_ANY,
7462306a36Sopenharmony_ci	REASON_COPY_TO_USER,
7562306a36Sopenharmony_ci	REASON_SUBMIT_URB,
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_civoid kmsan_print_origin(depot_stack_handle_t origin);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/**
8162306a36Sopenharmony_ci * kmsan_report() - Report a use of uninitialized value.
8262306a36Sopenharmony_ci * @origin:    Stack ID of the uninitialized value.
8362306a36Sopenharmony_ci * @address:   Address at which the memory access happens.
8462306a36Sopenharmony_ci * @size:      Memory access size.
8562306a36Sopenharmony_ci * @off_first: Offset (from @address) of the first byte to be reported.
8662306a36Sopenharmony_ci * @off_last:  Offset (from @address) of the last byte to be reported.
8762306a36Sopenharmony_ci * @user_addr: When non-NULL, denotes the userspace address to which the kernel
8862306a36Sopenharmony_ci *             is leaking data.
8962306a36Sopenharmony_ci * @reason:    Error type from enum kmsan_bug_reason.
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * kmsan_report() prints an error message for a consequent group of bytes
9262306a36Sopenharmony_ci * sharing the same origin. If an uninitialized value is used in a comparison,
9362306a36Sopenharmony_ci * this function is called once without specifying the addresses. When checking
9462306a36Sopenharmony_ci * a memory range, KMSAN may call kmsan_report() multiple times with the same
9562306a36Sopenharmony_ci * @address, @size, @user_addr and @reason, but different @off_first and
9662306a36Sopenharmony_ci * @off_last corresponding to different @origin values.
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_civoid kmsan_report(depot_stack_handle_t origin, void *address, int size,
9962306a36Sopenharmony_ci		  int off_first, int off_last, const void *user_addr,
10062306a36Sopenharmony_ci		  enum kmsan_bug_reason reason);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciDECLARE_PER_CPU(struct kmsan_ctx, kmsan_percpu_ctx);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic __always_inline struct kmsan_ctx *kmsan_get_context(void)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	return in_task() ? &current->kmsan_ctx : raw_cpu_ptr(&kmsan_percpu_ctx);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/*
11062306a36Sopenharmony_ci * When a compiler hook or KMSAN runtime function is invoked, it may make a
11162306a36Sopenharmony_ci * call to instrumented code and eventually call itself recursively. To avoid
11262306a36Sopenharmony_ci * that, we guard the runtime entry regions with
11362306a36Sopenharmony_ci * kmsan_enter_runtime()/kmsan_leave_runtime() and exit the hook if
11462306a36Sopenharmony_ci * kmsan_in_runtime() is true.
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * Non-runtime code may occasionally get executed in nested IRQs from the
11762306a36Sopenharmony_ci * runtime code (e.g. when called via smp_call_function_single()). Because some
11862306a36Sopenharmony_ci * KMSAN routines may take locks (e.g. for memory allocation), we conservatively
11962306a36Sopenharmony_ci * bail out instead of calling them. To minimize the effect of this (potentially
12062306a36Sopenharmony_ci * missing initialization events) kmsan_in_runtime() is not checked in
12162306a36Sopenharmony_ci * non-blocking runtime functions.
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_cistatic __always_inline bool kmsan_in_runtime(void)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	if ((hardirq_count() >> HARDIRQ_SHIFT) > 1)
12662306a36Sopenharmony_ci		return true;
12762306a36Sopenharmony_ci	if (in_nmi())
12862306a36Sopenharmony_ci		return true;
12962306a36Sopenharmony_ci	return kmsan_get_context()->kmsan_in_runtime;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic __always_inline void kmsan_enter_runtime(void)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct kmsan_ctx *ctx;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	ctx = kmsan_get_context();
13762306a36Sopenharmony_ci	KMSAN_WARN_ON(ctx->kmsan_in_runtime++);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic __always_inline void kmsan_leave_runtime(void)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct kmsan_ctx *ctx = kmsan_get_context();
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	KMSAN_WARN_ON(--ctx->kmsan_in_runtime);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cidepot_stack_handle_t kmsan_save_stack(void);
14862306a36Sopenharmony_cidepot_stack_handle_t kmsan_save_stack_with_flags(gfp_t flags,
14962306a36Sopenharmony_ci						 unsigned int extra_bits);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/*
15262306a36Sopenharmony_ci * Pack and unpack the origin chain depth and UAF flag to/from the extra bits
15362306a36Sopenharmony_ci * provided by the stack depot.
15462306a36Sopenharmony_ci * The UAF flag is stored in the lowest bit, followed by the depth in the upper
15562306a36Sopenharmony_ci * bits.
15662306a36Sopenharmony_ci * set_dsh_extra_bits() is responsible for clamping the value.
15762306a36Sopenharmony_ci */
15862306a36Sopenharmony_cistatic __always_inline unsigned int kmsan_extra_bits(unsigned int depth,
15962306a36Sopenharmony_ci						     bool uaf)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	return (depth << 1) | uaf;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic __always_inline bool kmsan_uaf_from_eb(unsigned int extra_bits)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	return extra_bits & 1;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic __always_inline unsigned int kmsan_depth_from_eb(unsigned int extra_bits)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	return extra_bits >> 1;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * kmsan_internal_ functions are supposed to be very simple and not require the
17662306a36Sopenharmony_ci * kmsan_in_runtime() checks.
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_civoid kmsan_internal_memmove_metadata(void *dst, void *src, size_t n);
17962306a36Sopenharmony_civoid kmsan_internal_poison_memory(void *address, size_t size, gfp_t flags,
18062306a36Sopenharmony_ci				  unsigned int poison_flags);
18162306a36Sopenharmony_civoid kmsan_internal_unpoison_memory(void *address, size_t size, bool checked);
18262306a36Sopenharmony_civoid kmsan_internal_set_shadow_origin(void *address, size_t size, int b,
18362306a36Sopenharmony_ci				      u32 origin, bool checked);
18462306a36Sopenharmony_cidepot_stack_handle_t kmsan_internal_chain_origin(depot_stack_handle_t id);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_civoid kmsan_internal_task_create(struct task_struct *task);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cibool kmsan_metadata_is_contiguous(void *addr, size_t size);
18962306a36Sopenharmony_civoid kmsan_internal_check_memory(void *addr, size_t size, const void *user_addr,
19062306a36Sopenharmony_ci				 int reason);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistruct page *kmsan_vmalloc_to_page_or_null(void *vaddr);
19362306a36Sopenharmony_civoid kmsan_setup_meta(struct page *page, struct page *shadow,
19462306a36Sopenharmony_ci		      struct page *origin, int order);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/*
19762306a36Sopenharmony_ci * kmsan_internal_is_module_addr() and kmsan_internal_is_vmalloc_addr() are
19862306a36Sopenharmony_ci * non-instrumented versions of is_module_address() and is_vmalloc_addr() that
19962306a36Sopenharmony_ci * are safe to call from KMSAN runtime without recursion.
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_cistatic inline bool kmsan_internal_is_module_addr(void *vaddr)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	return ((u64)vaddr >= MODULES_VADDR) && ((u64)vaddr < MODULES_END);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic inline bool kmsan_internal_is_vmalloc_addr(void *addr)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	return ((u64)addr >= VMALLOC_START) && ((u64)addr < VMALLOC_END);
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci#endif /* __MM_KMSAN_KMSAN_H */
212