123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- // SPDX-License-Identifier: GPL-2.0-only
- // Copyright 2022 Google LLC
- // Author: Ard Biesheuvel <[email protected]>
- // NOTE: code in this file runs *very* early, and is not permitted to use
- // global variables or anything that relies on absolute addressing.
- #include <linux/libfdt.h>
- #include <linux/init.h>
- #include <linux/linkage.h>
- #include <linux/types.h>
- #include <linux/sizes.h>
- #include <linux/string.h>
- #include <asm/archrandom.h>
- #include <asm/memory.h>
- /* taken from lib/string.c */
- static char *__strstr(const char *s1, const char *s2)
- {
- size_t l1, l2;
- l2 = strlen(s2);
- if (!l2)
- return (char *)s1;
- l1 = strlen(s1);
- while (l1 >= l2) {
- l1--;
- if (!memcmp(s1, s2, l2))
- return (char *)s1;
- s1++;
- }
- return NULL;
- }
- static bool cmdline_contains_nokaslr(const u8 *cmdline)
- {
- const u8 *str;
- str = __strstr(cmdline, "nokaslr");
- return str == cmdline || (str > cmdline && *(str - 1) == ' ');
- }
- static bool is_kaslr_disabled_cmdline(void *fdt)
- {
- if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
- int node;
- const u8 *prop;
- node = fdt_path_offset(fdt, "/chosen");
- if (node < 0)
- goto out;
- prop = fdt_getprop(fdt, node, "bootargs", NULL);
- if (!prop)
- goto out;
- if (cmdline_contains_nokaslr(prop))
- return true;
- if (IS_ENABLED(CONFIG_CMDLINE_EXTEND))
- goto out;
- return false;
- }
- out:
- return cmdline_contains_nokaslr(CONFIG_CMDLINE);
- }
- static u64 get_kaslr_seed(void *fdt)
- {
- int node, len;
- fdt64_t *prop;
- u64 ret;
- node = fdt_path_offset(fdt, "/chosen");
- if (node < 0)
- return 0;
- prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
- if (!prop || len != sizeof(u64))
- return 0;
- ret = fdt64_to_cpu(*prop);
- *prop = 0;
- return ret;
- }
- asmlinkage u64 kaslr_early_init(void *fdt)
- {
- u64 seed;
- if (is_kaslr_disabled_cmdline(fdt))
- return 0;
- seed = get_kaslr_seed(fdt);
- if (!seed) {
- if (!__early_cpu_has_rndr() ||
- !__arm64_rndr((unsigned long *)&seed))
- return 0;
- }
- /*
- * OK, so we are proceeding with KASLR enabled. Calculate a suitable
- * kernel image offset from the seed. Let's place the kernel in the
- * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of
- * the lower and upper quarters to avoid colliding with other
- * allocations.
- */
- return BIT(VA_BITS_MIN - 3) + (seed & GENMASK(VA_BITS_MIN - 3, 0));
- }
|