test_kprobes.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * test_kprobes.c - simple sanity test for *probes
  3. *
  4. * Copyright IBM Corp. 2008
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it would be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  14. * the GNU General Public License for more details.
  15. */
  16. #include <linux/kernel.h>
  17. #include <linux/kprobes.h>
  18. #include <linux/random.h>
  19. #define div_factor 3
  20. static u32 rand1, preh_val, posth_val, jph_val;
  21. static int errors, handler_errors, num_tests;
  22. static noinline u32 kprobe_target(u32 value)
  23. {
  24. /*
  25. * gcc ignores noinline on some architectures unless we stuff
  26. * sufficient lard into the function. The get_kprobe() here is
  27. * just for that.
  28. *
  29. * NOTE: We aren't concerned about the correctness of get_kprobe()
  30. * here; hence, this call is neither under !preempt nor with the
  31. * kprobe_mutex held. This is fine(tm)
  32. */
  33. if (get_kprobe((void *)0xdeadbeef))
  34. printk(KERN_INFO "Kprobe smoke test: probe on 0xdeadbeef!\n");
  35. return (value / div_factor);
  36. }
  37. static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs)
  38. {
  39. preh_val = (rand1 / div_factor);
  40. return 0;
  41. }
  42. static void kp_post_handler(struct kprobe *p, struct pt_regs *regs,
  43. unsigned long flags)
  44. {
  45. if (preh_val != (rand1 / div_factor)) {
  46. handler_errors++;
  47. printk(KERN_ERR "Kprobe smoke test failed: "
  48. "incorrect value in post_handler\n");
  49. }
  50. posth_val = preh_val + div_factor;
  51. }
  52. static struct kprobe kp = {
  53. .symbol_name = "kprobe_target",
  54. .pre_handler = kp_pre_handler,
  55. .post_handler = kp_post_handler
  56. };
  57. static int test_kprobe(void)
  58. {
  59. int ret;
  60. ret = register_kprobe(&kp);
  61. if (ret < 0) {
  62. printk(KERN_ERR "Kprobe smoke test failed: "
  63. "register_kprobe returned %d\n", ret);
  64. return ret;
  65. }
  66. ret = kprobe_target(rand1);
  67. unregister_kprobe(&kp);
  68. if (preh_val == 0) {
  69. printk(KERN_ERR "Kprobe smoke test failed: "
  70. "kprobe pre_handler not called\n");
  71. handler_errors++;
  72. }
  73. if (posth_val == 0) {
  74. printk(KERN_ERR "Kprobe smoke test failed: "
  75. "kprobe post_handler not called\n");
  76. handler_errors++;
  77. }
  78. return 0;
  79. }
  80. static u32 j_kprobe_target(u32 value)
  81. {
  82. if (value != rand1) {
  83. handler_errors++;
  84. printk(KERN_ERR "Kprobe smoke test failed: "
  85. "incorrect value in jprobe handler\n");
  86. }
  87. jph_val = rand1;
  88. jprobe_return();
  89. return 0;
  90. }
  91. static struct jprobe jp = {
  92. .entry = j_kprobe_target,
  93. .kp.symbol_name = "kprobe_target"
  94. };
  95. static int test_jprobe(void)
  96. {
  97. int ret;
  98. ret = register_jprobe(&jp);
  99. if (ret < 0) {
  100. printk(KERN_ERR "Kprobe smoke test failed: "
  101. "register_jprobe returned %d\n", ret);
  102. return ret;
  103. }
  104. ret = kprobe_target(rand1);
  105. unregister_jprobe(&jp);
  106. if (jph_val == 0) {
  107. printk(KERN_ERR "Kprobe smoke test failed: "
  108. "jprobe handler not called\n");
  109. handler_errors++;
  110. }
  111. return 0;
  112. }
  113. #ifdef CONFIG_KRETPROBES
  114. static u32 krph_val;
  115. static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
  116. {
  117. unsigned long ret = regs_return_value(regs);
  118. if (ret != (rand1 / div_factor)) {
  119. handler_errors++;
  120. printk(KERN_ERR "Kprobe smoke test failed: "
  121. "incorrect value in kretprobe handler\n");
  122. }
  123. krph_val = (rand1 / div_factor);
  124. return 0;
  125. }
  126. static struct kretprobe rp = {
  127. .handler = return_handler,
  128. .kp.symbol_name = "kprobe_target"
  129. };
  130. static int test_kretprobe(void)
  131. {
  132. int ret;
  133. ret = register_kretprobe(&rp);
  134. if (ret < 0) {
  135. printk(KERN_ERR "Kprobe smoke test failed: "
  136. "register_kretprobe returned %d\n", ret);
  137. return ret;
  138. }
  139. ret = kprobe_target(rand1);
  140. unregister_kretprobe(&rp);
  141. if (krph_val == 0) {
  142. printk(KERN_ERR "Kprobe smoke test failed: "
  143. "kretprobe handler not called\n");
  144. handler_errors++;
  145. }
  146. return 0;
  147. }
  148. #endif /* CONFIG_KRETPROBES */
  149. int init_test_probes(void)
  150. {
  151. int ret;
  152. do {
  153. rand1 = random32();
  154. } while (rand1 <= div_factor);
  155. printk(KERN_INFO "Kprobe smoke test started\n");
  156. num_tests++;
  157. ret = test_kprobe();
  158. if (ret < 0)
  159. errors++;
  160. num_tests++;
  161. ret = test_jprobe();
  162. if (ret < 0)
  163. errors++;
  164. #ifdef CONFIG_KRETPROBES
  165. num_tests++;
  166. ret = test_kretprobe();
  167. if (ret < 0)
  168. errors++;
  169. #endif /* CONFIG_KRETPROBES */
  170. if (errors)
  171. printk(KERN_ERR "BUG: Kprobe smoke test: %d out of "
  172. "%d tests failed\n", errors, num_tests);
  173. else if (handler_errors)
  174. printk(KERN_ERR "BUG: Kprobe smoke test: %d error(s) "
  175. "running handlers\n", handler_errors);
  176. else
  177. printk(KERN_INFO "Kprobe smoke test passed successfully\n");
  178. return 0;
  179. }