debugfs.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * KCSAN debugfs interface.
  4. *
  5. * Copyright (C) 2019, Google LLC.
  6. */
  7. #define pr_fmt(fmt) "kcsan: " fmt
  8. #include <linux/atomic.h>
  9. #include <linux/bsearch.h>
  10. #include <linux/bug.h>
  11. #include <linux/debugfs.h>
  12. #include <linux/init.h>
  13. #include <linux/kallsyms.h>
  14. #include <linux/sched.h>
  15. #include <linux/seq_file.h>
  16. #include <linux/slab.h>
  17. #include <linux/sort.h>
  18. #include <linux/string.h>
  19. #include <linux/uaccess.h>
  20. #include "kcsan.h"
  21. atomic_long_t kcsan_counters[KCSAN_COUNTER_COUNT];
  22. static const char *const counter_names[] = {
  23. [KCSAN_COUNTER_USED_WATCHPOINTS] = "used_watchpoints",
  24. [KCSAN_COUNTER_SETUP_WATCHPOINTS] = "setup_watchpoints",
  25. [KCSAN_COUNTER_DATA_RACES] = "data_races",
  26. [KCSAN_COUNTER_ASSERT_FAILURES] = "assert_failures",
  27. [KCSAN_COUNTER_NO_CAPACITY] = "no_capacity",
  28. [KCSAN_COUNTER_REPORT_RACES] = "report_races",
  29. [KCSAN_COUNTER_RACES_UNKNOWN_ORIGIN] = "races_unknown_origin",
  30. [KCSAN_COUNTER_UNENCODABLE_ACCESSES] = "unencodable_accesses",
  31. [KCSAN_COUNTER_ENCODING_FALSE_POSITIVES] = "encoding_false_positives",
  32. };
  33. static_assert(ARRAY_SIZE(counter_names) == KCSAN_COUNTER_COUNT);
  34. /*
  35. * Addresses for filtering functions from reporting. This list can be used as a
  36. * whitelist or blacklist.
  37. */
  38. static struct {
  39. unsigned long *addrs; /* array of addresses */
  40. size_t size; /* current size */
  41. int used; /* number of elements used */
  42. bool sorted; /* if elements are sorted */
  43. bool whitelist; /* if list is a blacklist or whitelist */
  44. } report_filterlist;
  45. static DEFINE_RAW_SPINLOCK(report_filterlist_lock);
  46. /*
  47. * The microbenchmark allows benchmarking KCSAN core runtime only. To run
  48. * multiple threads, pipe 'microbench=<iters>' from multiple tasks into the
  49. * debugfs file. This will not generate any conflicts, and tests fast-path only.
  50. */
  51. static noinline void microbenchmark(unsigned long iters)
  52. {
  53. const struct kcsan_ctx ctx_save = current->kcsan_ctx;
  54. const bool was_enabled = READ_ONCE(kcsan_enabled);
  55. u64 cycles;
  56. /* We may have been called from an atomic region; reset context. */
  57. memset(&current->kcsan_ctx, 0, sizeof(current->kcsan_ctx));
  58. /*
  59. * Disable to benchmark fast-path for all accesses, and (expected
  60. * negligible) call into slow-path, but never set up watchpoints.
  61. */
  62. WRITE_ONCE(kcsan_enabled, false);
  63. pr_info("%s begin | iters: %lu\n", __func__, iters);
  64. cycles = get_cycles();
  65. while (iters--) {
  66. unsigned long addr = iters & ((PAGE_SIZE << 8) - 1);
  67. int type = !(iters & 0x7f) ? KCSAN_ACCESS_ATOMIC :
  68. (!(iters & 0xf) ? KCSAN_ACCESS_WRITE : 0);
  69. __kcsan_check_access((void *)addr, sizeof(long), type);
  70. }
  71. cycles = get_cycles() - cycles;
  72. pr_info("%s end | cycles: %llu\n", __func__, cycles);
  73. WRITE_ONCE(kcsan_enabled, was_enabled);
  74. /* restore context */
  75. current->kcsan_ctx = ctx_save;
  76. }
  77. static int cmp_filterlist_addrs(const void *rhs, const void *lhs)
  78. {
  79. const unsigned long a = *(const unsigned long *)rhs;
  80. const unsigned long b = *(const unsigned long *)lhs;
  81. return a < b ? -1 : a == b ? 0 : 1;
  82. }
  83. bool kcsan_skip_report_debugfs(unsigned long func_addr)
  84. {
  85. unsigned long symbolsize, offset;
  86. unsigned long flags;
  87. bool ret = false;
  88. if (!kallsyms_lookup_size_offset(func_addr, &symbolsize, &offset))
  89. return false;
  90. func_addr -= offset; /* Get function start */
  91. raw_spin_lock_irqsave(&report_filterlist_lock, flags);
  92. if (report_filterlist.used == 0)
  93. goto out;
  94. /* Sort array if it is unsorted, and then do a binary search. */
  95. if (!report_filterlist.sorted) {
  96. sort(report_filterlist.addrs, report_filterlist.used,
  97. sizeof(unsigned long), cmp_filterlist_addrs, NULL);
  98. report_filterlist.sorted = true;
  99. }
  100. ret = !!bsearch(&func_addr, report_filterlist.addrs,
  101. report_filterlist.used, sizeof(unsigned long),
  102. cmp_filterlist_addrs);
  103. if (report_filterlist.whitelist)
  104. ret = !ret;
  105. out:
  106. raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
  107. return ret;
  108. }
  109. static void set_report_filterlist_whitelist(bool whitelist)
  110. {
  111. unsigned long flags;
  112. raw_spin_lock_irqsave(&report_filterlist_lock, flags);
  113. report_filterlist.whitelist = whitelist;
  114. raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
  115. }
  116. /* Returns 0 on success, error-code otherwise. */
  117. static ssize_t insert_report_filterlist(const char *func)
  118. {
  119. unsigned long flags;
  120. unsigned long addr = kallsyms_lookup_name(func);
  121. unsigned long *delay_free = NULL;
  122. unsigned long *new_addrs = NULL;
  123. size_t new_size = 0;
  124. ssize_t ret = 0;
  125. if (!addr) {
  126. pr_err("could not find function: '%s'\n", func);
  127. return -ENOENT;
  128. }
  129. retry_alloc:
  130. /*
  131. * Check if we need an allocation, and re-validate under the lock. Since
  132. * the report_filterlist_lock is a raw, cannot allocate under the lock.
  133. */
  134. if (data_race(report_filterlist.used == report_filterlist.size)) {
  135. new_size = (report_filterlist.size ?: 4) * 2;
  136. delay_free = new_addrs = kmalloc_array(new_size, sizeof(unsigned long), GFP_KERNEL);
  137. if (!new_addrs)
  138. return -ENOMEM;
  139. }
  140. raw_spin_lock_irqsave(&report_filterlist_lock, flags);
  141. if (report_filterlist.used == report_filterlist.size) {
  142. /* Check we pre-allocated enough, and retry if not. */
  143. if (report_filterlist.used >= new_size) {
  144. raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
  145. kfree(new_addrs); /* kfree(NULL) is safe */
  146. delay_free = new_addrs = NULL;
  147. goto retry_alloc;
  148. }
  149. if (report_filterlist.used)
  150. memcpy(new_addrs, report_filterlist.addrs, report_filterlist.used * sizeof(unsigned long));
  151. delay_free = report_filterlist.addrs; /* free the old list */
  152. report_filterlist.addrs = new_addrs; /* switch to the new list */
  153. report_filterlist.size = new_size;
  154. }
  155. /* Note: deduplicating should be done in userspace. */
  156. report_filterlist.addrs[report_filterlist.used++] =
  157. kallsyms_lookup_name(func);
  158. report_filterlist.sorted = false;
  159. raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
  160. kfree(delay_free);
  161. return ret;
  162. }
  163. static int show_info(struct seq_file *file, void *v)
  164. {
  165. int i;
  166. unsigned long flags;
  167. /* show stats */
  168. seq_printf(file, "enabled: %i\n", READ_ONCE(kcsan_enabled));
  169. for (i = 0; i < KCSAN_COUNTER_COUNT; ++i) {
  170. seq_printf(file, "%s: %ld\n", counter_names[i],
  171. atomic_long_read(&kcsan_counters[i]));
  172. }
  173. /* show filter functions, and filter type */
  174. raw_spin_lock_irqsave(&report_filterlist_lock, flags);
  175. seq_printf(file, "\n%s functions: %s\n",
  176. report_filterlist.whitelist ? "whitelisted" : "blacklisted",
  177. report_filterlist.used == 0 ? "none" : "");
  178. for (i = 0; i < report_filterlist.used; ++i)
  179. seq_printf(file, " %ps\n", (void *)report_filterlist.addrs[i]);
  180. raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
  181. return 0;
  182. }
  183. static int debugfs_open(struct inode *inode, struct file *file)
  184. {
  185. return single_open(file, show_info, NULL);
  186. }
  187. static ssize_t
  188. debugfs_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
  189. {
  190. char kbuf[KSYM_NAME_LEN];
  191. char *arg;
  192. const size_t read_len = min(count, sizeof(kbuf) - 1);
  193. if (copy_from_user(kbuf, buf, read_len))
  194. return -EFAULT;
  195. kbuf[read_len] = '\0';
  196. arg = strstrip(kbuf);
  197. if (!strcmp(arg, "on")) {
  198. WRITE_ONCE(kcsan_enabled, true);
  199. } else if (!strcmp(arg, "off")) {
  200. WRITE_ONCE(kcsan_enabled, false);
  201. } else if (str_has_prefix(arg, "microbench=")) {
  202. unsigned long iters;
  203. if (kstrtoul(&arg[strlen("microbench=")], 0, &iters))
  204. return -EINVAL;
  205. microbenchmark(iters);
  206. } else if (!strcmp(arg, "whitelist")) {
  207. set_report_filterlist_whitelist(true);
  208. } else if (!strcmp(arg, "blacklist")) {
  209. set_report_filterlist_whitelist(false);
  210. } else if (arg[0] == '!') {
  211. ssize_t ret = insert_report_filterlist(&arg[1]);
  212. if (ret < 0)
  213. return ret;
  214. } else {
  215. return -EINVAL;
  216. }
  217. return count;
  218. }
  219. static const struct file_operations debugfs_ops =
  220. {
  221. .read = seq_read,
  222. .open = debugfs_open,
  223. .write = debugfs_write,
  224. .release = single_release
  225. };
  226. static int __init kcsan_debugfs_init(void)
  227. {
  228. debugfs_create_file("kcsan", 0644, NULL, NULL, &debugfs_ops);
  229. return 0;
  230. }
  231. late_initcall(kcsan_debugfs_init);