jump_label.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * jump label x86 support
  4. *
  5. * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
  6. *
  7. */
  8. #include <linux/jump_label.h>
  9. #include <linux/memory.h>
  10. #include <linux/uaccess.h>
  11. #include <linux/module.h>
  12. #include <linux/list.h>
  13. #include <linux/jhash.h>
  14. #include <linux/cpu.h>
  15. #include <asm/kprobes.h>
  16. #include <asm/alternative.h>
  17. #include <asm/text-patching.h>
  18. #ifdef HAVE_JUMP_LABEL
  19. union jump_code_union {
  20. char code[JUMP_LABEL_NOP_SIZE];
  21. struct {
  22. char jump;
  23. int offset;
  24. } __attribute__((packed));
  25. };
  26. static void bug_at(unsigned char *ip, int line)
  27. {
  28. /*
  29. * The location is not an op that we were expecting.
  30. * Something went wrong. Crash the box, as something could be
  31. * corrupting the kernel.
  32. */
  33. pr_crit("jump_label: Fatal kernel bug, unexpected op at %pS [%p] (%5ph) %d\n", ip, ip, ip, line);
  34. BUG();
  35. }
  36. static void __ref __jump_label_transform(struct jump_entry *entry,
  37. enum jump_label_type type,
  38. void *(*poker)(void *, const void *, size_t),
  39. int init)
  40. {
  41. union jump_code_union jmp;
  42. const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
  43. const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
  44. const void *expect, *code;
  45. int line;
  46. jmp.jump = 0xe9;
  47. jmp.offset = jump_entry_target(entry) -
  48. (jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE);
  49. if (early_boot_irqs_disabled)
  50. poker = text_poke_early;
  51. if (type == JUMP_LABEL_JMP) {
  52. if (init) {
  53. expect = default_nop; line = __LINE__;
  54. } else {
  55. expect = ideal_nop; line = __LINE__;
  56. }
  57. code = &jmp.code;
  58. } else {
  59. if (init) {
  60. expect = default_nop; line = __LINE__;
  61. } else {
  62. expect = &jmp.code; line = __LINE__;
  63. }
  64. code = ideal_nop;
  65. }
  66. if (memcmp((void *)jump_entry_code(entry), expect, JUMP_LABEL_NOP_SIZE))
  67. bug_at((void *)jump_entry_code(entry), line);
  68. /*
  69. * Make text_poke_bp() a default fallback poker.
  70. *
  71. * At the time the change is being done, just ignore whether we
  72. * are doing nop -> jump or jump -> nop transition, and assume
  73. * always nop being the 'currently valid' instruction
  74. *
  75. */
  76. if (poker) {
  77. (*poker)((void *)jump_entry_code(entry), code,
  78. JUMP_LABEL_NOP_SIZE);
  79. return;
  80. }
  81. text_poke_bp((void *)jump_entry_code(entry), code, JUMP_LABEL_NOP_SIZE,
  82. (void *)jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE);
  83. }
  84. void arch_jump_label_transform(struct jump_entry *entry,
  85. enum jump_label_type type)
  86. {
  87. mutex_lock(&text_mutex);
  88. __jump_label_transform(entry, type, NULL, 0);
  89. mutex_unlock(&text_mutex);
  90. }
  91. static enum {
  92. JL_STATE_START,
  93. JL_STATE_NO_UPDATE,
  94. JL_STATE_UPDATE,
  95. } jlstate __initdata_or_module = JL_STATE_START;
  96. __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry,
  97. enum jump_label_type type)
  98. {
  99. /*
  100. * This function is called at boot up and when modules are
  101. * first loaded. Check if the default nop, the one that is
  102. * inserted at compile time, is the ideal nop. If it is, then
  103. * we do not need to update the nop, and we can leave it as is.
  104. * If it is not, then we need to update the nop to the ideal nop.
  105. */
  106. if (jlstate == JL_STATE_START) {
  107. const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
  108. const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
  109. if (memcmp(ideal_nop, default_nop, 5) != 0)
  110. jlstate = JL_STATE_UPDATE;
  111. else
  112. jlstate = JL_STATE_NO_UPDATE;
  113. }
  114. if (jlstate == JL_STATE_UPDATE)
  115. __jump_label_transform(entry, type, text_poke_early, 1);
  116. }
  117. #endif