1b2d24b97SGerald Schaefer // SPDX-License-Identifier: GPL-2.0 2b2d24b97SGerald Schaefer /* 3b2d24b97SGerald Schaefer * Copyright IBM Corp. 2019 4b2d24b97SGerald Schaefer */ 5ca5999fdSMike Rapoport #include <linux/pgtable.h> 665fddcfcSMike Rapoport #include <asm/mem_detect.h> 7b2d24b97SGerald Schaefer #include <asm/cpacf.h> 8b2d24b97SGerald Schaefer #include <asm/timex.h> 9b2d24b97SGerald Schaefer #include <asm/sclp.h> 10b2d24b97SGerald Schaefer #include "compressed/decompressor.h" 11868202ceSVasily Gorbik #include "boot.h" 12b2d24b97SGerald Schaefer 13b2d24b97SGerald Schaefer #define PRNG_MODE_TDES 1 14b2d24b97SGerald Schaefer #define PRNG_MODE_SHA512 2 15b2d24b97SGerald Schaefer #define PRNG_MODE_TRNG 3 16b2d24b97SGerald Schaefer 17b2d24b97SGerald Schaefer struct prno_parm { 18b2d24b97SGerald Schaefer u32 res; 19b2d24b97SGerald Schaefer u32 reseed_counter; 20b2d24b97SGerald Schaefer u64 stream_bytes; 21b2d24b97SGerald Schaefer u8 V[112]; 22b2d24b97SGerald Schaefer u8 C[112]; 23b2d24b97SGerald Schaefer }; 24b2d24b97SGerald Schaefer 25b2d24b97SGerald Schaefer struct prng_parm { 26b2d24b97SGerald Schaefer u8 parm_block[32]; 27b2d24b97SGerald Schaefer u32 reseed_counter; 28b2d24b97SGerald Schaefer u64 byte_counter; 29b2d24b97SGerald Schaefer }; 30b2d24b97SGerald Schaefer 31b2d24b97SGerald Schaefer static int check_prng(void) 32b2d24b97SGerald Schaefer { 33b2d24b97SGerald Schaefer if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG)) { 34b2d24b97SGerald Schaefer sclp_early_printk("KASLR disabled: CPU has no PRNG\n"); 35b2d24b97SGerald Schaefer return 0; 36b2d24b97SGerald Schaefer } 37b2d24b97SGerald Schaefer if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG)) 38b2d24b97SGerald Schaefer return PRNG_MODE_TRNG; 39b2d24b97SGerald Schaefer if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN)) 40b2d24b97SGerald Schaefer return PRNG_MODE_SHA512; 41b2d24b97SGerald Schaefer else 42b2d24b97SGerald Schaefer return PRNG_MODE_TDES; 43b2d24b97SGerald Schaefer } 44b2d24b97SGerald Schaefer 4507a699bcSVasily Gorbik static int get_random(unsigned long limit, unsigned long *value) 46b2d24b97SGerald Schaefer { 47b2d24b97SGerald Schaefer struct prng_parm prng = { 48b2d24b97SGerald Schaefer /* initial parameter block for tdes mode, copied from libica */ 49b2d24b97SGerald Schaefer .parm_block = { 50b2d24b97SGerald Schaefer 0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52, 51b2d24b97SGerald Schaefer 0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4, 52b2d24b97SGerald Schaefer 0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF, 53b2d24b97SGerald Schaefer 0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0 54b2d24b97SGerald Schaefer }, 55b2d24b97SGerald Schaefer }; 56b2d24b97SGerald Schaefer unsigned long seed, random; 57b2d24b97SGerald Schaefer struct prno_parm prno; 58b2d24b97SGerald Schaefer __u64 entropy[4]; 59b2d24b97SGerald Schaefer int mode, i; 60b2d24b97SGerald Schaefer 61b2d24b97SGerald Schaefer mode = check_prng(); 62b2d24b97SGerald Schaefer seed = get_tod_clock_fast(); 63b2d24b97SGerald Schaefer switch (mode) { 64b2d24b97SGerald Schaefer case PRNG_MODE_TRNG: 65b2d24b97SGerald Schaefer cpacf_trng(NULL, 0, (u8 *) &random, sizeof(random)); 66b2d24b97SGerald Schaefer break; 67b2d24b97SGerald Schaefer case PRNG_MODE_SHA512: 68b2d24b97SGerald Schaefer cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, &prno, NULL, 0, 69b2d24b97SGerald Schaefer (u8 *) &seed, sizeof(seed)); 70b2d24b97SGerald Schaefer cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, &prno, (u8 *) &random, 71b2d24b97SGerald Schaefer sizeof(random), NULL, 0); 72b2d24b97SGerald Schaefer break; 73b2d24b97SGerald Schaefer case PRNG_MODE_TDES: 74b2d24b97SGerald Schaefer /* add entropy */ 75b2d24b97SGerald Schaefer *(unsigned long *) prng.parm_block ^= seed; 76b2d24b97SGerald Schaefer for (i = 0; i < 16; i++) { 77b2d24b97SGerald Schaefer cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, 78788d6715SNathan Chancellor (u8 *) entropy, (u8 *) entropy, 79b2d24b97SGerald Schaefer sizeof(entropy)); 80b2d24b97SGerald Schaefer memcpy(prng.parm_block, entropy, sizeof(entropy)); 81b2d24b97SGerald Schaefer } 82b2d24b97SGerald Schaefer random = seed; 83b2d24b97SGerald Schaefer cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, (u8 *) &random, 84b2d24b97SGerald Schaefer (u8 *) &random, sizeof(random)); 85b2d24b97SGerald Schaefer break; 86b2d24b97SGerald Schaefer default: 8707a699bcSVasily Gorbik return -1; 88b2d24b97SGerald Schaefer } 8907a699bcSVasily Gorbik *value = random % limit; 9007a699bcSVasily Gorbik return 0; 91b2d24b97SGerald Schaefer } 92b2d24b97SGerald Schaefer 935c46f276SVasily Gorbik /* 945c46f276SVasily Gorbik * To randomize kernel base address we have to consider several facts: 955c46f276SVasily Gorbik * 1. physical online memory might not be continuous and have holes. mem_detect 965c46f276SVasily Gorbik * info contains list of online memory ranges we should consider. 975c46f276SVasily Gorbik * 2. we have several memory regions which are occupied and we should not 985c46f276SVasily Gorbik * overlap and destroy them. Currently safe_addr tells us the border below 995c46f276SVasily Gorbik * which all those occupied regions are. We are safe to use anything above 1005c46f276SVasily Gorbik * safe_addr. 1015c46f276SVasily Gorbik * 3. the upper limit might apply as well, even if memory above that limit is 1025c46f276SVasily Gorbik * online. Currently those limitations are: 1035c46f276SVasily Gorbik * 3.1. Limit set by "mem=" kernel command line option 1045c46f276SVasily Gorbik * 3.2. memory reserved at the end for kasan initialization. 1055c46f276SVasily Gorbik * 4. kernel base address must be aligned to THREAD_SIZE (kernel stack size). 1065c46f276SVasily Gorbik * Which is required for CONFIG_CHECK_STACK. Currently THREAD_SIZE is 4 pages 1075c46f276SVasily Gorbik * (16 pages when the kernel is built with kasan enabled) 1085c46f276SVasily Gorbik * Assumptions: 1095c46f276SVasily Gorbik * 1. kernel size (including .bss size) and upper memory limit are page aligned. 1105c46f276SVasily Gorbik * 2. mem_detect memory region start is THREAD_SIZE aligned / end is PAGE_SIZE 1115c46f276SVasily Gorbik * aligned (in practice memory configurations granularity on z/VM and LPAR 1125c46f276SVasily Gorbik * is 1mb). 1135c46f276SVasily Gorbik * 1145c46f276SVasily Gorbik * To guarantee uniform distribution of kernel base address among all suitable 1155c46f276SVasily Gorbik * addresses we generate random value just once. For that we need to build a 1165c46f276SVasily Gorbik * continuous range in which every value would be suitable. We can build this 1175c46f276SVasily Gorbik * range by simply counting all suitable addresses (let's call them positions) 1185c46f276SVasily Gorbik * which would be valid as kernel base address. To count positions we iterate 1195c46f276SVasily Gorbik * over online memory ranges. For each range which is big enough for the 1205c46f276SVasily Gorbik * kernel image we count all suitable addresses we can put the kernel image at 1215c46f276SVasily Gorbik * that is 1225c46f276SVasily Gorbik * (end - start - kernel_size) / THREAD_SIZE + 1 1235c46f276SVasily Gorbik * Two functions count_valid_kernel_positions and position_to_address help 1245c46f276SVasily Gorbik * to count positions in memory range given and then convert position back 1255c46f276SVasily Gorbik * to address. 1265c46f276SVasily Gorbik */ 1275c46f276SVasily Gorbik static unsigned long count_valid_kernel_positions(unsigned long kernel_size, 1285c46f276SVasily Gorbik unsigned long _min, 1295c46f276SVasily Gorbik unsigned long _max) 1305c46f276SVasily Gorbik { 1315c46f276SVasily Gorbik unsigned long start, end, pos = 0; 1325c46f276SVasily Gorbik int i; 1335c46f276SVasily Gorbik 1345c46f276SVasily Gorbik for_each_mem_detect_block(i, &start, &end) { 1355c46f276SVasily Gorbik if (_min >= end) 1365c46f276SVasily Gorbik continue; 1375c46f276SVasily Gorbik if (start >= _max) 1385c46f276SVasily Gorbik break; 1395c46f276SVasily Gorbik start = max(_min, start); 1405c46f276SVasily Gorbik end = min(_max, end); 1415c46f276SVasily Gorbik if (end - start < kernel_size) 1425c46f276SVasily Gorbik continue; 1435c46f276SVasily Gorbik pos += (end - start - kernel_size) / THREAD_SIZE + 1; 1445c46f276SVasily Gorbik } 1455c46f276SVasily Gorbik 1465c46f276SVasily Gorbik return pos; 1475c46f276SVasily Gorbik } 1485c46f276SVasily Gorbik 1495c46f276SVasily Gorbik static unsigned long position_to_address(unsigned long pos, unsigned long kernel_size, 1505c46f276SVasily Gorbik unsigned long _min, unsigned long _max) 1515c46f276SVasily Gorbik { 1525c46f276SVasily Gorbik unsigned long start, end; 1535c46f276SVasily Gorbik int i; 1545c46f276SVasily Gorbik 1555c46f276SVasily Gorbik for_each_mem_detect_block(i, &start, &end) { 1565c46f276SVasily Gorbik if (_min >= end) 1575c46f276SVasily Gorbik continue; 1585c46f276SVasily Gorbik if (start >= _max) 1595c46f276SVasily Gorbik break; 1605c46f276SVasily Gorbik start = max(_min, start); 1615c46f276SVasily Gorbik end = min(_max, end); 1625c46f276SVasily Gorbik if (end - start < kernel_size) 1635c46f276SVasily Gorbik continue; 1645c46f276SVasily Gorbik if ((end - start - kernel_size) / THREAD_SIZE + 1 >= pos) 1655c46f276SVasily Gorbik return start + (pos - 1) * THREAD_SIZE; 1665c46f276SVasily Gorbik pos -= (end - start - kernel_size) / THREAD_SIZE + 1; 1675c46f276SVasily Gorbik } 1685c46f276SVasily Gorbik 1695c46f276SVasily Gorbik return 0; 1705c46f276SVasily Gorbik } 1715c46f276SVasily Gorbik 172b2d24b97SGerald Schaefer unsigned long get_random_base(unsigned long safe_addr) 173b2d24b97SGerald Schaefer { 1745c46f276SVasily Gorbik unsigned long memory_limit = get_mem_detect_end(); 1755c46f276SVasily Gorbik unsigned long base_pos, max_pos, kernel_size; 176759d4899SVasily Gorbik unsigned long kasan_needs; 177b2d24b97SGerald Schaefer int i; 178b2d24b97SGerald Schaefer 1795c46f276SVasily Gorbik if (memory_end_set) 1805c46f276SVasily Gorbik memory_limit = min(memory_limit, memory_end); 1815c46f276SVasily Gorbik 182b2d24b97SGerald Schaefer if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE) { 183b2d24b97SGerald Schaefer if (safe_addr < INITRD_START + INITRD_SIZE) 184b2d24b97SGerald Schaefer safe_addr = INITRD_START + INITRD_SIZE; 185b2d24b97SGerald Schaefer } 186b2d24b97SGerald Schaefer safe_addr = ALIGN(safe_addr, THREAD_SIZE); 187b2d24b97SGerald Schaefer 188759d4899SVasily Gorbik if ((IS_ENABLED(CONFIG_KASAN))) { 189759d4899SVasily Gorbik /* 190759d4899SVasily Gorbik * Estimate kasan memory requirements, which it will reserve 191759d4899SVasily Gorbik * at the very end of available physical memory. To estimate 192759d4899SVasily Gorbik * that, we take into account that kasan would require 193759d4899SVasily Gorbik * 1/8 of available physical memory (for shadow memory) + 194759d4899SVasily Gorbik * creating page tables for the whole memory + shadow memory 195759d4899SVasily Gorbik * region (1 + 1/8). To keep page tables estimates simple take 196759d4899SVasily Gorbik * the double of combined ptes size. 197759d4899SVasily Gorbik */ 198759d4899SVasily Gorbik memory_limit = get_mem_detect_end(); 199759d4899SVasily Gorbik if (memory_end_set && memory_limit > memory_end) 200759d4899SVasily Gorbik memory_limit = memory_end; 201759d4899SVasily Gorbik 202759d4899SVasily Gorbik /* for shadow memory */ 203759d4899SVasily Gorbik kasan_needs = memory_limit / 8; 204759d4899SVasily Gorbik /* for paging structures */ 205759d4899SVasily Gorbik kasan_needs += (memory_limit + kasan_needs) / PAGE_SIZE / 206759d4899SVasily Gorbik _PAGE_ENTRIES * _PAGE_TABLE_SIZE * 2; 207759d4899SVasily Gorbik memory_limit -= kasan_needs; 208759d4899SVasily Gorbik } 209759d4899SVasily Gorbik 210b2d24b97SGerald Schaefer kernel_size = vmlinux.image_size + vmlinux.bss_size; 2115c46f276SVasily Gorbik if (safe_addr + kernel_size > memory_limit) 2125c46f276SVasily Gorbik return 0; 2135c46f276SVasily Gorbik 2145c46f276SVasily Gorbik max_pos = count_valid_kernel_positions(kernel_size, safe_addr, memory_limit); 2155c46f276SVasily Gorbik if (!max_pos) { 216b2d24b97SGerald Schaefer sclp_early_printk("KASLR disabled: not enough memory\n"); 217b2d24b97SGerald Schaefer return 0; 218b2d24b97SGerald Schaefer } 219b2d24b97SGerald Schaefer 2205c46f276SVasily Gorbik /* we need a value in the range [1, base_pos] inclusive */ 2215c46f276SVasily Gorbik if (get_random(max_pos, &base_pos)) 222b2d24b97SGerald Schaefer return 0; 2235c46f276SVasily Gorbik return position_to_address(base_pos + 1, kernel_size, safe_addr, memory_limit); 224b2d24b97SGerald Schaefer } 225