18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This implements the various checks for CONFIG_HARDENED_USERCOPY*, 48c2ecf20Sopenharmony_ci * which are designed to protect kernel memory from needless exposure 58c2ecf20Sopenharmony_ci * and overwrite under many unintended conditions. This code is based 68c2ecf20Sopenharmony_ci * on PAX_USERCOPY, which is: 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2001-2016 PaX Team, Bradley Spengler, Open Source 98c2ecf20Sopenharmony_ci * Security Inc. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/highmem.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/sched/task.h> 188c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h> 198c2ecf20Sopenharmony_ci#include <linux/thread_info.h> 208c2ecf20Sopenharmony_ci#include <linux/atomic.h> 218c2ecf20Sopenharmony_ci#include <linux/jump_label.h> 228c2ecf20Sopenharmony_ci#include <asm/sections.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Checks if a given pointer and length is contained by the current 268c2ecf20Sopenharmony_ci * stack frame (if possible). 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * Returns: 298c2ecf20Sopenharmony_ci * NOT_STACK: not at all on the stack 308c2ecf20Sopenharmony_ci * GOOD_FRAME: fully within a valid stack frame 318c2ecf20Sopenharmony_ci * GOOD_STACK: fully on the stack (when can't do frame-checking) 328c2ecf20Sopenharmony_ci * BAD_STACK: error condition (invalid stack position or bad stack frame) 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic noinline int check_stack_object(const void *obj, unsigned long len) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci const void * const stack = task_stack_page(current); 378c2ecf20Sopenharmony_ci const void * const stackend = stack + THREAD_SIZE; 388c2ecf20Sopenharmony_ci int ret; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* Object is not on the stack at all. */ 418c2ecf20Sopenharmony_ci if (obj + len <= stack || stackend <= obj) 428c2ecf20Sopenharmony_ci return NOT_STACK; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* 458c2ecf20Sopenharmony_ci * Reject: object partially overlaps the stack (passing the 468c2ecf20Sopenharmony_ci * check above means at least one end is within the stack, 478c2ecf20Sopenharmony_ci * so if this check fails, the other end is outside the stack). 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci if (obj < stack || stackend < obj + len) 508c2ecf20Sopenharmony_ci return BAD_STACK; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Check if object is safely within a valid frame. */ 538c2ecf20Sopenharmony_ci ret = arch_within_stack_frames(stack, stackend, obj, len); 548c2ecf20Sopenharmony_ci if (ret) 558c2ecf20Sopenharmony_ci return ret; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return GOOD_STACK; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * If these functions are reached, then CONFIG_HARDENED_USERCOPY has found 628c2ecf20Sopenharmony_ci * an unexpected state during a copy_from_user() or copy_to_user() call. 638c2ecf20Sopenharmony_ci * There are several checks being performed on the buffer by the 648c2ecf20Sopenharmony_ci * __check_object_size() function. Normal stack buffer usage should never 658c2ecf20Sopenharmony_ci * trip the checks, and kernel text addressing will always trip the check. 668c2ecf20Sopenharmony_ci * For cache objects, it is checking that only the whitelisted range of 678c2ecf20Sopenharmony_ci * bytes for a given cache is being accessed (via the cache's usersize and 688c2ecf20Sopenharmony_ci * useroffset fields). To adjust a cache whitelist, use the usercopy-aware 698c2ecf20Sopenharmony_ci * kmem_cache_create_usercopy() function to create the cache (and 708c2ecf20Sopenharmony_ci * carefully audit the whitelist range). 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_civoid usercopy_warn(const char *name, const char *detail, bool to_user, 738c2ecf20Sopenharmony_ci unsigned long offset, unsigned long len) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci WARN_ONCE(1, "Bad or missing usercopy whitelist? Kernel memory %s attempt detected %s %s%s%s%s (offset %lu, size %lu)!\n", 768c2ecf20Sopenharmony_ci to_user ? "exposure" : "overwrite", 778c2ecf20Sopenharmony_ci to_user ? "from" : "to", 788c2ecf20Sopenharmony_ci name ? : "unknown?!", 798c2ecf20Sopenharmony_ci detail ? " '" : "", detail ? : "", detail ? "'" : "", 808c2ecf20Sopenharmony_ci offset, len); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid __noreturn usercopy_abort(const char *name, const char *detail, 848c2ecf20Sopenharmony_ci bool to_user, unsigned long offset, 858c2ecf20Sopenharmony_ci unsigned long len) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci pr_emerg("Kernel memory %s attempt detected %s %s%s%s%s (offset %lu, size %lu)!\n", 888c2ecf20Sopenharmony_ci to_user ? "exposure" : "overwrite", 898c2ecf20Sopenharmony_ci to_user ? "from" : "to", 908c2ecf20Sopenharmony_ci name ? : "unknown?!", 918c2ecf20Sopenharmony_ci detail ? " '" : "", detail ? : "", detail ? "'" : "", 928c2ecf20Sopenharmony_ci offset, len); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * For greater effect, it would be nice to do do_group_exit(), 968c2ecf20Sopenharmony_ci * but BUG() actually hooks all the lock-breaking and per-arch 978c2ecf20Sopenharmony_ci * Oops code, so that is used here instead. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci BUG(); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* Returns true if any portion of [ptr,ptr+n) over laps with [low,high). */ 1038c2ecf20Sopenharmony_cistatic bool overlaps(const unsigned long ptr, unsigned long n, 1048c2ecf20Sopenharmony_ci unsigned long low, unsigned long high) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci const unsigned long check_low = ptr; 1078c2ecf20Sopenharmony_ci unsigned long check_high = check_low + n; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Does not overlap if entirely above or entirely below. */ 1108c2ecf20Sopenharmony_ci if (check_low >= high || check_high <= low) 1118c2ecf20Sopenharmony_ci return false; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return true; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* Is this address range in the kernel text area? */ 1178c2ecf20Sopenharmony_cistatic inline void check_kernel_text_object(const unsigned long ptr, 1188c2ecf20Sopenharmony_ci unsigned long n, bool to_user) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci unsigned long textlow = (unsigned long)_stext; 1218c2ecf20Sopenharmony_ci unsigned long texthigh = (unsigned long)_etext; 1228c2ecf20Sopenharmony_ci unsigned long textlow_linear, texthigh_linear; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (overlaps(ptr, n, textlow, texthigh)) 1258c2ecf20Sopenharmony_ci usercopy_abort("kernel text", NULL, to_user, ptr - textlow, n); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * Some architectures have virtual memory mappings with a secondary 1298c2ecf20Sopenharmony_ci * mapping of the kernel text, i.e. there is more than one virtual 1308c2ecf20Sopenharmony_ci * kernel address that points to the kernel image. It is usually 1318c2ecf20Sopenharmony_ci * when there is a separate linear physical memory mapping, in that 1328c2ecf20Sopenharmony_ci * __pa() is not just the reverse of __va(). This can be detected 1338c2ecf20Sopenharmony_ci * and checked: 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci textlow_linear = (unsigned long)lm_alias(textlow); 1368c2ecf20Sopenharmony_ci /* No different mapping: we're done. */ 1378c2ecf20Sopenharmony_ci if (textlow_linear == textlow) 1388c2ecf20Sopenharmony_ci return; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Check the secondary mapping... */ 1418c2ecf20Sopenharmony_ci texthigh_linear = (unsigned long)lm_alias(texthigh); 1428c2ecf20Sopenharmony_ci if (overlaps(ptr, n, textlow_linear, texthigh_linear)) 1438c2ecf20Sopenharmony_ci usercopy_abort("linear kernel text", NULL, to_user, 1448c2ecf20Sopenharmony_ci ptr - textlow_linear, n); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic inline void check_bogus_address(const unsigned long ptr, unsigned long n, 1488c2ecf20Sopenharmony_ci bool to_user) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci /* Reject if object wraps past end of memory. */ 1518c2ecf20Sopenharmony_ci if (ptr + (n - 1) < ptr) 1528c2ecf20Sopenharmony_ci usercopy_abort("wrapped address", NULL, to_user, 0, ptr + n); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Reject if NULL or ZERO-allocation. */ 1558c2ecf20Sopenharmony_ci if (ZERO_OR_NULL_PTR(ptr)) 1568c2ecf20Sopenharmony_ci usercopy_abort("null address", NULL, to_user, ptr, n); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* Checks for allocs that are marked in some way as spanning multiple pages. */ 1608c2ecf20Sopenharmony_cistatic inline void check_page_span(const void *ptr, unsigned long n, 1618c2ecf20Sopenharmony_ci struct page *page, bool to_user) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci#ifdef CONFIG_HARDENED_USERCOPY_PAGESPAN 1648c2ecf20Sopenharmony_ci const void *end = ptr + n - 1; 1658c2ecf20Sopenharmony_ci struct page *endpage; 1668c2ecf20Sopenharmony_ci bool is_reserved, is_cma; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * Sometimes the kernel data regions are not marked Reserved (see 1708c2ecf20Sopenharmony_ci * check below). And sometimes [_sdata,_edata) does not cover 1718c2ecf20Sopenharmony_ci * rodata and/or bss, so check each range explicitly. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Allow reads of kernel rodata region (if not marked as Reserved). */ 1758c2ecf20Sopenharmony_ci if (ptr >= (const void *)__start_rodata && 1768c2ecf20Sopenharmony_ci end <= (const void *)__end_rodata) { 1778c2ecf20Sopenharmony_ci if (!to_user) 1788c2ecf20Sopenharmony_ci usercopy_abort("rodata", NULL, to_user, 0, n); 1798c2ecf20Sopenharmony_ci return; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Allow kernel data region (if not marked as Reserved). */ 1838c2ecf20Sopenharmony_ci if (ptr >= (const void *)_sdata && end <= (const void *)_edata) 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Allow kernel bss region (if not marked as Reserved). */ 1878c2ecf20Sopenharmony_ci if (ptr >= (const void *)__bss_start && 1888c2ecf20Sopenharmony_ci end <= (const void *)__bss_stop) 1898c2ecf20Sopenharmony_ci return; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Is the object wholly within one base page? */ 1928c2ecf20Sopenharmony_ci if (likely(((unsigned long)ptr & (unsigned long)PAGE_MASK) == 1938c2ecf20Sopenharmony_ci ((unsigned long)end & (unsigned long)PAGE_MASK))) 1948c2ecf20Sopenharmony_ci return; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Allow if fully inside the same compound (__GFP_COMP) page. */ 1978c2ecf20Sopenharmony_ci endpage = virt_to_head_page(end); 1988c2ecf20Sopenharmony_ci if (likely(endpage == page)) 1998c2ecf20Sopenharmony_ci return; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Reject if range is entirely either Reserved (i.e. special or 2038c2ecf20Sopenharmony_ci * device memory), or CMA. Otherwise, reject since the object spans 2048c2ecf20Sopenharmony_ci * several independently allocated pages. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci is_reserved = PageReserved(page); 2078c2ecf20Sopenharmony_ci is_cma = is_migrate_cma_page(page); 2088c2ecf20Sopenharmony_ci if (!is_reserved && !is_cma) 2098c2ecf20Sopenharmony_ci usercopy_abort("spans multiple pages", NULL, to_user, 0, n); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (ptr += PAGE_SIZE; ptr <= end; ptr += PAGE_SIZE) { 2128c2ecf20Sopenharmony_ci page = virt_to_head_page(ptr); 2138c2ecf20Sopenharmony_ci if (is_reserved && !PageReserved(page)) 2148c2ecf20Sopenharmony_ci usercopy_abort("spans Reserved and non-Reserved pages", 2158c2ecf20Sopenharmony_ci NULL, to_user, 0, n); 2168c2ecf20Sopenharmony_ci if (is_cma && !is_migrate_cma_page(page)) 2178c2ecf20Sopenharmony_ci usercopy_abort("spans CMA and non-CMA pages", NULL, 2188c2ecf20Sopenharmony_ci to_user, 0, n); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci#endif 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic inline void check_heap_object(const void *ptr, unsigned long n, 2248c2ecf20Sopenharmony_ci bool to_user) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct page *page; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!virt_addr_valid(ptr)) 2298c2ecf20Sopenharmony_ci return; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * When CONFIG_HIGHMEM=y, kmap_to_page() will give either the 2338c2ecf20Sopenharmony_ci * highmem page or fallback to virt_to_page(). The following 2348c2ecf20Sopenharmony_ci * is effectively a highmem-aware virt_to_head_page(). 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci page = compound_head(kmap_to_page((void *)ptr)); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (PageSlab(page)) { 2398c2ecf20Sopenharmony_ci /* Check slab allocator for flags and size. */ 2408c2ecf20Sopenharmony_ci __check_heap_object(ptr, n, page, to_user); 2418c2ecf20Sopenharmony_ci } else { 2428c2ecf20Sopenharmony_ci /* Verify object does not incorrectly span multiple pages. */ 2438c2ecf20Sopenharmony_ci check_page_span(ptr, n, page, to_user); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic DEFINE_STATIC_KEY_FALSE_RO(bypass_usercopy_checks); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* 2508c2ecf20Sopenharmony_ci * Validates that the given object is: 2518c2ecf20Sopenharmony_ci * - not bogus address 2528c2ecf20Sopenharmony_ci * - fully contained by stack (or stack frame, when available) 2538c2ecf20Sopenharmony_ci * - fully within SLAB object (or object whitelist area, when available) 2548c2ecf20Sopenharmony_ci * - not in kernel text 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_civoid __check_object_size(const void *ptr, unsigned long n, bool to_user) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci if (static_branch_unlikely(&bypass_usercopy_checks)) 2598c2ecf20Sopenharmony_ci return; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* Skip all tests if size is zero. */ 2628c2ecf20Sopenharmony_ci if (!n) 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Check for invalid addresses. */ 2668c2ecf20Sopenharmony_ci check_bogus_address((const unsigned long)ptr, n, to_user); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Check for bad stack object. */ 2698c2ecf20Sopenharmony_ci switch (check_stack_object(ptr, n)) { 2708c2ecf20Sopenharmony_ci case NOT_STACK: 2718c2ecf20Sopenharmony_ci /* Object is not touching the current process stack. */ 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci case GOOD_FRAME: 2748c2ecf20Sopenharmony_ci case GOOD_STACK: 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * Object is either in the correct frame (when it 2778c2ecf20Sopenharmony_ci * is possible to check) or just generally on the 2788c2ecf20Sopenharmony_ci * process stack (when frame checking not available). 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci return; 2818c2ecf20Sopenharmony_ci default: 2828c2ecf20Sopenharmony_ci usercopy_abort("process stack", NULL, to_user, 0, n); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Check for bad heap object. */ 2868c2ecf20Sopenharmony_ci check_heap_object(ptr, n, to_user); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Check for object in kernel to avoid text exposure. */ 2898c2ecf20Sopenharmony_ci check_kernel_text_object((const unsigned long)ptr, n, to_user); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__check_object_size); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic bool enable_checks __initdata = true; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int __init parse_hardened_usercopy(char *str) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci if (strtobool(str, &enable_checks)) 2988c2ecf20Sopenharmony_ci pr_warn("Invalid option string for hardened_usercopy: '%s'\n", 2998c2ecf20Sopenharmony_ci str); 3008c2ecf20Sopenharmony_ci return 1; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci__setup("hardened_usercopy=", parse_hardened_usercopy); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int __init set_hardened_usercopy(void) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci if (enable_checks == false) 3088c2ecf20Sopenharmony_ci static_branch_enable(&bypass_usercopy_checks); 3098c2ecf20Sopenharmony_ci return 1; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cilate_initcall(set_hardened_usercopy); 313