0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "kcsan: " fmt
0009
0010 #include <linux/atomic.h>
0011 #include <linux/bsearch.h>
0012 #include <linux/bug.h>
0013 #include <linux/debugfs.h>
0014 #include <linux/init.h>
0015 #include <linux/kallsyms.h>
0016 #include <linux/sched.h>
0017 #include <linux/seq_file.h>
0018 #include <linux/slab.h>
0019 #include <linux/sort.h>
0020 #include <linux/string.h>
0021 #include <linux/uaccess.h>
0022
0023 #include "kcsan.h"
0024
0025 atomic_long_t kcsan_counters[KCSAN_COUNTER_COUNT];
0026 static const char *const counter_names[] = {
0027 [KCSAN_COUNTER_USED_WATCHPOINTS] = "used_watchpoints",
0028 [KCSAN_COUNTER_SETUP_WATCHPOINTS] = "setup_watchpoints",
0029 [KCSAN_COUNTER_DATA_RACES] = "data_races",
0030 [KCSAN_COUNTER_ASSERT_FAILURES] = "assert_failures",
0031 [KCSAN_COUNTER_NO_CAPACITY] = "no_capacity",
0032 [KCSAN_COUNTER_REPORT_RACES] = "report_races",
0033 [KCSAN_COUNTER_RACES_UNKNOWN_ORIGIN] = "races_unknown_origin",
0034 [KCSAN_COUNTER_UNENCODABLE_ACCESSES] = "unencodable_accesses",
0035 [KCSAN_COUNTER_ENCODING_FALSE_POSITIVES] = "encoding_false_positives",
0036 };
0037 static_assert(ARRAY_SIZE(counter_names) == KCSAN_COUNTER_COUNT);
0038
0039
0040
0041
0042
0043 static struct {
0044 unsigned long *addrs;
0045 size_t size;
0046 int used;
0047 bool sorted;
0048 bool whitelist;
0049 } report_filterlist = {
0050 .addrs = NULL,
0051 .size = 8,
0052 .used = 0,
0053 .sorted = false,
0054 .whitelist = false,
0055 };
0056 static DEFINE_SPINLOCK(report_filterlist_lock);
0057
0058
0059
0060
0061
0062
0063 static noinline void microbenchmark(unsigned long iters)
0064 {
0065 const struct kcsan_ctx ctx_save = current->kcsan_ctx;
0066 const bool was_enabled = READ_ONCE(kcsan_enabled);
0067 u64 cycles;
0068
0069
0070 memset(¤t->kcsan_ctx, 0, sizeof(current->kcsan_ctx));
0071
0072
0073
0074
0075 WRITE_ONCE(kcsan_enabled, false);
0076
0077 pr_info("%s begin | iters: %lu\n", __func__, iters);
0078
0079 cycles = get_cycles();
0080 while (iters--) {
0081 unsigned long addr = iters & ((PAGE_SIZE << 8) - 1);
0082 int type = !(iters & 0x7f) ? KCSAN_ACCESS_ATOMIC :
0083 (!(iters & 0xf) ? KCSAN_ACCESS_WRITE : 0);
0084 __kcsan_check_access((void *)addr, sizeof(long), type);
0085 }
0086 cycles = get_cycles() - cycles;
0087
0088 pr_info("%s end | cycles: %llu\n", __func__, cycles);
0089
0090 WRITE_ONCE(kcsan_enabled, was_enabled);
0091
0092 current->kcsan_ctx = ctx_save;
0093 }
0094
0095 static int cmp_filterlist_addrs(const void *rhs, const void *lhs)
0096 {
0097 const unsigned long a = *(const unsigned long *)rhs;
0098 const unsigned long b = *(const unsigned long *)lhs;
0099
0100 return a < b ? -1 : a == b ? 0 : 1;
0101 }
0102
0103 bool kcsan_skip_report_debugfs(unsigned long func_addr)
0104 {
0105 unsigned long symbolsize, offset;
0106 unsigned long flags;
0107 bool ret = false;
0108
0109 if (!kallsyms_lookup_size_offset(func_addr, &symbolsize, &offset))
0110 return false;
0111 func_addr -= offset;
0112
0113 spin_lock_irqsave(&report_filterlist_lock, flags);
0114 if (report_filterlist.used == 0)
0115 goto out;
0116
0117
0118 if (!report_filterlist.sorted) {
0119 sort(report_filterlist.addrs, report_filterlist.used,
0120 sizeof(unsigned long), cmp_filterlist_addrs, NULL);
0121 report_filterlist.sorted = true;
0122 }
0123 ret = !!bsearch(&func_addr, report_filterlist.addrs,
0124 report_filterlist.used, sizeof(unsigned long),
0125 cmp_filterlist_addrs);
0126 if (report_filterlist.whitelist)
0127 ret = !ret;
0128
0129 out:
0130 spin_unlock_irqrestore(&report_filterlist_lock, flags);
0131 return ret;
0132 }
0133
0134 static void set_report_filterlist_whitelist(bool whitelist)
0135 {
0136 unsigned long flags;
0137
0138 spin_lock_irqsave(&report_filterlist_lock, flags);
0139 report_filterlist.whitelist = whitelist;
0140 spin_unlock_irqrestore(&report_filterlist_lock, flags);
0141 }
0142
0143
0144 static ssize_t insert_report_filterlist(const char *func)
0145 {
0146 unsigned long flags;
0147 unsigned long addr = kallsyms_lookup_name(func);
0148 ssize_t ret = 0;
0149
0150 if (!addr) {
0151 pr_err("could not find function: '%s'\n", func);
0152 return -ENOENT;
0153 }
0154
0155 spin_lock_irqsave(&report_filterlist_lock, flags);
0156
0157 if (report_filterlist.addrs == NULL) {
0158
0159 report_filterlist.addrs =
0160 kmalloc_array(report_filterlist.size,
0161 sizeof(unsigned long), GFP_ATOMIC);
0162 if (report_filterlist.addrs == NULL) {
0163 ret = -ENOMEM;
0164 goto out;
0165 }
0166 } else if (report_filterlist.used == report_filterlist.size) {
0167
0168 size_t new_size = report_filterlist.size * 2;
0169 unsigned long *new_addrs =
0170 krealloc(report_filterlist.addrs,
0171 new_size * sizeof(unsigned long), GFP_ATOMIC);
0172
0173 if (new_addrs == NULL) {
0174
0175 ret = -ENOMEM;
0176 goto out;
0177 }
0178
0179 report_filterlist.size = new_size;
0180 report_filterlist.addrs = new_addrs;
0181 }
0182
0183
0184 report_filterlist.addrs[report_filterlist.used++] =
0185 kallsyms_lookup_name(func);
0186 report_filterlist.sorted = false;
0187
0188 out:
0189 spin_unlock_irqrestore(&report_filterlist_lock, flags);
0190
0191 return ret;
0192 }
0193
0194 static int show_info(struct seq_file *file, void *v)
0195 {
0196 int i;
0197 unsigned long flags;
0198
0199
0200 seq_printf(file, "enabled: %i\n", READ_ONCE(kcsan_enabled));
0201 for (i = 0; i < KCSAN_COUNTER_COUNT; ++i) {
0202 seq_printf(file, "%s: %ld\n", counter_names[i],
0203 atomic_long_read(&kcsan_counters[i]));
0204 }
0205
0206
0207 spin_lock_irqsave(&report_filterlist_lock, flags);
0208 seq_printf(file, "\n%s functions: %s\n",
0209 report_filterlist.whitelist ? "whitelisted" : "blacklisted",
0210 report_filterlist.used == 0 ? "none" : "");
0211 for (i = 0; i < report_filterlist.used; ++i)
0212 seq_printf(file, " %ps\n", (void *)report_filterlist.addrs[i]);
0213 spin_unlock_irqrestore(&report_filterlist_lock, flags);
0214
0215 return 0;
0216 }
0217
0218 static int debugfs_open(struct inode *inode, struct file *file)
0219 {
0220 return single_open(file, show_info, NULL);
0221 }
0222
0223 static ssize_t
0224 debugfs_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
0225 {
0226 char kbuf[KSYM_NAME_LEN];
0227 char *arg;
0228 int read_len = count < (sizeof(kbuf) - 1) ? count : (sizeof(kbuf) - 1);
0229
0230 if (copy_from_user(kbuf, buf, read_len))
0231 return -EFAULT;
0232 kbuf[read_len] = '\0';
0233 arg = strstrip(kbuf);
0234
0235 if (!strcmp(arg, "on")) {
0236 WRITE_ONCE(kcsan_enabled, true);
0237 } else if (!strcmp(arg, "off")) {
0238 WRITE_ONCE(kcsan_enabled, false);
0239 } else if (str_has_prefix(arg, "microbench=")) {
0240 unsigned long iters;
0241
0242 if (kstrtoul(&arg[strlen("microbench=")], 0, &iters))
0243 return -EINVAL;
0244 microbenchmark(iters);
0245 } else if (!strcmp(arg, "whitelist")) {
0246 set_report_filterlist_whitelist(true);
0247 } else if (!strcmp(arg, "blacklist")) {
0248 set_report_filterlist_whitelist(false);
0249 } else if (arg[0] == '!') {
0250 ssize_t ret = insert_report_filterlist(&arg[1]);
0251
0252 if (ret < 0)
0253 return ret;
0254 } else {
0255 return -EINVAL;
0256 }
0257
0258 return count;
0259 }
0260
0261 static const struct file_operations debugfs_ops =
0262 {
0263 .read = seq_read,
0264 .open = debugfs_open,
0265 .write = debugfs_write,
0266 .release = single_release
0267 };
0268
0269 static int __init kcsan_debugfs_init(void)
0270 {
0271 debugfs_create_file("kcsan", 0644, NULL, NULL, &debugfs_ops);
0272 return 0;
0273 }
0274
0275 late_initcall(kcsan_debugfs_init);