0001
0002
0003
0004
0005
0006
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
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
0104
0105
0106
0107
0108
0109 return BIT(VA_BITS_MIN - 3) + (seed & GENMASK(VA_BITS_MIN - 3, 0));
0110 }