execmem.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2002 Richard Henderson
  4. * Copyright (C) 2001 Rusty Russell, 2002, 2010 Rusty Russell IBM.
  5. * Copyright (C) 2023 Luis Chamberlain <mcgrof@kernel.org>
  6. * Copyright (C) 2024 Mike Rapoport IBM.
  7. */
  8. #include <linux/mm.h>
  9. #include <linux/vmalloc.h>
  10. #include <linux/execmem.h>
  11. #include <linux/moduleloader.h>
  12. static struct execmem_info *execmem_info __ro_after_init;
  13. static struct execmem_info default_execmem_info __ro_after_init;
  14. static void *__execmem_alloc(struct execmem_range *range, size_t size)
  15. {
  16. bool kasan = range->flags & EXECMEM_KASAN_SHADOW;
  17. unsigned long vm_flags = VM_FLUSH_RESET_PERMS;
  18. gfp_t gfp_flags = GFP_KERNEL | __GFP_NOWARN;
  19. unsigned long start = range->start;
  20. unsigned long end = range->end;
  21. unsigned int align = range->alignment;
  22. pgprot_t pgprot = range->pgprot;
  23. void *p;
  24. if (kasan)
  25. vm_flags |= VM_DEFER_KMEMLEAK;
  26. p = __vmalloc_node_range(size, align, start, end, gfp_flags,
  27. pgprot, vm_flags, NUMA_NO_NODE,
  28. __builtin_return_address(0));
  29. if (!p && range->fallback_start) {
  30. start = range->fallback_start;
  31. end = range->fallback_end;
  32. p = __vmalloc_node_range(size, align, start, end, gfp_flags,
  33. pgprot, vm_flags, NUMA_NO_NODE,
  34. __builtin_return_address(0));
  35. }
  36. if (!p) {
  37. pr_warn_ratelimited("execmem: unable to allocate memory\n");
  38. return NULL;
  39. }
  40. if (kasan && (kasan_alloc_module_shadow(p, size, GFP_KERNEL) < 0)) {
  41. vfree(p);
  42. return NULL;
  43. }
  44. return kasan_reset_tag(p);
  45. }
  46. void *execmem_alloc(enum execmem_type type, size_t size)
  47. {
  48. struct execmem_range *range = &execmem_info->ranges[type];
  49. return __execmem_alloc(range, size);
  50. }
  51. void execmem_free(void *ptr)
  52. {
  53. /*
  54. * This memory may be RO, and freeing RO memory in an interrupt is not
  55. * supported by vmalloc.
  56. */
  57. WARN_ON(in_interrupt());
  58. vfree(ptr);
  59. }
  60. static bool execmem_validate(struct execmem_info *info)
  61. {
  62. struct execmem_range *r = &info->ranges[EXECMEM_DEFAULT];
  63. if (!r->alignment || !r->start || !r->end || !pgprot_val(r->pgprot)) {
  64. pr_crit("Invalid parameters for execmem allocator, module loading will fail");
  65. return false;
  66. }
  67. return true;
  68. }
  69. static void execmem_init_missing(struct execmem_info *info)
  70. {
  71. struct execmem_range *default_range = &info->ranges[EXECMEM_DEFAULT];
  72. for (int i = EXECMEM_DEFAULT + 1; i < EXECMEM_TYPE_MAX; i++) {
  73. struct execmem_range *r = &info->ranges[i];
  74. if (!r->start) {
  75. if (i == EXECMEM_MODULE_DATA)
  76. r->pgprot = PAGE_KERNEL;
  77. else
  78. r->pgprot = default_range->pgprot;
  79. r->alignment = default_range->alignment;
  80. r->start = default_range->start;
  81. r->end = default_range->end;
  82. r->flags = default_range->flags;
  83. r->fallback_start = default_range->fallback_start;
  84. r->fallback_end = default_range->fallback_end;
  85. }
  86. }
  87. }
  88. struct execmem_info * __weak execmem_arch_setup(void)
  89. {
  90. return NULL;
  91. }
  92. static void __init __execmem_init(void)
  93. {
  94. struct execmem_info *info = execmem_arch_setup();
  95. if (!info) {
  96. info = execmem_info = &default_execmem_info;
  97. info->ranges[EXECMEM_DEFAULT].start = VMALLOC_START;
  98. info->ranges[EXECMEM_DEFAULT].end = VMALLOC_END;
  99. info->ranges[EXECMEM_DEFAULT].pgprot = PAGE_KERNEL_EXEC;
  100. info->ranges[EXECMEM_DEFAULT].alignment = 1;
  101. }
  102. if (!execmem_validate(info))
  103. return;
  104. execmem_init_missing(info);
  105. execmem_info = info;
  106. }
  107. #ifdef CONFIG_ARCH_WANTS_EXECMEM_LATE
  108. static int __init execmem_late_init(void)
  109. {
  110. __execmem_init();
  111. return 0;
  112. }
  113. core_initcall(execmem_late_init);
  114. #else
  115. void __init execmem_init(void)
  116. {
  117. __execmem_init();
  118. }
  119. #endif