patch.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * functions to patch RO kernel text during runtime
  4. *
  5. * Copyright (c) 2019 Sven Schnelle <[email protected]>
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/spinlock.h>
  9. #include <linux/kprobes.h>
  10. #include <linux/mm.h>
  11. #include <linux/stop_machine.h>
  12. #include <asm/cacheflush.h>
  13. #include <asm/fixmap.h>
  14. #include <asm/patch.h>
  15. struct patch {
  16. void *addr;
  17. u32 *insn;
  18. unsigned int len;
  19. };
  20. static DEFINE_RAW_SPINLOCK(patch_lock);
  21. static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags,
  22. int *need_unmap)
  23. {
  24. unsigned long uintaddr = (uintptr_t) addr;
  25. bool module = !core_kernel_text(uintaddr);
  26. struct page *page;
  27. *need_unmap = 0;
  28. if (module && IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
  29. page = vmalloc_to_page(addr);
  30. else if (!module && IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
  31. page = virt_to_page(addr);
  32. else
  33. return addr;
  34. *need_unmap = 1;
  35. set_fixmap(fixmap, page_to_phys(page));
  36. raw_spin_lock_irqsave(&patch_lock, *flags);
  37. return (void *) (__fix_to_virt(fixmap) + (uintaddr & ~PAGE_MASK));
  38. }
  39. static void __kprobes patch_unmap(int fixmap, unsigned long *flags)
  40. {
  41. clear_fixmap(fixmap);
  42. raw_spin_unlock_irqrestore(&patch_lock, *flags);
  43. }
  44. void __kprobes __patch_text_multiple(void *addr, u32 *insn, unsigned int len)
  45. {
  46. unsigned long start = (unsigned long)addr;
  47. unsigned long end = (unsigned long)addr + len;
  48. unsigned long flags;
  49. u32 *p, *fixmap;
  50. int mapped;
  51. /* Make sure we don't have any aliases in cache */
  52. flush_kernel_dcache_range_asm(start, end);
  53. flush_kernel_icache_range_asm(start, end);
  54. flush_tlb_kernel_range(start, end);
  55. p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags, &mapped);
  56. while (len >= 4) {
  57. *p++ = *insn++;
  58. addr += sizeof(u32);
  59. len -= sizeof(u32);
  60. if (len && offset_in_page(addr) == 0) {
  61. /*
  62. * We're crossing a page boundary, so
  63. * need to remap
  64. */
  65. flush_kernel_dcache_range_asm((unsigned long)fixmap,
  66. (unsigned long)p);
  67. flush_tlb_kernel_range((unsigned long)fixmap,
  68. (unsigned long)p);
  69. if (mapped)
  70. patch_unmap(FIX_TEXT_POKE0, &flags);
  71. p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags,
  72. &mapped);
  73. }
  74. }
  75. flush_kernel_dcache_range_asm((unsigned long)fixmap, (unsigned long)p);
  76. flush_tlb_kernel_range((unsigned long)fixmap, (unsigned long)p);
  77. if (mapped)
  78. patch_unmap(FIX_TEXT_POKE0, &flags);
  79. }
  80. void __kprobes __patch_text(void *addr, u32 insn)
  81. {
  82. __patch_text_multiple(addr, &insn, sizeof(insn));
  83. }
  84. static int __kprobes patch_text_stop_machine(void *data)
  85. {
  86. struct patch *patch = data;
  87. __patch_text_multiple(patch->addr, patch->insn, patch->len);
  88. return 0;
  89. }
  90. void __kprobes patch_text(void *addr, unsigned int insn)
  91. {
  92. struct patch patch = {
  93. .addr = addr,
  94. .insn = &insn,
  95. .len = sizeof(insn),
  96. };
  97. stop_machine_cpuslocked(patch_text_stop_machine, &patch, NULL);
  98. }
  99. void __kprobes patch_text_multiple(void *addr, u32 *insn, unsigned int len)
  100. {
  101. struct patch patch = {
  102. .addr = addr,
  103. .insn = insn,
  104. .len = len
  105. };
  106. stop_machine_cpuslocked(patch_text_stop_machine, &patch, NULL);
  107. }