jump_label.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * jump label x86 support
  3. *
  4. * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
  5. *
  6. */
  7. #include <linux/jump_label.h>
  8. #include <linux/memory.h>
  9. #include <linux/uaccess.h>
  10. #include <linux/module.h>
  11. #include <linux/list.h>
  12. #include <linux/jhash.h>
  13. #include <linux/cpu.h>
  14. #include <asm/kprobes.h>
  15. #include <asm/alternative.h>
  16. #include <asm/text-patching.h>
  17. #ifdef HAVE_JUMP_LABEL
  18. union jump_code_union {
  19. char code[JUMP_LABEL_NOP_SIZE];
  20. struct {
  21. char jump;
  22. int offset;
  23. } __attribute__((packed));
  24. };
  25. static void bug_at(unsigned char *ip, int line)
  26. {
  27. /*
  28. * The location is not an op that we were expecting.
  29. * Something went wrong. Crash the box, as something could be
  30. * corrupting the kernel.
  31. */
  32. pr_warning("Unexpected op at %pS [%p] (%02x %02x %02x %02x %02x) %s:%d\n",
  33. ip, ip, ip[0], ip[1], ip[2], ip[3], ip[4], __FILE__, line);
  34. BUG();
  35. }
  36. static void __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 code;
  42. const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
  43. const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
  44. if (type == JUMP_LABEL_JMP) {
  45. if (init) {
  46. /*
  47. * Jump label is enabled for the first time.
  48. * So we expect a default_nop...
  49. */
  50. if (unlikely(memcmp((void *)entry->code, default_nop, 5)
  51. != 0))
  52. bug_at((void *)entry->code, __LINE__);
  53. } else {
  54. /*
  55. * ...otherwise expect an ideal_nop. Otherwise
  56. * something went horribly wrong.
  57. */
  58. if (unlikely(memcmp((void *)entry->code, ideal_nop, 5)
  59. != 0))
  60. bug_at((void *)entry->code, __LINE__);
  61. }
  62. code.jump = 0xe9;
  63. code.offset = entry->target -
  64. (entry->code + JUMP_LABEL_NOP_SIZE);
  65. } else {
  66. /*
  67. * We are disabling this jump label. If it is not what
  68. * we think it is, then something must have gone wrong.
  69. * If this is the first initialization call, then we
  70. * are converting the default nop to the ideal nop.
  71. */
  72. if (init) {
  73. if (unlikely(memcmp((void *)entry->code, default_nop, 5) != 0))
  74. bug_at((void *)entry->code, __LINE__);
  75. } else {
  76. code.jump = 0xe9;
  77. code.offset = entry->target -
  78. (entry->code + JUMP_LABEL_NOP_SIZE);
  79. if (unlikely(memcmp((void *)entry->code, &code, 5) != 0))
  80. bug_at((void *)entry->code, __LINE__);
  81. }
  82. memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
  83. }
  84. /*
  85. * Make text_poke_bp() a default fallback poker.
  86. *
  87. * At the time the change is being done, just ignore whether we
  88. * are doing nop -> jump or jump -> nop transition, and assume
  89. * always nop being the 'currently valid' instruction
  90. *
  91. */
  92. if (poker)
  93. (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
  94. else
  95. text_poke_bp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE,
  96. (void *)entry->code + JUMP_LABEL_NOP_SIZE);
  97. }
  98. void arch_jump_label_transform(struct jump_entry *entry,
  99. enum jump_label_type type)
  100. {
  101. get_online_cpus();
  102. mutex_lock(&text_mutex);
  103. __jump_label_transform(entry, type, NULL, 0);
  104. mutex_unlock(&text_mutex);
  105. put_online_cpus();
  106. }
  107. static enum {
  108. JL_STATE_START,
  109. JL_STATE_NO_UPDATE,
  110. JL_STATE_UPDATE,
  111. } jlstate __initdata_or_module = JL_STATE_START;
  112. __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry,
  113. enum jump_label_type type)
  114. {
  115. /*
  116. * This function is called at boot up and when modules are
  117. * first loaded. Check if the default nop, the one that is
  118. * inserted at compile time, is the ideal nop. If it is, then
  119. * we do not need to update the nop, and we can leave it as is.
  120. * If it is not, then we need to update the nop to the ideal nop.
  121. */
  122. if (jlstate == JL_STATE_START) {
  123. const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
  124. const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
  125. if (memcmp(ideal_nop, default_nop, 5) != 0)
  126. jlstate = JL_STATE_UPDATE;
  127. else
  128. jlstate = JL_STATE_NO_UPDATE;
  129. }
  130. if (jlstate == JL_STATE_UPDATE)
  131. __jump_label_transform(entry, type, text_poke_early, 1);
  132. }
  133. #endif