kaslr_early.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright 2022 Google LLC
  3. // Author: Ard Biesheuvel <[email protected]>
  4. // NOTE: code in this file runs *very* early, and is not permitted to use
  5. // global variables or anything that relies on absolute addressing.
  6. #include <linux/libfdt.h>
  7. #include <linux/init.h>
  8. #include <linux/linkage.h>
  9. #include <linux/types.h>
  10. #include <linux/sizes.h>
  11. #include <linux/string.h>
  12. #include <asm/archrandom.h>
  13. #include <asm/memory.h>
  14. /* taken from lib/string.c */
  15. static char *__strstr(const char *s1, const char *s2)
  16. {
  17. size_t l1, l2;
  18. l2 = strlen(s2);
  19. if (!l2)
  20. return (char *)s1;
  21. l1 = strlen(s1);
  22. while (l1 >= l2) {
  23. l1--;
  24. if (!memcmp(s1, s2, l2))
  25. return (char *)s1;
  26. s1++;
  27. }
  28. return NULL;
  29. }
  30. static bool cmdline_contains_nokaslr(const u8 *cmdline)
  31. {
  32. const u8 *str;
  33. str = __strstr(cmdline, "nokaslr");
  34. return str == cmdline || (str > cmdline && *(str - 1) == ' ');
  35. }
  36. static bool is_kaslr_disabled_cmdline(void *fdt)
  37. {
  38. if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
  39. int node;
  40. const u8 *prop;
  41. node = fdt_path_offset(fdt, "/chosen");
  42. if (node < 0)
  43. goto out;
  44. prop = fdt_getprop(fdt, node, "bootargs", NULL);
  45. if (!prop)
  46. goto out;
  47. if (cmdline_contains_nokaslr(prop))
  48. return true;
  49. if (IS_ENABLED(CONFIG_CMDLINE_EXTEND))
  50. goto out;
  51. return false;
  52. }
  53. out:
  54. return cmdline_contains_nokaslr(CONFIG_CMDLINE);
  55. }
  56. static u64 get_kaslr_seed(void *fdt)
  57. {
  58. int node, len;
  59. fdt64_t *prop;
  60. u64 ret;
  61. node = fdt_path_offset(fdt, "/chosen");
  62. if (node < 0)
  63. return 0;
  64. prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
  65. if (!prop || len != sizeof(u64))
  66. return 0;
  67. ret = fdt64_to_cpu(*prop);
  68. *prop = 0;
  69. return ret;
  70. }
  71. asmlinkage u64 kaslr_early_init(void *fdt)
  72. {
  73. u64 seed;
  74. if (is_kaslr_disabled_cmdline(fdt))
  75. return 0;
  76. seed = get_kaslr_seed(fdt);
  77. if (!seed) {
  78. if (!__early_cpu_has_rndr() ||
  79. !__arm64_rndr((unsigned long *)&seed))
  80. return 0;
  81. }
  82. /*
  83. * OK, so we are proceeding with KASLR enabled. Calculate a suitable
  84. * kernel image offset from the seed. Let's place the kernel in the
  85. * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of
  86. * the lower and upper quarters to avoid colliding with other
  87. * allocations.
  88. */
  89. return BIT(VA_BITS_MIN - 3) + (seed & GENMASK(VA_BITS_MIN - 3, 0));
  90. }