]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/misc/lkdtm_core.c
lkdtm: split heap corruption tests to separate file
[mirror_ubuntu-zesty-kernel.git] / drivers / misc / lkdtm_core.c
CommitLineData
8bb31b9d 1/*
426f3a53
KC
2 * 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.
8bb31b9d
AG
7 *
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 <ankita@in.ibm.com>
25 *
8bb31b9d
AG
26 * It is adapted from the Linux Kernel Dump Test Tool by
27 * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net>
28 *
0347af4e 29 * Debugfs support added by Simon Kagstrom <simon.kagstrom@netinsight.net>
8bb31b9d 30 *
0347af4e 31 * See Documentation/fault-injection/provoke-crashes.txt for instructions
8bb31b9d 32 */
426f3a53 33#define pr_fmt(fmt) "lkdtm: " fmt
8bb31b9d
AG
34
35#include <linux/kernel.h>
5d861d92 36#include <linux/fs.h>
8bb31b9d 37#include <linux/module.h>
5d861d92 38#include <linux/buffer_head.h>
8bb31b9d 39#include <linux/kprobes.h>
5d861d92 40#include <linux/list.h>
8bb31b9d 41#include <linux/init.h>
8bb31b9d 42#include <linux/interrupt.h>
5d861d92 43#include <linux/hrtimer.h>
5a0e3ad6 44#include <linux/slab.h>
8bb31b9d 45#include <scsi/scsi_cmnd.h>
0347af4e 46#include <linux/debugfs.h>
8bb31b9d
AG
47
48#ifdef CONFIG_IDE
49#include <linux/ide.h>
50#endif
51
9a49a528
KC
52#include "lkdtm.h"
53
7d196ac3
KC
54/*
55 * Make sure our attempts to over run the kernel stack doesn't trigger
56 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
57 * recurse past the end of THREAD_SIZE by default.
58 */
59#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
60#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2)
61#else
62#define REC_STACK_SIZE (THREAD_SIZE / 8)
63#endif
64#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)
65
8bb31b9d 66#define DEFAULT_COUNT 10
8bb31b9d
AG
67
68enum cname {
93e2f585
NK
69 CN_INVALID,
70 CN_INT_HARDWARE_ENTRY,
71 CN_INT_HW_IRQ_EN,
72 CN_INT_TASKLET_ENTRY,
73 CN_FS_DEVRW,
74 CN_MEM_SWAPOUT,
75 CN_TIMERADD,
76 CN_SCSI_DISPATCH_CMD,
77 CN_IDE_CORE_CP,
78 CN_DIRECT,
8bb31b9d
AG
79};
80
81enum ctype {
93e2f585
NK
82 CT_NONE,
83 CT_PANIC,
84 CT_BUG,
65892723 85 CT_WARNING,
93e2f585
NK
86 CT_EXCEPTION,
87 CT_LOOP,
88 CT_OVERFLOW,
89 CT_CORRUPT_STACK,
90 CT_UNALIGNED_LOAD_STORE_WRITE,
91 CT_OVERWRITE_ALLOCATION,
92 CT_WRITE_AFTER_FREE,
bc0b8cc6 93 CT_READ_AFTER_FREE,
920d451f
LA
94 CT_WRITE_BUDDY_AFTER_FREE,
95 CT_READ_BUDDY_AFTER_FREE,
93e2f585
NK
96 CT_SOFTLOCKUP,
97 CT_HARDLOCKUP,
274a5855 98 CT_SPINLOCKUP,
93e2f585 99 CT_HUNG_TASK,
cc33c537
KC
100 CT_EXEC_DATA,
101 CT_EXEC_STACK,
102 CT_EXEC_KMALLOC,
103 CT_EXEC_VMALLOC,
9a49a528 104 CT_EXEC_RODATA,
9ae113ce
KC
105 CT_EXEC_USERSPACE,
106 CT_ACCESS_USERSPACE,
107 CT_WRITE_RO,
7cca071c 108 CT_WRITE_RO_AFTER_INIT,
dc2b9e90 109 CT_WRITE_KERN,
b5484527
KC
110 CT_ATOMIC_UNDERFLOW,
111 CT_ATOMIC_OVERFLOW,
aa981a66
KC
112 CT_USERCOPY_HEAP_SIZE_TO,
113 CT_USERCOPY_HEAP_SIZE_FROM,
114 CT_USERCOPY_HEAP_FLAG_TO,
115 CT_USERCOPY_HEAP_FLAG_FROM,
116 CT_USERCOPY_STACK_FRAME_TO,
117 CT_USERCOPY_STACK_FRAME_FROM,
118 CT_USERCOPY_STACK_BEYOND,
6c352140 119 CT_USERCOPY_KERNEL,
8bb31b9d
AG
120};
121
122static char* cp_name[] = {
123 "INT_HARDWARE_ENTRY",
124 "INT_HW_IRQ_EN",
125 "INT_TASKLET_ENTRY",
126 "FS_DEVRW",
127 "MEM_SWAPOUT",
128 "TIMERADD",
129 "SCSI_DISPATCH_CMD",
0347af4e
SK
130 "IDE_CORE_CP",
131 "DIRECT",
8bb31b9d
AG
132};
133
134static char* cp_type[] = {
135 "PANIC",
136 "BUG",
65892723 137 "WARNING",
8bb31b9d
AG
138 "EXCEPTION",
139 "LOOP",
0347af4e
SK
140 "OVERFLOW",
141 "CORRUPT_STACK",
142 "UNALIGNED_LOAD_STORE_WRITE",
143 "OVERWRITE_ALLOCATION",
144 "WRITE_AFTER_FREE",
bc0b8cc6 145 "READ_AFTER_FREE",
920d451f
LA
146 "WRITE_BUDDY_AFTER_FREE",
147 "READ_BUDDY_AFTER_FREE",
a48223f9
FW
148 "SOFTLOCKUP",
149 "HARDLOCKUP",
274a5855 150 "SPINLOCKUP",
a48223f9 151 "HUNG_TASK",
cc33c537
KC
152 "EXEC_DATA",
153 "EXEC_STACK",
154 "EXEC_KMALLOC",
155 "EXEC_VMALLOC",
9a49a528 156 "EXEC_RODATA",
9ae113ce
KC
157 "EXEC_USERSPACE",
158 "ACCESS_USERSPACE",
159 "WRITE_RO",
7cca071c 160 "WRITE_RO_AFTER_INIT",
dc2b9e90 161 "WRITE_KERN",
b5484527
KC
162 "ATOMIC_UNDERFLOW",
163 "ATOMIC_OVERFLOW",
aa981a66
KC
164 "USERCOPY_HEAP_SIZE_TO",
165 "USERCOPY_HEAP_SIZE_FROM",
166 "USERCOPY_HEAP_FLAG_TO",
167 "USERCOPY_HEAP_FLAG_FROM",
168 "USERCOPY_STACK_FRAME_TO",
169 "USERCOPY_STACK_FRAME_FROM",
170 "USERCOPY_STACK_BEYOND",
6c352140 171 "USERCOPY_KERNEL",
8bb31b9d
AG
172};
173
174static struct jprobe lkdtm;
175
176static int lkdtm_parse_commandline(void);
177static void lkdtm_handler(void);
178
ec1c620b
AV
179static char* cpoint_name;
180static char* cpoint_type;
8bb31b9d
AG
181static int cpoint_count = DEFAULT_COUNT;
182static int recur_count = REC_NUM_DEFAULT;
183
93e2f585
NK
184static enum cname cpoint = CN_INVALID;
185static enum ctype cptype = CT_NONE;
8bb31b9d 186static int count = DEFAULT_COUNT;
aa2c96d6 187static DEFINE_SPINLOCK(count_lock);
274a5855 188static DEFINE_SPINLOCK(lock_me_up);
8bb31b9d
AG
189
190module_param(recur_count, int, 0644);
7d196ac3 191MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test");
dca41306 192module_param(cpoint_name, charp, 0444);
5d861d92 193MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
dca41306 194module_param(cpoint_type, charp, 0444);
5d861d92
RD
195MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\
196 "hitting the crash point");
197module_param(cpoint_count, int, 0644);
198MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
199 "crash point is to be hit to trigger action");
8bb31b9d 200
2118116e 201static unsigned int jp_do_irq(unsigned int irq)
8bb31b9d
AG
202{
203 lkdtm_handler();
204 jprobe_return();
205 return 0;
206}
207
2118116e
AB
208static irqreturn_t jp_handle_irq_event(unsigned int irq,
209 struct irqaction *action)
8bb31b9d
AG
210{
211 lkdtm_handler();
212 jprobe_return();
213 return 0;
214}
215
2118116e 216static void jp_tasklet_action(struct softirq_action *a)
8bb31b9d
AG
217{
218 lkdtm_handler();
219 jprobe_return();
220}
221
2118116e 222static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
8bb31b9d
AG
223{
224 lkdtm_handler();
225 jprobe_return();
226}
227
228struct scan_control;
229
2118116e
AB
230static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
231 struct zone *zone,
232 struct scan_control *sc)
8bb31b9d
AG
233{
234 lkdtm_handler();
235 jprobe_return();
236 return 0;
237}
238
2118116e
AB
239static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
240 const enum hrtimer_mode mode)
8bb31b9d
AG
241{
242 lkdtm_handler();
243 jprobe_return();
244 return 0;
245}
246
2118116e 247static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
8bb31b9d
AG
248{
249 lkdtm_handler();
250 jprobe_return();
251 return 0;
252}
253
254#ifdef CONFIG_IDE
44629432 255static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
8bb31b9d
AG
256 struct block_device *bdev, unsigned int cmd,
257 unsigned long arg)
258{
259 lkdtm_handler();
260 jprobe_return();
261 return 0;
262}
263#endif
264
0347af4e
SK
265/* Return the crashpoint number or NONE if the name is invalid */
266static enum ctype parse_cp_type(const char *what, size_t count)
267{
268 int i;
269
270 for (i = 0; i < ARRAY_SIZE(cp_type); i++) {
271 if (!strcmp(what, cp_type[i]))
272 return i + 1;
273 }
274
93e2f585 275 return CT_NONE;
0347af4e
SK
276}
277
278static const char *cp_type_to_str(enum ctype type)
279{
93e2f585 280 if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type))
0347af4e
SK
281 return "None";
282
283 return cp_type[type - 1];
284}
285
286static const char *cp_name_to_str(enum cname name)
287{
93e2f585 288 if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
0347af4e
SK
289 return "INVALID";
290
291 return cp_name[name - 1];
292}
293
294
8bb31b9d
AG
295static int lkdtm_parse_commandline(void)
296{
297 int i;
aa2c96d6 298 unsigned long flags;
8bb31b9d 299
0347af4e 300 if (cpoint_count < 1 || recur_count < 1)
8bb31b9d
AG
301 return -EINVAL;
302
aa2c96d6 303 spin_lock_irqsave(&count_lock, flags);
0347af4e 304 count = cpoint_count;
aa2c96d6 305 spin_unlock_irqrestore(&count_lock, flags);
0347af4e
SK
306
307 /* No special parameters */
308 if (!cpoint_type && !cpoint_name)
309 return 0;
310
311 /* Neither or both of these need to be set */
312 if (!cpoint_type || !cpoint_name)
313 return -EINVAL;
314
315 cptype = parse_cp_type(cpoint_type, strlen(cpoint_type));
93e2f585 316 if (cptype == CT_NONE)
0347af4e
SK
317 return -EINVAL;
318
319 for (i = 0; i < ARRAY_SIZE(cp_name); i++) {
8bb31b9d
AG
320 if (!strcmp(cpoint_name, cp_name[i])) {
321 cpoint = i + 1;
0347af4e 322 return 0;
8bb31b9d
AG
323 }
324 }
325
0347af4e
SK
326 /* Could not find a valid crash point */
327 return -EINVAL;
8bb31b9d
AG
328}
329
7d196ac3 330static int recursive_loop(int remaining)
8bb31b9d 331{
7d196ac3 332 char buf[REC_STACK_SIZE];
8bb31b9d 333
7d196ac3
KC
334 /* Make sure compiler does not optimize this away. */
335 memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE);
336 if (!remaining)
8bb31b9d
AG
337 return 0;
338 else
7d196ac3 339 return recursive_loop(remaining - 1);
8bb31b9d
AG
340}
341
629c66a2
KC
342static noinline void corrupt_stack(void)
343{
344 /* Use default char array length that triggers stack protection. */
345 char data[8];
346
347 memset((void *)data, 0, 64);
348}
349
0347af4e 350static void lkdtm_do_action(enum ctype which)
8bb31b9d 351{
0347af4e 352 switch (which) {
93e2f585 353 case CT_PANIC:
0347af4e
SK
354 panic("dumptest");
355 break;
93e2f585 356 case CT_BUG:
0347af4e
SK
357 BUG();
358 break;
65892723
KC
359 case CT_WARNING:
360 WARN_ON(1);
361 break;
93e2f585 362 case CT_EXCEPTION:
0347af4e
SK
363 *((int *) 0) = 0;
364 break;
93e2f585 365 case CT_LOOP:
0347af4e
SK
366 for (;;)
367 ;
368 break;
93e2f585 369 case CT_OVERFLOW:
7d196ac3 370 (void) recursive_loop(recur_count);
0347af4e 371 break;
629c66a2
KC
372 case CT_CORRUPT_STACK:
373 corrupt_stack();
0347af4e 374 break;
93e2f585 375 case CT_UNALIGNED_LOAD_STORE_WRITE: {
0347af4e
SK
376 static u8 data[5] __attribute__((aligned(4))) = {1, 2,
377 3, 4, 5};
378 u32 *p;
379 u32 val = 0x12345678;
380
381 p = (u32 *)(data + 1);
382 if (*p == 0)
383 val = 0x87654321;
384 *p = val;
385 break;
386 }
ffc514f3
KC
387 case CT_OVERWRITE_ALLOCATION:
388 lkdtm_OVERWRITE_ALLOCATION();
0347af4e 389 break;
ffc514f3
KC
390 case CT_WRITE_AFTER_FREE:
391 lkdtm_WRITE_AFTER_FREE();
0347af4e 392 break;
ffc514f3
KC
393 case CT_READ_AFTER_FREE:
394 lkdtm_READ_AFTER_FREE();
bc0b8cc6 395 break;
ffc514f3
KC
396 case CT_WRITE_BUDDY_AFTER_FREE:
397 lkdtm_WRITE_BUDDY_AFTER_FREE();
920d451f 398 break;
ffc514f3
KC
399 case CT_READ_BUDDY_AFTER_FREE:
400 lkdtm_READ_BUDDY_AFTER_FREE();
0347af4e 401 break;
93e2f585 402 case CT_SOFTLOCKUP:
a48223f9
FW
403 preempt_disable();
404 for (;;)
405 cpu_relax();
406 break;
93e2f585 407 case CT_HARDLOCKUP:
a48223f9
FW
408 local_irq_disable();
409 for (;;)
410 cpu_relax();
411 break;
274a5855
KC
412 case CT_SPINLOCKUP:
413 /* Must be called twice to trigger. */
414 spin_lock(&lock_me_up);
5123662a
KC
415 /* Let sparse know we intended to exit holding the lock. */
416 __release(&lock_me_up);
274a5855 417 break;
93e2f585 418 case CT_HUNG_TASK:
a48223f9
FW
419 set_current_state(TASK_UNINTERRUPTIBLE);
420 schedule();
421 break;
cc33c537 422 case CT_EXEC_DATA:
0d9eb29b 423 lkdtm_EXEC_DATA();
cc33c537 424 break;
0d9eb29b
KC
425 case CT_EXEC_STACK:
426 lkdtm_EXEC_STACK();
cc33c537 427 break;
0d9eb29b
KC
428 case CT_EXEC_KMALLOC:
429 lkdtm_EXEC_KMALLOC();
cc33c537 430 break;
0d9eb29b
KC
431 case CT_EXEC_VMALLOC:
432 lkdtm_EXEC_VMALLOC();
cc33c537 433 break;
9a49a528 434 case CT_EXEC_RODATA:
0d9eb29b 435 lkdtm_EXEC_RODATA();
9a49a528 436 break;
0d9eb29b
KC
437 case CT_EXEC_USERSPACE:
438 lkdtm_EXEC_USERSPACE();
9ae113ce 439 break;
0d9eb29b
KC
440 case CT_ACCESS_USERSPACE:
441 lkdtm_ACCESS_USERSPACE();
9ae113ce 442 break;
0d9eb29b
KC
443 case CT_WRITE_RO:
444 lkdtm_WRITE_RO();
7cca071c 445 break;
0d9eb29b
KC
446 case CT_WRITE_RO_AFTER_INIT:
447 lkdtm_WRITE_RO_AFTER_INIT();
9ae113ce 448 break;
0d9eb29b
KC
449 case CT_WRITE_KERN:
450 lkdtm_WRITE_KERN();
dc2b9e90 451 break;
b5484527 452 case CT_ATOMIC_UNDERFLOW: {
5fd9e480 453 atomic_t under = ATOMIC_INIT(INT_MIN);
5fd9e480 454
b5484527
KC
455 pr_info("attempting good atomic increment\n");
456 atomic_inc(&under);
457 atomic_dec(&under);
458
459 pr_info("attempting bad atomic underflow\n");
5fd9e480 460 atomic_dec(&under);
b5484527
KC
461 break;
462 }
463 case CT_ATOMIC_OVERFLOW: {
464 atomic_t over = ATOMIC_INIT(INT_MAX);
465
466 pr_info("attempting good atomic decrement\n");
467 atomic_dec(&over);
468 atomic_inc(&over);
469
470 pr_info("attempting bad atomic overflow\n");
5fd9e480
DW
471 atomic_inc(&over);
472
473 return;
474 }
aa981a66 475 case CT_USERCOPY_HEAP_SIZE_TO:
a3dff71c 476 lkdtm_USERCOPY_HEAP_SIZE_TO();
aa981a66
KC
477 break;
478 case CT_USERCOPY_HEAP_SIZE_FROM:
a3dff71c 479 lkdtm_USERCOPY_HEAP_SIZE_FROM();
aa981a66
KC
480 break;
481 case CT_USERCOPY_HEAP_FLAG_TO:
a3dff71c 482 lkdtm_USERCOPY_HEAP_FLAG_TO();
aa981a66
KC
483 break;
484 case CT_USERCOPY_HEAP_FLAG_FROM:
a3dff71c 485 lkdtm_USERCOPY_HEAP_FLAG_FROM();
aa981a66
KC
486 break;
487 case CT_USERCOPY_STACK_FRAME_TO:
a3dff71c 488 lkdtm_USERCOPY_STACK_FRAME_TO();
aa981a66
KC
489 break;
490 case CT_USERCOPY_STACK_FRAME_FROM:
a3dff71c 491 lkdtm_USERCOPY_STACK_FRAME_FROM();
aa981a66
KC
492 break;
493 case CT_USERCOPY_STACK_BEYOND:
a3dff71c 494 lkdtm_USERCOPY_STACK_BEYOND();
aa981a66 495 break;
6c352140 496 case CT_USERCOPY_KERNEL:
a3dff71c 497 lkdtm_USERCOPY_KERNEL();
6c352140 498 break;
93e2f585 499 case CT_NONE:
0347af4e
SK
500 default:
501 break;
502 }
503
504}
505
506static void lkdtm_handler(void)
507{
aa2c96d6 508 unsigned long flags;
92618184 509 bool do_it = false;
aa2c96d6
JH
510
511 spin_lock_irqsave(&count_lock, flags);
0347af4e 512 count--;
feac6e21
KC
513 pr_info("Crash point %s of type %s hit, trigger in %d rounds\n",
514 cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
8bb31b9d
AG
515
516 if (count == 0) {
92618184 517 do_it = true;
8bb31b9d
AG
518 count = cpoint_count;
519 }
aa2c96d6 520 spin_unlock_irqrestore(&count_lock, flags);
92618184
CW
521
522 if (do_it)
523 lkdtm_do_action(cptype);
8bb31b9d
AG
524}
525
0347af4e 526static int lkdtm_register_cpoint(enum cname which)
8bb31b9d
AG
527{
528 int ret;
529
93e2f585 530 cpoint = CN_INVALID;
0347af4e
SK
531 if (lkdtm.entry != NULL)
532 unregister_jprobe(&lkdtm);
8bb31b9d 533
0347af4e 534 switch (which) {
93e2f585 535 case CN_DIRECT:
0347af4e
SK
536 lkdtm_do_action(cptype);
537 return 0;
93e2f585 538 case CN_INT_HARDWARE_ENTRY:
f58f2fa9 539 lkdtm.kp.symbol_name = "do_IRQ";
8bb31b9d
AG
540 lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
541 break;
93e2f585 542 case CN_INT_HW_IRQ_EN:
8bb31b9d
AG
543 lkdtm.kp.symbol_name = "handle_IRQ_event";
544 lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
545 break;
93e2f585 546 case CN_INT_TASKLET_ENTRY:
8bb31b9d
AG
547 lkdtm.kp.symbol_name = "tasklet_action";
548 lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
549 break;
93e2f585 550 case CN_FS_DEVRW:
8bb31b9d
AG
551 lkdtm.kp.symbol_name = "ll_rw_block";
552 lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
553 break;
93e2f585 554 case CN_MEM_SWAPOUT:
18a61e4a
AG
555 lkdtm.kp.symbol_name = "shrink_inactive_list";
556 lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list;
8bb31b9d 557 break;
93e2f585 558 case CN_TIMERADD:
8bb31b9d
AG
559 lkdtm.kp.symbol_name = "hrtimer_start";
560 lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
561 break;
93e2f585 562 case CN_SCSI_DISPATCH_CMD:
8bb31b9d
AG
563 lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
564 lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
565 break;
93e2f585 566 case CN_IDE_CORE_CP:
8bb31b9d
AG
567#ifdef CONFIG_IDE
568 lkdtm.kp.symbol_name = "generic_ide_ioctl";
569 lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
570#else
feac6e21 571 pr_info("Crash point not available\n");
0347af4e 572 return -EINVAL;
8bb31b9d
AG
573#endif
574 break;
575 default:
feac6e21 576 pr_info("Invalid Crash Point\n");
0347af4e 577 return -EINVAL;
8bb31b9d
AG
578 }
579
0347af4e 580 cpoint = which;
8bb31b9d 581 if ((ret = register_jprobe(&lkdtm)) < 0) {
feac6e21 582 pr_info("Couldn't register jprobe\n");
93e2f585 583 cpoint = CN_INVALID;
0347af4e
SK
584 }
585
586 return ret;
587}
588
589static ssize_t do_register_entry(enum cname which, struct file *f,
590 const char __user *user_buf, size_t count, loff_t *off)
591{
592 char *buf;
593 int err;
594
595 if (count >= PAGE_SIZE)
596 return -EINVAL;
597
598 buf = (char *)__get_free_page(GFP_KERNEL);
599 if (!buf)
600 return -ENOMEM;
601 if (copy_from_user(buf, user_buf, count)) {
602 free_page((unsigned long) buf);
603 return -EFAULT;
604 }
605 /* NULL-terminate and remove enter */
606 buf[count] = '\0';
607 strim(buf);
608
609 cptype = parse_cp_type(buf, count);
610 free_page((unsigned long) buf);
611
93e2f585 612 if (cptype == CT_NONE)
0347af4e
SK
613 return -EINVAL;
614
615 err = lkdtm_register_cpoint(which);
616 if (err < 0)
617 return err;
618
619 *off += count;
620
621 return count;
622}
623
624/* Generic read callback that just prints out the available crash types */
625static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf,
626 size_t count, loff_t *off)
627{
628 char *buf;
629 int i, n, out;
630
631 buf = (char *)__get_free_page(GFP_KERNEL);
086ff4b3
AC
632 if (buf == NULL)
633 return -ENOMEM;
0347af4e
SK
634
635 n = snprintf(buf, PAGE_SIZE, "Available crash types:\n");
636 for (i = 0; i < ARRAY_SIZE(cp_type); i++)
637 n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]);
638 buf[n] = '\0';
639
640 out = simple_read_from_buffer(user_buf, count, off,
641 buf, n);
642 free_page((unsigned long) buf);
643
644 return out;
645}
646
647static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
648{
649 return 0;
650}
651
652
653static ssize_t int_hardware_entry(struct file *f, const char __user *buf,
654 size_t count, loff_t *off)
655{
93e2f585 656 return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off);
0347af4e
SK
657}
658
659static ssize_t int_hw_irq_en(struct file *f, const char __user *buf,
660 size_t count, loff_t *off)
661{
93e2f585 662 return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off);
0347af4e
SK
663}
664
665static ssize_t int_tasklet_entry(struct file *f, const char __user *buf,
666 size_t count, loff_t *off)
667{
93e2f585 668 return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off);
0347af4e
SK
669}
670
671static ssize_t fs_devrw_entry(struct file *f, const char __user *buf,
672 size_t count, loff_t *off)
673{
93e2f585 674 return do_register_entry(CN_FS_DEVRW, f, buf, count, off);
0347af4e
SK
675}
676
677static ssize_t mem_swapout_entry(struct file *f, const char __user *buf,
678 size_t count, loff_t *off)
679{
93e2f585 680 return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off);
0347af4e
SK
681}
682
683static ssize_t timeradd_entry(struct file *f, const char __user *buf,
684 size_t count, loff_t *off)
685{
93e2f585 686 return do_register_entry(CN_TIMERADD, f, buf, count, off);
0347af4e
SK
687}
688
689static ssize_t scsi_dispatch_cmd_entry(struct file *f,
690 const char __user *buf, size_t count, loff_t *off)
691{
93e2f585 692 return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off);
0347af4e
SK
693}
694
695static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf,
696 size_t count, loff_t *off)
697{
93e2f585 698 return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off);
0347af4e
SK
699}
700
701/* Special entry to just crash directly. Available without KPROBEs */
702static ssize_t direct_entry(struct file *f, const char __user *user_buf,
703 size_t count, loff_t *off)
704{
705 enum ctype type;
706 char *buf;
707
708 if (count >= PAGE_SIZE)
709 return -EINVAL;
710 if (count < 1)
711 return -EINVAL;
712
713 buf = (char *)__get_free_page(GFP_KERNEL);
714 if (!buf)
715 return -ENOMEM;
716 if (copy_from_user(buf, user_buf, count)) {
717 free_page((unsigned long) buf);
718 return -EFAULT;
719 }
720 /* NULL-terminate and remove enter */
721 buf[count] = '\0';
722 strim(buf);
723
724 type = parse_cp_type(buf, count);
725 free_page((unsigned long) buf);
93e2f585 726 if (type == CT_NONE)
0347af4e
SK
727 return -EINVAL;
728
feac6e21 729 pr_info("Performing direct entry %s\n", cp_type_to_str(type));
0347af4e
SK
730 lkdtm_do_action(type);
731 *off += count;
732
733 return count;
734}
735
736struct crash_entry {
737 const char *name;
738 const struct file_operations fops;
739};
740
741static const struct crash_entry crash_entries[] = {
742 {"DIRECT", {.read = lkdtm_debugfs_read,
05271ec4 743 .llseek = generic_file_llseek,
0347af4e
SK
744 .open = lkdtm_debugfs_open,
745 .write = direct_entry} },
746 {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read,
05271ec4 747 .llseek = generic_file_llseek,
0347af4e
SK
748 .open = lkdtm_debugfs_open,
749 .write = int_hardware_entry} },
750 {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read,
05271ec4 751 .llseek = generic_file_llseek,
0347af4e
SK
752 .open = lkdtm_debugfs_open,
753 .write = int_hw_irq_en} },
754 {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read,
05271ec4 755 .llseek = generic_file_llseek,
0347af4e
SK
756 .open = lkdtm_debugfs_open,
757 .write = int_tasklet_entry} },
758 {"FS_DEVRW", {.read = lkdtm_debugfs_read,
05271ec4 759 .llseek = generic_file_llseek,
0347af4e
SK
760 .open = lkdtm_debugfs_open,
761 .write = fs_devrw_entry} },
762 {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read,
05271ec4 763 .llseek = generic_file_llseek,
0347af4e
SK
764 .open = lkdtm_debugfs_open,
765 .write = mem_swapout_entry} },
766 {"TIMERADD", {.read = lkdtm_debugfs_read,
05271ec4 767 .llseek = generic_file_llseek,
0347af4e
SK
768 .open = lkdtm_debugfs_open,
769 .write = timeradd_entry} },
770 {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read,
05271ec4 771 .llseek = generic_file_llseek,
0347af4e
SK
772 .open = lkdtm_debugfs_open,
773 .write = scsi_dispatch_cmd_entry} },
774 {"IDE_CORE_CP", {.read = lkdtm_debugfs_read,
05271ec4 775 .llseek = generic_file_llseek,
0347af4e
SK
776 .open = lkdtm_debugfs_open,
777 .write = ide_core_cp_entry} },
778};
779
780static struct dentry *lkdtm_debugfs_root;
781
782static int __init lkdtm_module_init(void)
783{
784 int ret = -EINVAL;
785 int n_debugfs_entries = 1; /* Assume only the direct entry */
786 int i;
787
a3dff71c 788 /* Handle test-specific initialization. */
0d9eb29b 789 lkdtm_perms_init();
a3dff71c
KC
790 lkdtm_usercopy_init();
791
0347af4e
SK
792 /* Register debugfs interface */
793 lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
794 if (!lkdtm_debugfs_root) {
feac6e21 795 pr_err("creating root dir failed\n");
0347af4e
SK
796 return -ENODEV;
797 }
798
799#ifdef CONFIG_KPROBES
800 n_debugfs_entries = ARRAY_SIZE(crash_entries);
801#endif
802
803 for (i = 0; i < n_debugfs_entries; i++) {
804 const struct crash_entry *cur = &crash_entries[i];
805 struct dentry *de;
806
807 de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
808 NULL, &cur->fops);
809 if (de == NULL) {
feac6e21 810 pr_err("could not create %s\n", cur->name);
0347af4e
SK
811 goto out_err;
812 }
813 }
814
815 if (lkdtm_parse_commandline() == -EINVAL) {
feac6e21 816 pr_info("Invalid command\n");
0347af4e
SK
817 goto out_err;
818 }
819
93e2f585 820 if (cpoint != CN_INVALID && cptype != CT_NONE) {
0347af4e
SK
821 ret = lkdtm_register_cpoint(cpoint);
822 if (ret < 0) {
feac6e21 823 pr_info("Invalid crash point %d\n", cpoint);
0347af4e
SK
824 goto out_err;
825 }
feac6e21
KC
826 pr_info("Crash point %s of type %s registered\n",
827 cpoint_name, cpoint_type);
0347af4e 828 } else {
feac6e21 829 pr_info("No crash points registered, enable through debugfs\n");
8bb31b9d
AG
830 }
831
8bb31b9d 832 return 0;
0347af4e
SK
833
834out_err:
835 debugfs_remove_recursive(lkdtm_debugfs_root);
836 return ret;
8bb31b9d
AG
837}
838
2118116e 839static void __exit lkdtm_module_exit(void)
8bb31b9d 840{
0347af4e
SK
841 debugfs_remove_recursive(lkdtm_debugfs_root);
842
a3dff71c
KC
843 /* Handle test-specific clean-up. */
844 lkdtm_usercopy_exit();
aa981a66 845
0347af4e 846 unregister_jprobe(&lkdtm);
feac6e21 847 pr_info("Crash point unregistered\n");
8bb31b9d
AG
848}
849
850module_init(lkdtm_module_init);
851module_exit(lkdtm_module_exit);
852
853MODULE_LICENSE("GPL");
da86920f 854MODULE_DESCRIPTION("Kprobe module for testing crash dumps");