blob: 5d41c2230d2e47de8711a71b4f31c76860876f40 [file] [log] [blame]
Ankita Garg8bb31b92006-10-02 02:17:36 -07001/*
Kees Cook426f3a52016-06-03 11:16:32 -07002 * Linux Kernel Dump Test Module for testing kernel crashes conditions:
3 * induces system failures at predefined crashpoints and under predefined
4 * operational conditions in order to evaluate the reliability of kernel
5 * sanity checking and crash dumps obtained using different dumping
6 * solutions.
Ankita Garg8bb31b92006-10-02 02:17:36 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * Copyright (C) IBM Corporation, 2006
23 *
24 * Author: Ankita Garg <[email protected]>
25 *
Ankita Garg8bb31b92006-10-02 02:17:36 -070026 * It is adapted from the Linux Kernel Dump Test Tool by
27 * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net>
28 *
Simon Kagstrom0347af42010-03-05 13:42:49 -080029 * Debugfs support added by Simon Kagstrom <[email protected]>
Ankita Garg8bb31b92006-10-02 02:17:36 -070030 *
Simon Kagstrom0347af42010-03-05 13:42:49 -080031 * See Documentation/fault-injection/provoke-crashes.txt for instructions
Ankita Garg8bb31b92006-10-02 02:17:36 -070032 */
Kees Cook6d2e91a2016-07-15 16:04:39 -070033#include "lkdtm.h"
Randy Dunlap5d861d92006-11-02 22:07:06 -080034#include <linux/fs.h>
Ankita Garg8bb31b92006-10-02 02:17:36 -070035#include <linux/module.h>
Randy Dunlap5d861d92006-11-02 22:07:06 -080036#include <linux/buffer_head.h>
Ankita Garg8bb31b92006-10-02 02:17:36 -070037#include <linux/kprobes.h>
Randy Dunlap5d861d92006-11-02 22:07:06 -080038#include <linux/list.h>
Ankita Garg8bb31b92006-10-02 02:17:36 -070039#include <linux/init.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090040#include <linux/slab.h>
Simon Kagstrom0347af42010-03-05 13:42:49 -080041#include <linux/debugfs.h>
Ankita Garg8bb31b92006-10-02 02:17:36 -070042
Kees Cookd87c9782016-06-29 08:07:11 -070043#define DEFAULT_COUNT 10
44
Kees Cookc479e3f2016-06-29 08:18:27 -070045static int lkdtm_debugfs_open(struct inode *inode, struct file *file);
46static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf,
47 size_t count, loff_t *off);
48static ssize_t direct_entry(struct file *f, const char __user *user_buf,
49 size_t count, loff_t *off);
Arnd Bergmann2b271cb72016-07-15 15:58:55 -070050
51#ifdef CONFIG_KPROBES
Kees Cook31c5c872017-10-20 06:31:27 -070052static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs);
Kees Cookc479e3f2016-06-29 08:18:27 -070053static ssize_t lkdtm_debugfs_entry(struct file *f,
54 const char __user *user_buf,
55 size_t count, loff_t *off);
Kees Cook31c5c872017-10-20 06:31:27 -070056# define CRASHPOINT_KPROBE(_symbol) \
57 .kprobe = { \
58 .symbol_name = (_symbol), \
59 .pre_handler = lkdtm_kprobe_handler, \
60 },
61# define CRASHPOINT_WRITE(_symbol) \
62 (_symbol) ? lkdtm_debugfs_entry : direct_entry
63#else
64# define CRASHPOINT_KPROBE(_symbol)
65# define CRASHPOINT_WRITE(_symbol) direct_entry
Kees Cookf2c6edc2016-06-29 08:10:36 -070066#endif
67
Kees Cookc479e3f2016-06-29 08:18:27 -070068/* Crash points */
69struct crashpoint {
70 const char *name;
71 const struct file_operations fops;
Kees Cook31c5c872017-10-20 06:31:27 -070072 struct kprobe kprobe;
Ankita Garg8bb31b92006-10-02 02:17:36 -070073};
74
Kees Cook31c5c872017-10-20 06:31:27 -070075#define CRASHPOINT(_name, _symbol) \
Kees Cookc479e3f2016-06-29 08:18:27 -070076 { \
77 .name = _name, \
78 .fops = { \
79 .read = lkdtm_debugfs_read, \
80 .llseek = generic_file_llseek, \
81 .open = lkdtm_debugfs_open, \
Kees Cook31c5c872017-10-20 06:31:27 -070082 .write = CRASHPOINT_WRITE(_symbol) \
Kees Cookc479e3f2016-06-29 08:18:27 -070083 }, \
Kees Cook31c5c872017-10-20 06:31:27 -070084 CRASHPOINT_KPROBE(_symbol) \
Kees Cookc479e3f2016-06-29 08:18:27 -070085 }
86
87/* Define the possible places where we can trigger a crash point. */
Kees Cook31c5c872017-10-20 06:31:27 -070088static struct crashpoint crashpoints[] = {
89 CRASHPOINT("DIRECT", NULL),
Kees Cookc479e3f2016-06-29 08:18:27 -070090#ifdef CONFIG_KPROBES
Kees Cook31c5c872017-10-20 06:31:27 -070091 CRASHPOINT("INT_HARDWARE_ENTRY", "do_IRQ"),
Ivan Delalande5be2a502018-01-24 17:16:22 -080092 CRASHPOINT("INT_HW_IRQ_EN", "handle_irq_event"),
Kees Cook31c5c872017-10-20 06:31:27 -070093 CRASHPOINT("INT_TASKLET_ENTRY", "tasklet_action"),
94 CRASHPOINT("FS_DEVRW", "ll_rw_block"),
95 CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"),
96 CRASHPOINT("TIMERADD", "hrtimer_start"),
97 CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"),
Kees Cook31c5c872017-10-20 06:31:27 -070098 CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"),
Kees Cookc479e3f2016-06-29 08:18:27 -070099#endif
Ankita Garg8bb31b92006-10-02 02:17:36 -0700100};
101
Kees Cookc479e3f2016-06-29 08:18:27 -0700102
103/* Crash types. */
104struct crashtype {
105 const char *name;
106 void (*func)(void);
Ankita Garg8bb31b92006-10-02 02:17:36 -0700107};
108
Kees Cookc479e3f2016-06-29 08:18:27 -0700109#define CRASHTYPE(_name) \
110 { \
111 .name = __stringify(_name), \
112 .func = lkdtm_ ## _name, \
113 }
114
115/* Define the possible types of crashes that can be triggered. */
Kees Cook75f98b72017-10-20 06:31:49 -0700116static const struct crashtype crashtypes[] = {
Kees Cookc479e3f2016-06-29 08:18:27 -0700117 CRASHTYPE(PANIC),
118 CRASHTYPE(BUG),
119 CRASHTYPE(WARNING),
120 CRASHTYPE(EXCEPTION),
121 CRASHTYPE(LOOP),
122 CRASHTYPE(OVERFLOW),
Kees Cook6819d102016-08-17 14:42:12 -0700123 CRASHTYPE(CORRUPT_LIST_ADD),
124 CRASHTYPE(CORRUPT_LIST_DEL),
Kees Cooke22aa9d2017-03-24 10:51:25 -0700125 CRASHTYPE(CORRUPT_USER_DS),
Kees Cookc479e3f2016-06-29 08:18:27 -0700126 CRASHTYPE(CORRUPT_STACK),
Kees Cook93e78c62017-08-04 14:34:40 -0700127 CRASHTYPE(CORRUPT_STACK_STRONG),
Kees Cook7b25a852017-08-04 13:04:21 -0700128 CRASHTYPE(STACK_GUARD_PAGE_LEADING),
129 CRASHTYPE(STACK_GUARD_PAGE_TRAILING),
Kees Cookc479e3f2016-06-29 08:18:27 -0700130 CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
131 CRASHTYPE(OVERWRITE_ALLOCATION),
132 CRASHTYPE(WRITE_AFTER_FREE),
133 CRASHTYPE(READ_AFTER_FREE),
134 CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
135 CRASHTYPE(READ_BUDDY_AFTER_FREE),
136 CRASHTYPE(SOFTLOCKUP),
137 CRASHTYPE(HARDLOCKUP),
138 CRASHTYPE(SPINLOCKUP),
139 CRASHTYPE(HUNG_TASK),
140 CRASHTYPE(EXEC_DATA),
141 CRASHTYPE(EXEC_STACK),
142 CRASHTYPE(EXEC_KMALLOC),
143 CRASHTYPE(EXEC_VMALLOC),
144 CRASHTYPE(EXEC_RODATA),
145 CRASHTYPE(EXEC_USERSPACE),
146 CRASHTYPE(ACCESS_USERSPACE),
147 CRASHTYPE(WRITE_RO),
148 CRASHTYPE(WRITE_RO_AFTER_INIT),
149 CRASHTYPE(WRITE_KERN),
Kees Cook95925c92017-04-24 13:23:21 -0700150 CRASHTYPE(REFCOUNT_INC_OVERFLOW),
151 CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
152 CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),
153 CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW),
154 CRASHTYPE(REFCOUNT_DEC_ZERO),
155 CRASHTYPE(REFCOUNT_DEC_NEGATIVE),
156 CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE),
157 CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE),
158 CRASHTYPE(REFCOUNT_INC_ZERO),
159 CRASHTYPE(REFCOUNT_ADD_ZERO),
160 CRASHTYPE(REFCOUNT_INC_SATURATED),
161 CRASHTYPE(REFCOUNT_DEC_SATURATED),
162 CRASHTYPE(REFCOUNT_ADD_SATURATED),
163 CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED),
164 CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED),
165 CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED),
166 CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED),
Kees Cookc7fea482017-07-21 06:19:14 -0700167 CRASHTYPE(REFCOUNT_TIMING),
168 CRASHTYPE(ATOMIC_TIMING),
Kees Cookc479e3f2016-06-29 08:18:27 -0700169 CRASHTYPE(USERCOPY_HEAP_SIZE_TO),
170 CRASHTYPE(USERCOPY_HEAP_SIZE_FROM),
Kees Cooke47e3112017-06-14 18:56:55 -0700171 CRASHTYPE(USERCOPY_HEAP_WHITELIST_TO),
172 CRASHTYPE(USERCOPY_HEAP_WHITELIST_FROM),
Kees Cookc479e3f2016-06-29 08:18:27 -0700173 CRASHTYPE(USERCOPY_STACK_FRAME_TO),
174 CRASHTYPE(USERCOPY_STACK_FRAME_FROM),
175 CRASHTYPE(USERCOPY_STACK_BEYOND),
176 CRASHTYPE(USERCOPY_KERNEL),
Jann Hornbef45902018-08-28 22:14:21 +0200177 CRASHTYPE(USERCOPY_KERNEL_DS),
Alexander Popovf90d1e02018-08-17 01:17:00 +0300178 CRASHTYPE(STACKLEAK_ERASING),
Ankita Garg8bb31b92006-10-02 02:17:36 -0700179};
180
Kees Cookc479e3f2016-06-29 08:18:27 -0700181
Kees Cook31c5c872017-10-20 06:31:27 -0700182/* Global kprobe entry and crashtype. */
183static struct kprobe *lkdtm_kprobe;
Kees Cook75f98b72017-10-20 06:31:49 -0700184static struct crashpoint *lkdtm_crashpoint;
185static const struct crashtype *lkdtm_crashtype;
Ankita Garg8bb31b92006-10-02 02:17:36 -0700186
Kees Cookd87c9782016-06-29 08:07:11 -0700187/* Module parameters */
188static int recur_count = -1;
Ankita Garg8bb31b92006-10-02 02:17:36 -0700189module_param(recur_count, int, 0644);
Kees Cook7d196ac2013-10-24 09:25:39 -0700190MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test");
Kees Cookd87c9782016-06-29 08:07:11 -0700191
192static char* cpoint_name;
Rusty Russelldca41302010-08-11 23:04:21 -0600193module_param(cpoint_name, charp, 0444);
Randy Dunlap5d861d92006-11-02 22:07:06 -0800194MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
Kees Cookd87c9782016-06-29 08:07:11 -0700195
196static char* cpoint_type;
Rusty Russelldca41302010-08-11 23:04:21 -0600197module_param(cpoint_type, charp, 0444);
Randy Dunlap5d861d92006-11-02 22:07:06 -0800198MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\
199 "hitting the crash point");
Kees Cookd87c9782016-06-29 08:07:11 -0700200
201static int cpoint_count = DEFAULT_COUNT;
Randy Dunlap5d861d92006-11-02 22:07:06 -0800202module_param(cpoint_count, int, 0644);
203MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
204 "crash point is to be hit to trigger action");
Ankita Garg8bb31b92006-10-02 02:17:36 -0700205
Kees Cookc479e3f2016-06-29 08:18:27 -0700206
207/* Return the crashtype number or NULL if the name is invalid */
Kees Cook75f98b72017-10-20 06:31:49 -0700208static const struct crashtype *find_crashtype(const char *name)
Simon Kagstrom0347af42010-03-05 13:42:49 -0800209{
210 int i;
211
Kees Cookc479e3f2016-06-29 08:18:27 -0700212 for (i = 0; i < ARRAY_SIZE(crashtypes); i++) {
213 if (!strcmp(name, crashtypes[i].name))
214 return &crashtypes[i];
Simon Kagstrom0347af42010-03-05 13:42:49 -0800215 }
216
Kees Cookc479e3f2016-06-29 08:18:27 -0700217 return NULL;
Simon Kagstrom0347af42010-03-05 13:42:49 -0800218}
219
Kees Cookc479e3f2016-06-29 08:18:27 -0700220/*
221 * This is forced noinline just so it distinctly shows up in the stackdump
222 * which makes validation of expected lkdtm crashes easier.
223 */
Kees Cook75f98b72017-10-20 06:31:49 -0700224static noinline void lkdtm_do_action(const struct crashtype *crashtype)
Simon Kagstrom0347af42010-03-05 13:42:49 -0800225{
Kees Cook31c5c872017-10-20 06:31:27 -0700226 if (WARN_ON(!crashtype || !crashtype->func))
227 return;
Kees Cookc479e3f2016-06-29 08:18:27 -0700228 crashtype->func();
Simon Kagstrom0347af42010-03-05 13:42:49 -0800229}
230
Kees Cookc479e3f2016-06-29 08:18:27 -0700231static int lkdtm_register_cpoint(struct crashpoint *crashpoint,
Kees Cook75f98b72017-10-20 06:31:49 -0700232 const struct crashtype *crashtype)
Ankita Garg8bb31b92006-10-02 02:17:36 -0700233{
234 int ret;
235
Kees Cookc479e3f2016-06-29 08:18:27 -0700236 /* If this doesn't have a symbol, just call immediately. */
Kees Cook31c5c872017-10-20 06:31:27 -0700237 if (!crashpoint->kprobe.symbol_name) {
Kees Cookc479e3f2016-06-29 08:18:27 -0700238 lkdtm_do_action(crashtype);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800239 return 0;
Ankita Garg8bb31b92006-10-02 02:17:36 -0700240 }
241
Kees Cook31c5c872017-10-20 06:31:27 -0700242 if (lkdtm_kprobe != NULL)
243 unregister_kprobe(lkdtm_kprobe);
Kees Cookc479e3f2016-06-29 08:18:27 -0700244
245 lkdtm_crashpoint = crashpoint;
246 lkdtm_crashtype = crashtype;
Kees Cook31c5c872017-10-20 06:31:27 -0700247 lkdtm_kprobe = &crashpoint->kprobe;
248 ret = register_kprobe(lkdtm_kprobe);
Kees Cookc479e3f2016-06-29 08:18:27 -0700249 if (ret < 0) {
Kees Cook31c5c872017-10-20 06:31:27 -0700250 pr_info("Couldn't register kprobe %s\n",
251 crashpoint->kprobe.symbol_name);
252 lkdtm_kprobe = NULL;
Kees Cookc479e3f2016-06-29 08:18:27 -0700253 lkdtm_crashpoint = NULL;
254 lkdtm_crashtype = NULL;
Ankita Garg8bb31b92006-10-02 02:17:36 -0700255 }
256
Simon Kagstrom0347af42010-03-05 13:42:49 -0800257 return ret;
258}
259
Arnd Bergmann2b271cb72016-07-15 15:58:55 -0700260#ifdef CONFIG_KPROBES
261/* Global crash counter and spinlock. */
262static int crash_count = DEFAULT_COUNT;
263static DEFINE_SPINLOCK(crash_count_lock);
264
Kees Cook31c5c872017-10-20 06:31:27 -0700265/* Called by kprobe entry points. */
266static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs)
Arnd Bergmann2b271cb72016-07-15 15:58:55 -0700267{
268 unsigned long flags;
269 bool do_it = false;
270
Kees Cook31c5c872017-10-20 06:31:27 -0700271 if (WARN_ON(!lkdtm_crashpoint || !lkdtm_crashtype))
272 return 0;
Arnd Bergmann2b271cb72016-07-15 15:58:55 -0700273
274 spin_lock_irqsave(&crash_count_lock, flags);
275 crash_count--;
276 pr_info("Crash point %s of type %s hit, trigger in %d rounds\n",
277 lkdtm_crashpoint->name, lkdtm_crashtype->name, crash_count);
278
279 if (crash_count == 0) {
280 do_it = true;
281 crash_count = cpoint_count;
282 }
283 spin_unlock_irqrestore(&crash_count_lock, flags);
284
285 if (do_it)
286 lkdtm_do_action(lkdtm_crashtype);
Kees Cook31c5c872017-10-20 06:31:27 -0700287
288 return 0;
Arnd Bergmann2b271cb72016-07-15 15:58:55 -0700289}
290
Kees Cookc479e3f2016-06-29 08:18:27 -0700291static ssize_t lkdtm_debugfs_entry(struct file *f,
292 const char __user *user_buf,
293 size_t count, loff_t *off)
Simon Kagstrom0347af42010-03-05 13:42:49 -0800294{
Kees Cookc479e3f2016-06-29 08:18:27 -0700295 struct crashpoint *crashpoint = file_inode(f)->i_private;
Kees Cook75f98b72017-10-20 06:31:49 -0700296 const struct crashtype *crashtype = NULL;
Simon Kagstrom0347af42010-03-05 13:42:49 -0800297 char *buf;
298 int err;
299
300 if (count >= PAGE_SIZE)
301 return -EINVAL;
302
303 buf = (char *)__get_free_page(GFP_KERNEL);
304 if (!buf)
305 return -ENOMEM;
306 if (copy_from_user(buf, user_buf, count)) {
307 free_page((unsigned long) buf);
308 return -EFAULT;
309 }
310 /* NULL-terminate and remove enter */
311 buf[count] = '\0';
312 strim(buf);
313
Kees Cookc479e3f2016-06-29 08:18:27 -0700314 crashtype = find_crashtype(buf);
315 free_page((unsigned long)buf);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800316
Kees Cookc479e3f2016-06-29 08:18:27 -0700317 if (!crashtype)
Simon Kagstrom0347af42010-03-05 13:42:49 -0800318 return -EINVAL;
319
Kees Cookc479e3f2016-06-29 08:18:27 -0700320 err = lkdtm_register_cpoint(crashpoint, crashtype);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800321 if (err < 0)
322 return err;
323
324 *off += count;
325
326 return count;
327}
Arnd Bergmann2b271cb72016-07-15 15:58:55 -0700328#endif
Simon Kagstrom0347af42010-03-05 13:42:49 -0800329
330/* Generic read callback that just prints out the available crash types */
331static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf,
332 size_t count, loff_t *off)
333{
334 char *buf;
335 int i, n, out;
336
337 buf = (char *)__get_free_page(GFP_KERNEL);
Alan Cox086ff4b2012-07-30 14:43:24 -0700338 if (buf == NULL)
339 return -ENOMEM;
Simon Kagstrom0347af42010-03-05 13:42:49 -0800340
341 n = snprintf(buf, PAGE_SIZE, "Available crash types:\n");
Kees Cookc479e3f2016-06-29 08:18:27 -0700342 for (i = 0; i < ARRAY_SIZE(crashtypes); i++) {
343 n += snprintf(buf + n, PAGE_SIZE - n, "%s\n",
344 crashtypes[i].name);
345 }
Simon Kagstrom0347af42010-03-05 13:42:49 -0800346 buf[n] = '\0';
347
348 out = simple_read_from_buffer(user_buf, count, off,
349 buf, n);
350 free_page((unsigned long) buf);
351
352 return out;
353}
354
355static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
356{
Ankita Garg8bb31b92006-10-02 02:17:36 -0700357 return 0;
358}
359
Simon Kagstrom0347af42010-03-05 13:42:49 -0800360/* Special entry to just crash directly. Available without KPROBEs */
361static ssize_t direct_entry(struct file *f, const char __user *user_buf,
362 size_t count, loff_t *off)
363{
Kees Cook75f98b72017-10-20 06:31:49 -0700364 const struct crashtype *crashtype;
Simon Kagstrom0347af42010-03-05 13:42:49 -0800365 char *buf;
366
367 if (count >= PAGE_SIZE)
368 return -EINVAL;
369 if (count < 1)
370 return -EINVAL;
371
372 buf = (char *)__get_free_page(GFP_KERNEL);
373 if (!buf)
374 return -ENOMEM;
375 if (copy_from_user(buf, user_buf, count)) {
376 free_page((unsigned long) buf);
377 return -EFAULT;
378 }
379 /* NULL-terminate and remove enter */
380 buf[count] = '\0';
381 strim(buf);
382
Kees Cookc479e3f2016-06-29 08:18:27 -0700383 crashtype = find_crashtype(buf);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800384 free_page((unsigned long) buf);
Kees Cookc479e3f2016-06-29 08:18:27 -0700385 if (!crashtype)
Simon Kagstrom0347af42010-03-05 13:42:49 -0800386 return -EINVAL;
387
Kees Cookc479e3f2016-06-29 08:18:27 -0700388 pr_info("Performing direct entry %s\n", crashtype->name);
389 lkdtm_do_action(crashtype);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800390 *off += count;
391
392 return count;
393}
394
Simon Kagstrom0347af42010-03-05 13:42:49 -0800395static struct dentry *lkdtm_debugfs_root;
396
397static int __init lkdtm_module_init(void)
398{
Kees Cookc479e3f2016-06-29 08:18:27 -0700399 struct crashpoint *crashpoint = NULL;
Kees Cook75f98b72017-10-20 06:31:49 -0700400 const struct crashtype *crashtype = NULL;
Simon Kagstrom0347af42010-03-05 13:42:49 -0800401 int ret = -EINVAL;
Simon Kagstrom0347af42010-03-05 13:42:49 -0800402 int i;
403
Kees Cookc479e3f2016-06-29 08:18:27 -0700404 /* Neither or both of these need to be set */
405 if ((cpoint_type || cpoint_name) && !(cpoint_type && cpoint_name)) {
406 pr_err("Need both cpoint_type and cpoint_name or neither\n");
407 return -EINVAL;
408 }
409
410 if (cpoint_type) {
411 crashtype = find_crashtype(cpoint_type);
412 if (!crashtype) {
413 pr_err("Unknown crashtype '%s'\n", cpoint_type);
414 return -EINVAL;
415 }
416 }
417
418 if (cpoint_name) {
419 for (i = 0; i < ARRAY_SIZE(crashpoints); i++) {
420 if (!strcmp(cpoint_name, crashpoints[i].name))
421 crashpoint = &crashpoints[i];
422 }
423
424 /* Refuse unknown crashpoints. */
425 if (!crashpoint) {
426 pr_err("Invalid crashpoint %s\n", cpoint_name);
427 return -EINVAL;
428 }
429 }
430
Arnd Bergmann2b271cb72016-07-15 15:58:55 -0700431#ifdef CONFIG_KPROBES
Kees Cookc479e3f2016-06-29 08:18:27 -0700432 /* Set crash count. */
433 crash_count = cpoint_count;
Arnd Bergmann2b271cb72016-07-15 15:58:55 -0700434#endif
Kees Cookc479e3f2016-06-29 08:18:27 -0700435
Kees Cooka3dff712016-06-26 08:46:23 -0700436 /* Handle test-specific initialization. */
Kees Cook00f496c2016-06-26 22:17:25 -0700437 lkdtm_bugs_init(&recur_count);
Kees Cook0d9eb292016-06-26 15:12:31 -0700438 lkdtm_perms_init();
Kees Cooka3dff712016-06-26 08:46:23 -0700439 lkdtm_usercopy_init();
440
Simon Kagstrom0347af42010-03-05 13:42:49 -0800441 /* Register debugfs interface */
442 lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
443 if (!lkdtm_debugfs_root) {
Kees Cookfeac6e22014-02-09 13:48:46 -0800444 pr_err("creating root dir failed\n");
Simon Kagstrom0347af42010-03-05 13:42:49 -0800445 return -ENODEV;
446 }
447
Kees Cookc479e3f2016-06-29 08:18:27 -0700448 /* Install debugfs trigger files. */
449 for (i = 0; i < ARRAY_SIZE(crashpoints); i++) {
450 struct crashpoint *cur = &crashpoints[i];
Simon Kagstrom0347af42010-03-05 13:42:49 -0800451 struct dentry *de;
452
453 de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
Kees Cookc479e3f2016-06-29 08:18:27 -0700454 cur, &cur->fops);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800455 if (de == NULL) {
Kees Cookc479e3f2016-06-29 08:18:27 -0700456 pr_err("could not create crashpoint %s\n", cur->name);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800457 goto out_err;
458 }
459 }
460
Kees Cookc479e3f2016-06-29 08:18:27 -0700461 /* Install crashpoint if one was selected. */
462 if (crashpoint) {
463 ret = lkdtm_register_cpoint(crashpoint, crashtype);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800464 if (ret < 0) {
Kees Cookc479e3f2016-06-29 08:18:27 -0700465 pr_info("Invalid crashpoint %s\n", crashpoint->name);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800466 goto out_err;
467 }
Kees Cookfeac6e22014-02-09 13:48:46 -0800468 pr_info("Crash point %s of type %s registered\n",
Kees Cookc479e3f2016-06-29 08:18:27 -0700469 crashpoint->name, cpoint_type);
Simon Kagstrom0347af42010-03-05 13:42:49 -0800470 } else {
Kees Cookfeac6e22014-02-09 13:48:46 -0800471 pr_info("No crash points registered, enable through debugfs\n");
Simon Kagstrom0347af42010-03-05 13:42:49 -0800472 }
473
474 return 0;
475
476out_err:
477 debugfs_remove_recursive(lkdtm_debugfs_root);
478 return ret;
479}
480
Adrian Bunk21181162008-02-06 01:36:50 -0800481static void __exit lkdtm_module_exit(void)
Ankita Garg8bb31b92006-10-02 02:17:36 -0700482{
Simon Kagstrom0347af42010-03-05 13:42:49 -0800483 debugfs_remove_recursive(lkdtm_debugfs_root);
484
Kees Cooka3dff712016-06-26 08:46:23 -0700485 /* Handle test-specific clean-up. */
486 lkdtm_usercopy_exit();
Kees Cookaa981a62016-06-03 12:06:52 -0700487
Kees Cook31c5c872017-10-20 06:31:27 -0700488 if (lkdtm_kprobe != NULL)
489 unregister_kprobe(lkdtm_kprobe);
Juerg Haefliger9ba60572017-01-19 11:40:13 +0100490
Kees Cookfeac6e22014-02-09 13:48:46 -0800491 pr_info("Crash point unregistered\n");
Ankita Garg8bb31b92006-10-02 02:17:36 -0700492}
493
494module_init(lkdtm_module_init);
495module_exit(lkdtm_module_exit);
496
497MODULE_LICENSE("GPL");
Kees Cookc479e3f2016-06-29 08:18:27 -0700498MODULE_DESCRIPTION("Kernel crash testing module");