Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright 2022 Google LLC
0003 // Author: Ard Biesheuvel <ardb@google.com>
0004 
0005 // NOTE: code in this file runs *very* early, and is not permitted to use
0006 // global variables or anything that relies on absolute addressing.
0007 
0008 #include <linux/libfdt.h>
0009 #include <linux/init.h>
0010 #include <linux/linkage.h>
0011 #include <linux/types.h>
0012 #include <linux/sizes.h>
0013 #include <linux/string.h>
0014 
0015 #include <asm/archrandom.h>
0016 #include <asm/memory.h>
0017 
0018 /* taken from lib/string.c */
0019 static char *__strstr(const char *s1, const char *s2)
0020 {
0021     size_t l1, l2;
0022 
0023     l2 = strlen(s2);
0024     if (!l2)
0025         return (char *)s1;
0026     l1 = strlen(s1);
0027     while (l1 >= l2) {
0028         l1--;
0029         if (!memcmp(s1, s2, l2))
0030             return (char *)s1;
0031         s1++;
0032     }
0033     return NULL;
0034 }
0035 static bool cmdline_contains_nokaslr(const u8 *cmdline)
0036 {
0037     const u8 *str;
0038 
0039     str = __strstr(cmdline, "nokaslr");
0040     return str == cmdline || (str > cmdline && *(str - 1) == ' ');
0041 }
0042 
0043 static bool is_kaslr_disabled_cmdline(void *fdt)
0044 {
0045     if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
0046         int node;
0047         const u8 *prop;
0048 
0049         node = fdt_path_offset(fdt, "/chosen");
0050         if (node < 0)
0051             goto out;
0052 
0053         prop = fdt_getprop(fdt, node, "bootargs", NULL);
0054         if (!prop)
0055             goto out;
0056 
0057         if (cmdline_contains_nokaslr(prop))
0058             return true;
0059 
0060         if (IS_ENABLED(CONFIG_CMDLINE_EXTEND))
0061             goto out;
0062 
0063         return false;
0064     }
0065 out:
0066     return cmdline_contains_nokaslr(CONFIG_CMDLINE);
0067 }
0068 
0069 static u64 get_kaslr_seed(void *fdt)
0070 {
0071     int node, len;
0072     fdt64_t *prop;
0073     u64 ret;
0074 
0075     node = fdt_path_offset(fdt, "/chosen");
0076     if (node < 0)
0077         return 0;
0078 
0079     prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
0080     if (!prop || len != sizeof(u64))
0081         return 0;
0082 
0083     ret = fdt64_to_cpu(*prop);
0084     *prop = 0;
0085     return ret;
0086 }
0087 
0088 asmlinkage u64 kaslr_early_init(void *fdt)
0089 {
0090     u64 seed;
0091 
0092     if (is_kaslr_disabled_cmdline(fdt))
0093         return 0;
0094 
0095     seed = get_kaslr_seed(fdt);
0096     if (!seed) {
0097         if (!__early_cpu_has_rndr() ||
0098             !__arm64_rndr((unsigned long *)&seed))
0099             return 0;
0100     }
0101 
0102     /*
0103      * OK, so we are proceeding with KASLR enabled. Calculate a suitable
0104      * kernel image offset from the seed. Let's place the kernel in the
0105      * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of
0106      * the lower and upper quarters to avoid colliding with other
0107      * allocations.
0108      */
0109     return BIT(VA_BITS_MIN - 3) + (seed & GENMASK(VA_BITS_MIN - 3, 0));
0110 }