162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This implements the various checks for CONFIG_HARDENED_USERCOPY*, 462306a36Sopenharmony_ci * which are designed to protect kernel memory from needless exposure 562306a36Sopenharmony_ci * and overwrite under many unintended conditions. This code is based 662306a36Sopenharmony_ci * on PAX_USERCOPY, which is: 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 2001-2016 PaX Team, Bradley Spengler, Open Source 962306a36Sopenharmony_ci * Security Inc. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/mm.h> 1462306a36Sopenharmony_ci#include <linux/highmem.h> 1562306a36Sopenharmony_ci#include <linux/kstrtox.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/sched.h> 1862306a36Sopenharmony_ci#include <linux/sched/task.h> 1962306a36Sopenharmony_ci#include <linux/sched/task_stack.h> 2062306a36Sopenharmony_ci#include <linux/thread_info.h> 2162306a36Sopenharmony_ci#include <linux/vmalloc.h> 2262306a36Sopenharmony_ci#include <linux/atomic.h> 2362306a36Sopenharmony_ci#include <linux/jump_label.h> 2462306a36Sopenharmony_ci#include <asm/sections.h> 2562306a36Sopenharmony_ci#include "slab.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Checks if a given pointer and length is contained by the current 2962306a36Sopenharmony_ci * stack frame (if possible). 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * Returns: 3262306a36Sopenharmony_ci * NOT_STACK: not at all on the stack 3362306a36Sopenharmony_ci * GOOD_FRAME: fully within a valid stack frame 3462306a36Sopenharmony_ci * GOOD_STACK: within the current stack (when can't frame-check exactly) 3562306a36Sopenharmony_ci * BAD_STACK: error condition (invalid stack position or bad stack frame) 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic noinline int check_stack_object(const void *obj, unsigned long len) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci const void * const stack = task_stack_page(current); 4062306a36Sopenharmony_ci const void * const stackend = stack + THREAD_SIZE; 4162306a36Sopenharmony_ci int ret; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Object is not on the stack at all. */ 4462306a36Sopenharmony_ci if (obj + len <= stack || stackend <= obj) 4562306a36Sopenharmony_ci return NOT_STACK; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* 4862306a36Sopenharmony_ci * Reject: object partially overlaps the stack (passing the 4962306a36Sopenharmony_ci * check above means at least one end is within the stack, 5062306a36Sopenharmony_ci * so if this check fails, the other end is outside the stack). 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci if (obj < stack || stackend < obj + len) 5362306a36Sopenharmony_ci return BAD_STACK; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Check if object is safely within a valid frame. */ 5662306a36Sopenharmony_ci ret = arch_within_stack_frames(stack, stackend, obj, len); 5762306a36Sopenharmony_ci if (ret) 5862306a36Sopenharmony_ci return ret; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* Finally, check stack depth if possible. */ 6162306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_CURRENT_STACK_POINTER 6262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_STACK_GROWSUP)) { 6362306a36Sopenharmony_ci if ((void *)current_stack_pointer < obj + len) 6462306a36Sopenharmony_ci return BAD_STACK; 6562306a36Sopenharmony_ci } else { 6662306a36Sopenharmony_ci if (obj < (void *)current_stack_pointer) 6762306a36Sopenharmony_ci return BAD_STACK; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return GOOD_STACK; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * If these functions are reached, then CONFIG_HARDENED_USERCOPY has found 7662306a36Sopenharmony_ci * an unexpected state during a copy_from_user() or copy_to_user() call. 7762306a36Sopenharmony_ci * There are several checks being performed on the buffer by the 7862306a36Sopenharmony_ci * __check_object_size() function. Normal stack buffer usage should never 7962306a36Sopenharmony_ci * trip the checks, and kernel text addressing will always trip the check. 8062306a36Sopenharmony_ci * For cache objects, it is checking that only the whitelisted range of 8162306a36Sopenharmony_ci * bytes for a given cache is being accessed (via the cache's usersize and 8262306a36Sopenharmony_ci * useroffset fields). To adjust a cache whitelist, use the usercopy-aware 8362306a36Sopenharmony_ci * kmem_cache_create_usercopy() function to create the cache (and 8462306a36Sopenharmony_ci * carefully audit the whitelist range). 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_civoid __noreturn usercopy_abort(const char *name, const char *detail, 8762306a36Sopenharmony_ci bool to_user, unsigned long offset, 8862306a36Sopenharmony_ci unsigned long len) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci pr_emerg("Kernel memory %s attempt detected %s %s%s%s%s (offset %lu, size %lu)!\n", 9162306a36Sopenharmony_ci to_user ? "exposure" : "overwrite", 9262306a36Sopenharmony_ci to_user ? "from" : "to", 9362306a36Sopenharmony_ci name ? : "unknown?!", 9462306a36Sopenharmony_ci detail ? " '" : "", detail ? : "", detail ? "'" : "", 9562306a36Sopenharmony_ci offset, len); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * For greater effect, it would be nice to do do_group_exit(), 9962306a36Sopenharmony_ci * but BUG() actually hooks all the lock-breaking and per-arch 10062306a36Sopenharmony_ci * Oops code, so that is used here instead. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci BUG(); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* Returns true if any portion of [ptr,ptr+n) over laps with [low,high). */ 10662306a36Sopenharmony_cistatic bool overlaps(const unsigned long ptr, unsigned long n, 10762306a36Sopenharmony_ci unsigned long low, unsigned long high) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci const unsigned long check_low = ptr; 11062306a36Sopenharmony_ci unsigned long check_high = check_low + n; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Does not overlap if entirely above or entirely below. */ 11362306a36Sopenharmony_ci if (check_low >= high || check_high <= low) 11462306a36Sopenharmony_ci return false; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return true; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* Is this address range in the kernel text area? */ 12062306a36Sopenharmony_cistatic inline void check_kernel_text_object(const unsigned long ptr, 12162306a36Sopenharmony_ci unsigned long n, bool to_user) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci unsigned long textlow = (unsigned long)_stext; 12462306a36Sopenharmony_ci unsigned long texthigh = (unsigned long)_etext; 12562306a36Sopenharmony_ci unsigned long textlow_linear, texthigh_linear; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (overlaps(ptr, n, textlow, texthigh)) 12862306a36Sopenharmony_ci usercopy_abort("kernel text", NULL, to_user, ptr - textlow, n); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * Some architectures have virtual memory mappings with a secondary 13262306a36Sopenharmony_ci * mapping of the kernel text, i.e. there is more than one virtual 13362306a36Sopenharmony_ci * kernel address that points to the kernel image. It is usually 13462306a36Sopenharmony_ci * when there is a separate linear physical memory mapping, in that 13562306a36Sopenharmony_ci * __pa() is not just the reverse of __va(). This can be detected 13662306a36Sopenharmony_ci * and checked: 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci textlow_linear = (unsigned long)lm_alias(textlow); 13962306a36Sopenharmony_ci /* No different mapping: we're done. */ 14062306a36Sopenharmony_ci if (textlow_linear == textlow) 14162306a36Sopenharmony_ci return; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Check the secondary mapping... */ 14462306a36Sopenharmony_ci texthigh_linear = (unsigned long)lm_alias(texthigh); 14562306a36Sopenharmony_ci if (overlaps(ptr, n, textlow_linear, texthigh_linear)) 14662306a36Sopenharmony_ci usercopy_abort("linear kernel text", NULL, to_user, 14762306a36Sopenharmony_ci ptr - textlow_linear, n); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic inline void check_bogus_address(const unsigned long ptr, unsigned long n, 15162306a36Sopenharmony_ci bool to_user) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci /* Reject if object wraps past end of memory. */ 15462306a36Sopenharmony_ci if (ptr + (n - 1) < ptr) 15562306a36Sopenharmony_ci usercopy_abort("wrapped address", NULL, to_user, 0, ptr + n); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Reject if NULL or ZERO-allocation. */ 15862306a36Sopenharmony_ci if (ZERO_OR_NULL_PTR(ptr)) 15962306a36Sopenharmony_ci usercopy_abort("null address", NULL, to_user, ptr, n); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic inline void check_heap_object(const void *ptr, unsigned long n, 16362306a36Sopenharmony_ci bool to_user) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci unsigned long addr = (unsigned long)ptr; 16662306a36Sopenharmony_ci unsigned long offset; 16762306a36Sopenharmony_ci struct folio *folio; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (is_kmap_addr(ptr)) { 17062306a36Sopenharmony_ci offset = offset_in_page(ptr); 17162306a36Sopenharmony_ci if (n > PAGE_SIZE - offset) 17262306a36Sopenharmony_ci usercopy_abort("kmap", NULL, to_user, offset, n); 17362306a36Sopenharmony_ci return; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (is_vmalloc_addr(ptr) && !pagefault_disabled()) { 17762306a36Sopenharmony_ci struct vmap_area *area = find_vmap_area(addr); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (!area) 18062306a36Sopenharmony_ci usercopy_abort("vmalloc", "no area", to_user, 0, n); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (n > area->va_end - addr) { 18362306a36Sopenharmony_ci offset = addr - area->va_start; 18462306a36Sopenharmony_ci usercopy_abort("vmalloc", NULL, to_user, offset, n); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci return; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!virt_addr_valid(ptr)) 19062306a36Sopenharmony_ci return; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci folio = virt_to_folio(ptr); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (folio_test_slab(folio)) { 19562306a36Sopenharmony_ci /* Check slab allocator for flags and size. */ 19662306a36Sopenharmony_ci __check_heap_object(ptr, n, folio_slab(folio), to_user); 19762306a36Sopenharmony_ci } else if (folio_test_large(folio)) { 19862306a36Sopenharmony_ci offset = ptr - folio_address(folio); 19962306a36Sopenharmony_ci if (n > folio_size(folio) - offset) 20062306a36Sopenharmony_ci usercopy_abort("page alloc", NULL, to_user, offset, n); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic DEFINE_STATIC_KEY_FALSE_RO(bypass_usercopy_checks); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * Validates that the given object is: 20862306a36Sopenharmony_ci * - not bogus address 20962306a36Sopenharmony_ci * - fully contained by stack (or stack frame, when available) 21062306a36Sopenharmony_ci * - fully within SLAB object (or object whitelist area, when available) 21162306a36Sopenharmony_ci * - not in kernel text 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_civoid __check_object_size(const void *ptr, unsigned long n, bool to_user) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci if (static_branch_unlikely(&bypass_usercopy_checks)) 21662306a36Sopenharmony_ci return; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* Skip all tests if size is zero. */ 21962306a36Sopenharmony_ci if (!n) 22062306a36Sopenharmony_ci return; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Check for invalid addresses. */ 22362306a36Sopenharmony_ci check_bogus_address((const unsigned long)ptr, n, to_user); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Check for bad stack object. */ 22662306a36Sopenharmony_ci switch (check_stack_object(ptr, n)) { 22762306a36Sopenharmony_ci case NOT_STACK: 22862306a36Sopenharmony_ci /* Object is not touching the current process stack. */ 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci case GOOD_FRAME: 23162306a36Sopenharmony_ci case GOOD_STACK: 23262306a36Sopenharmony_ci /* 23362306a36Sopenharmony_ci * Object is either in the correct frame (when it 23462306a36Sopenharmony_ci * is possible to check) or just generally on the 23562306a36Sopenharmony_ci * process stack (when frame checking not available). 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci return; 23862306a36Sopenharmony_ci default: 23962306a36Sopenharmony_ci usercopy_abort("process stack", NULL, to_user, 24062306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_CURRENT_STACK_POINTER 24162306a36Sopenharmony_ci IS_ENABLED(CONFIG_STACK_GROWSUP) ? 24262306a36Sopenharmony_ci ptr - (void *)current_stack_pointer : 24362306a36Sopenharmony_ci (void *)current_stack_pointer - ptr, 24462306a36Sopenharmony_ci#else 24562306a36Sopenharmony_ci 0, 24662306a36Sopenharmony_ci#endif 24762306a36Sopenharmony_ci n); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Check for bad heap object. */ 25162306a36Sopenharmony_ci check_heap_object(ptr, n, to_user); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Check for object in kernel to avoid text exposure. */ 25462306a36Sopenharmony_ci check_kernel_text_object((const unsigned long)ptr, n, to_user); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ciEXPORT_SYMBOL(__check_object_size); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic bool enable_checks __initdata = true; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int __init parse_hardened_usercopy(char *str) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci if (kstrtobool(str, &enable_checks)) 26362306a36Sopenharmony_ci pr_warn("Invalid option string for hardened_usercopy: '%s'\n", 26462306a36Sopenharmony_ci str); 26562306a36Sopenharmony_ci return 1; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci__setup("hardened_usercopy=", parse_hardened_usercopy); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int __init set_hardened_usercopy(void) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci if (enable_checks == false) 27362306a36Sopenharmony_ci static_branch_enable(&bypass_usercopy_checks); 27462306a36Sopenharmony_ci return 1; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cilate_initcall(set_hardened_usercopy); 278