Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.5-rc6 879 lines 20 kB view raw
1/* 2 * Kprobe module for testing crash dumps 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * Copyright (C) IBM Corporation, 2006 19 * 20 * Author: Ankita Garg <ankita@in.ibm.com> 21 * 22 * This module induces system failures at predefined crashpoints to 23 * evaluate the reliability of crash dumps obtained using different dumping 24 * solutions. 25 * 26 * It is adapted from the Linux Kernel Dump Test Tool by 27 * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net> 28 * 29 * Debugfs support added by Simon Kagstrom <simon.kagstrom@netinsight.net> 30 * 31 * See Documentation/fault-injection/provoke-crashes.txt for instructions 32 */ 33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 34 35#include <linux/kernel.h> 36#include <linux/fs.h> 37#include <linux/module.h> 38#include <linux/buffer_head.h> 39#include <linux/kprobes.h> 40#include <linux/list.h> 41#include <linux/init.h> 42#include <linux/interrupt.h> 43#include <linux/hrtimer.h> 44#include <linux/slab.h> 45#include <scsi/scsi_cmnd.h> 46#include <linux/debugfs.h> 47#include <linux/vmalloc.h> 48#include <linux/mman.h> 49#include <asm/cacheflush.h> 50 51#ifdef CONFIG_IDE 52#include <linux/ide.h> 53#endif 54 55/* 56 * Make sure our attempts to over run the kernel stack doesn't trigger 57 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we 58 * recurse past the end of THREAD_SIZE by default. 59 */ 60#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) 61#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) 62#else 63#define REC_STACK_SIZE (THREAD_SIZE / 8) 64#endif 65#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) 66 67#define DEFAULT_COUNT 10 68#define EXEC_SIZE 64 69 70enum cname { 71 CN_INVALID, 72 CN_INT_HARDWARE_ENTRY, 73 CN_INT_HW_IRQ_EN, 74 CN_INT_TASKLET_ENTRY, 75 CN_FS_DEVRW, 76 CN_MEM_SWAPOUT, 77 CN_TIMERADD, 78 CN_SCSI_DISPATCH_CMD, 79 CN_IDE_CORE_CP, 80 CN_DIRECT, 81}; 82 83enum ctype { 84 CT_NONE, 85 CT_PANIC, 86 CT_BUG, 87 CT_WARNING, 88 CT_EXCEPTION, 89 CT_LOOP, 90 CT_OVERFLOW, 91 CT_CORRUPT_STACK, 92 CT_UNALIGNED_LOAD_STORE_WRITE, 93 CT_OVERWRITE_ALLOCATION, 94 CT_WRITE_AFTER_FREE, 95 CT_SOFTLOCKUP, 96 CT_HARDLOCKUP, 97 CT_SPINLOCKUP, 98 CT_HUNG_TASK, 99 CT_EXEC_DATA, 100 CT_EXEC_STACK, 101 CT_EXEC_KMALLOC, 102 CT_EXEC_VMALLOC, 103 CT_EXEC_USERSPACE, 104 CT_ACCESS_USERSPACE, 105 CT_WRITE_RO, 106 CT_WRITE_KERN, 107}; 108 109static char* cp_name[] = { 110 "INT_HARDWARE_ENTRY", 111 "INT_HW_IRQ_EN", 112 "INT_TASKLET_ENTRY", 113 "FS_DEVRW", 114 "MEM_SWAPOUT", 115 "TIMERADD", 116 "SCSI_DISPATCH_CMD", 117 "IDE_CORE_CP", 118 "DIRECT", 119}; 120 121static char* cp_type[] = { 122 "PANIC", 123 "BUG", 124 "WARNING", 125 "EXCEPTION", 126 "LOOP", 127 "OVERFLOW", 128 "CORRUPT_STACK", 129 "UNALIGNED_LOAD_STORE_WRITE", 130 "OVERWRITE_ALLOCATION", 131 "WRITE_AFTER_FREE", 132 "SOFTLOCKUP", 133 "HARDLOCKUP", 134 "SPINLOCKUP", 135 "HUNG_TASK", 136 "EXEC_DATA", 137 "EXEC_STACK", 138 "EXEC_KMALLOC", 139 "EXEC_VMALLOC", 140 "EXEC_USERSPACE", 141 "ACCESS_USERSPACE", 142 "WRITE_RO", 143 "WRITE_KERN", 144}; 145 146static struct jprobe lkdtm; 147 148static int lkdtm_parse_commandline(void); 149static void lkdtm_handler(void); 150 151static char* cpoint_name; 152static char* cpoint_type; 153static int cpoint_count = DEFAULT_COUNT; 154static int recur_count = REC_NUM_DEFAULT; 155 156static enum cname cpoint = CN_INVALID; 157static enum ctype cptype = CT_NONE; 158static int count = DEFAULT_COUNT; 159static DEFINE_SPINLOCK(count_lock); 160static DEFINE_SPINLOCK(lock_me_up); 161 162static u8 data_area[EXEC_SIZE]; 163 164static const unsigned long rodata = 0xAA55AA55; 165 166module_param(recur_count, int, 0644); 167MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); 168module_param(cpoint_name, charp, 0444); 169MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); 170module_param(cpoint_type, charp, 0444); 171MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ 172 "hitting the crash point"); 173module_param(cpoint_count, int, 0644); 174MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ 175 "crash point is to be hit to trigger action"); 176 177static unsigned int jp_do_irq(unsigned int irq) 178{ 179 lkdtm_handler(); 180 jprobe_return(); 181 return 0; 182} 183 184static irqreturn_t jp_handle_irq_event(unsigned int irq, 185 struct irqaction *action) 186{ 187 lkdtm_handler(); 188 jprobe_return(); 189 return 0; 190} 191 192static void jp_tasklet_action(struct softirq_action *a) 193{ 194 lkdtm_handler(); 195 jprobe_return(); 196} 197 198static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) 199{ 200 lkdtm_handler(); 201 jprobe_return(); 202} 203 204struct scan_control; 205 206static unsigned long jp_shrink_inactive_list(unsigned long max_scan, 207 struct zone *zone, 208 struct scan_control *sc) 209{ 210 lkdtm_handler(); 211 jprobe_return(); 212 return 0; 213} 214 215static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, 216 const enum hrtimer_mode mode) 217{ 218 lkdtm_handler(); 219 jprobe_return(); 220 return 0; 221} 222 223static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) 224{ 225 lkdtm_handler(); 226 jprobe_return(); 227 return 0; 228} 229 230#ifdef CONFIG_IDE 231static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, 232 struct block_device *bdev, unsigned int cmd, 233 unsigned long arg) 234{ 235 lkdtm_handler(); 236 jprobe_return(); 237 return 0; 238} 239#endif 240 241/* Return the crashpoint number or NONE if the name is invalid */ 242static enum ctype parse_cp_type(const char *what, size_t count) 243{ 244 int i; 245 246 for (i = 0; i < ARRAY_SIZE(cp_type); i++) { 247 if (!strcmp(what, cp_type[i])) 248 return i + 1; 249 } 250 251 return CT_NONE; 252} 253 254static const char *cp_type_to_str(enum ctype type) 255{ 256 if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type)) 257 return "None"; 258 259 return cp_type[type - 1]; 260} 261 262static const char *cp_name_to_str(enum cname name) 263{ 264 if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) 265 return "INVALID"; 266 267 return cp_name[name - 1]; 268} 269 270 271static int lkdtm_parse_commandline(void) 272{ 273 int i; 274 unsigned long flags; 275 276 if (cpoint_count < 1 || recur_count < 1) 277 return -EINVAL; 278 279 spin_lock_irqsave(&count_lock, flags); 280 count = cpoint_count; 281 spin_unlock_irqrestore(&count_lock, flags); 282 283 /* No special parameters */ 284 if (!cpoint_type && !cpoint_name) 285 return 0; 286 287 /* Neither or both of these need to be set */ 288 if (!cpoint_type || !cpoint_name) 289 return -EINVAL; 290 291 cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); 292 if (cptype == CT_NONE) 293 return -EINVAL; 294 295 for (i = 0; i < ARRAY_SIZE(cp_name); i++) { 296 if (!strcmp(cpoint_name, cp_name[i])) { 297 cpoint = i + 1; 298 return 0; 299 } 300 } 301 302 /* Could not find a valid crash point */ 303 return -EINVAL; 304} 305 306static int recursive_loop(int remaining) 307{ 308 char buf[REC_STACK_SIZE]; 309 310 /* Make sure compiler does not optimize this away. */ 311 memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); 312 if (!remaining) 313 return 0; 314 else 315 return recursive_loop(remaining - 1); 316} 317 318static void do_nothing(void) 319{ 320 return; 321} 322 323/* Must immediately follow do_nothing for size calculuations to work out. */ 324static void do_overwritten(void) 325{ 326 pr_info("do_overwritten wasn't overwritten!\n"); 327 return; 328} 329 330static noinline void corrupt_stack(void) 331{ 332 /* Use default char array length that triggers stack protection. */ 333 char data[8]; 334 335 memset((void *)data, 0, 64); 336} 337 338static void execute_location(void *dst) 339{ 340 void (*func)(void) = dst; 341 342 pr_info("attempting ok execution at %p\n", do_nothing); 343 do_nothing(); 344 345 memcpy(dst, do_nothing, EXEC_SIZE); 346 flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); 347 pr_info("attempting bad execution at %p\n", func); 348 func(); 349} 350 351static void execute_user_location(void *dst) 352{ 353 /* Intentionally crossing kernel/user memory boundary. */ 354 void (*func)(void) = dst; 355 356 pr_info("attempting ok execution at %p\n", do_nothing); 357 do_nothing(); 358 359 if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE)) 360 return; 361 flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); 362 pr_info("attempting bad execution at %p\n", func); 363 func(); 364} 365 366static void lkdtm_do_action(enum ctype which) 367{ 368 switch (which) { 369 case CT_PANIC: 370 panic("dumptest"); 371 break; 372 case CT_BUG: 373 BUG(); 374 break; 375 case CT_WARNING: 376 WARN_ON(1); 377 break; 378 case CT_EXCEPTION: 379 *((int *) 0) = 0; 380 break; 381 case CT_LOOP: 382 for (;;) 383 ; 384 break; 385 case CT_OVERFLOW: 386 (void) recursive_loop(recur_count); 387 break; 388 case CT_CORRUPT_STACK: 389 corrupt_stack(); 390 break; 391 case CT_UNALIGNED_LOAD_STORE_WRITE: { 392 static u8 data[5] __attribute__((aligned(4))) = {1, 2, 393 3, 4, 5}; 394 u32 *p; 395 u32 val = 0x12345678; 396 397 p = (u32 *)(data + 1); 398 if (*p == 0) 399 val = 0x87654321; 400 *p = val; 401 break; 402 } 403 case CT_OVERWRITE_ALLOCATION: { 404 size_t len = 1020; 405 u32 *data = kmalloc(len, GFP_KERNEL); 406 407 data[1024 / sizeof(u32)] = 0x12345678; 408 kfree(data); 409 break; 410 } 411 case CT_WRITE_AFTER_FREE: { 412 size_t len = 1024; 413 u32 *data = kmalloc(len, GFP_KERNEL); 414 415 kfree(data); 416 schedule(); 417 memset(data, 0x78, len); 418 break; 419 } 420 case CT_SOFTLOCKUP: 421 preempt_disable(); 422 for (;;) 423 cpu_relax(); 424 break; 425 case CT_HARDLOCKUP: 426 local_irq_disable(); 427 for (;;) 428 cpu_relax(); 429 break; 430 case CT_SPINLOCKUP: 431 /* Must be called twice to trigger. */ 432 spin_lock(&lock_me_up); 433 /* Let sparse know we intended to exit holding the lock. */ 434 __release(&lock_me_up); 435 break; 436 case CT_HUNG_TASK: 437 set_current_state(TASK_UNINTERRUPTIBLE); 438 schedule(); 439 break; 440 case CT_EXEC_DATA: 441 execute_location(data_area); 442 break; 443 case CT_EXEC_STACK: { 444 u8 stack_area[EXEC_SIZE]; 445 execute_location(stack_area); 446 break; 447 } 448 case CT_EXEC_KMALLOC: { 449 u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); 450 execute_location(kmalloc_area); 451 kfree(kmalloc_area); 452 break; 453 } 454 case CT_EXEC_VMALLOC: { 455 u32 *vmalloc_area = vmalloc(EXEC_SIZE); 456 execute_location(vmalloc_area); 457 vfree(vmalloc_area); 458 break; 459 } 460 case CT_EXEC_USERSPACE: { 461 unsigned long user_addr; 462 463 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 464 PROT_READ | PROT_WRITE | PROT_EXEC, 465 MAP_ANONYMOUS | MAP_PRIVATE, 0); 466 if (user_addr >= TASK_SIZE) { 467 pr_warn("Failed to allocate user memory\n"); 468 return; 469 } 470 execute_user_location((void *)user_addr); 471 vm_munmap(user_addr, PAGE_SIZE); 472 break; 473 } 474 case CT_ACCESS_USERSPACE: { 475 unsigned long user_addr, tmp = 0; 476 unsigned long *ptr; 477 478 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 479 PROT_READ | PROT_WRITE | PROT_EXEC, 480 MAP_ANONYMOUS | MAP_PRIVATE, 0); 481 if (user_addr >= TASK_SIZE) { 482 pr_warn("Failed to allocate user memory\n"); 483 return; 484 } 485 486 if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { 487 pr_warn("copy_to_user failed\n"); 488 vm_munmap(user_addr, PAGE_SIZE); 489 return; 490 } 491 492 ptr = (unsigned long *)user_addr; 493 494 pr_info("attempting bad read at %p\n", ptr); 495 tmp = *ptr; 496 tmp += 0xc0dec0de; 497 498 pr_info("attempting bad write at %p\n", ptr); 499 *ptr = tmp; 500 501 vm_munmap(user_addr, PAGE_SIZE); 502 503 break; 504 } 505 case CT_WRITE_RO: { 506 unsigned long *ptr; 507 508 ptr = (unsigned long *)&rodata; 509 510 pr_info("attempting bad write at %p\n", ptr); 511 *ptr ^= 0xabcd1234; 512 513 break; 514 } 515 case CT_WRITE_KERN: { 516 size_t size; 517 unsigned char *ptr; 518 519 size = (unsigned long)do_overwritten - 520 (unsigned long)do_nothing; 521 ptr = (unsigned char *)do_overwritten; 522 523 pr_info("attempting bad %zu byte write at %p\n", size, ptr); 524 memcpy(ptr, (unsigned char *)do_nothing, size); 525 flush_icache_range((unsigned long)ptr, 526 (unsigned long)(ptr + size)); 527 528 do_overwritten(); 529 break; 530 } 531 case CT_NONE: 532 default: 533 break; 534 } 535 536} 537 538static void lkdtm_handler(void) 539{ 540 unsigned long flags; 541 bool do_it = false; 542 543 spin_lock_irqsave(&count_lock, flags); 544 count--; 545 pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", 546 cp_name_to_str(cpoint), cp_type_to_str(cptype), count); 547 548 if (count == 0) { 549 do_it = true; 550 count = cpoint_count; 551 } 552 spin_unlock_irqrestore(&count_lock, flags); 553 554 if (do_it) 555 lkdtm_do_action(cptype); 556} 557 558static int lkdtm_register_cpoint(enum cname which) 559{ 560 int ret; 561 562 cpoint = CN_INVALID; 563 if (lkdtm.entry != NULL) 564 unregister_jprobe(&lkdtm); 565 566 switch (which) { 567 case CN_DIRECT: 568 lkdtm_do_action(cptype); 569 return 0; 570 case CN_INT_HARDWARE_ENTRY: 571 lkdtm.kp.symbol_name = "do_IRQ"; 572 lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; 573 break; 574 case CN_INT_HW_IRQ_EN: 575 lkdtm.kp.symbol_name = "handle_IRQ_event"; 576 lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; 577 break; 578 case CN_INT_TASKLET_ENTRY: 579 lkdtm.kp.symbol_name = "tasklet_action"; 580 lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; 581 break; 582 case CN_FS_DEVRW: 583 lkdtm.kp.symbol_name = "ll_rw_block"; 584 lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; 585 break; 586 case CN_MEM_SWAPOUT: 587 lkdtm.kp.symbol_name = "shrink_inactive_list"; 588 lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; 589 break; 590 case CN_TIMERADD: 591 lkdtm.kp.symbol_name = "hrtimer_start"; 592 lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; 593 break; 594 case CN_SCSI_DISPATCH_CMD: 595 lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; 596 lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; 597 break; 598 case CN_IDE_CORE_CP: 599#ifdef CONFIG_IDE 600 lkdtm.kp.symbol_name = "generic_ide_ioctl"; 601 lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; 602#else 603 pr_info("Crash point not available\n"); 604 return -EINVAL; 605#endif 606 break; 607 default: 608 pr_info("Invalid Crash Point\n"); 609 return -EINVAL; 610 } 611 612 cpoint = which; 613 if ((ret = register_jprobe(&lkdtm)) < 0) { 614 pr_info("Couldn't register jprobe\n"); 615 cpoint = CN_INVALID; 616 } 617 618 return ret; 619} 620 621static ssize_t do_register_entry(enum cname which, struct file *f, 622 const char __user *user_buf, size_t count, loff_t *off) 623{ 624 char *buf; 625 int err; 626 627 if (count >= PAGE_SIZE) 628 return -EINVAL; 629 630 buf = (char *)__get_free_page(GFP_KERNEL); 631 if (!buf) 632 return -ENOMEM; 633 if (copy_from_user(buf, user_buf, count)) { 634 free_page((unsigned long) buf); 635 return -EFAULT; 636 } 637 /* NULL-terminate and remove enter */ 638 buf[count] = '\0'; 639 strim(buf); 640 641 cptype = parse_cp_type(buf, count); 642 free_page((unsigned long) buf); 643 644 if (cptype == CT_NONE) 645 return -EINVAL; 646 647 err = lkdtm_register_cpoint(which); 648 if (err < 0) 649 return err; 650 651 *off += count; 652 653 return count; 654} 655 656/* Generic read callback that just prints out the available crash types */ 657static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, 658 size_t count, loff_t *off) 659{ 660 char *buf; 661 int i, n, out; 662 663 buf = (char *)__get_free_page(GFP_KERNEL); 664 if (buf == NULL) 665 return -ENOMEM; 666 667 n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); 668 for (i = 0; i < ARRAY_SIZE(cp_type); i++) 669 n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]); 670 buf[n] = '\0'; 671 672 out = simple_read_from_buffer(user_buf, count, off, 673 buf, n); 674 free_page((unsigned long) buf); 675 676 return out; 677} 678 679static int lkdtm_debugfs_open(struct inode *inode, struct file *file) 680{ 681 return 0; 682} 683 684 685static ssize_t int_hardware_entry(struct file *f, const char __user *buf, 686 size_t count, loff_t *off) 687{ 688 return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off); 689} 690 691static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, 692 size_t count, loff_t *off) 693{ 694 return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off); 695} 696 697static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, 698 size_t count, loff_t *off) 699{ 700 return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off); 701} 702 703static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, 704 size_t count, loff_t *off) 705{ 706 return do_register_entry(CN_FS_DEVRW, f, buf, count, off); 707} 708 709static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, 710 size_t count, loff_t *off) 711{ 712 return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off); 713} 714 715static ssize_t timeradd_entry(struct file *f, const char __user *buf, 716 size_t count, loff_t *off) 717{ 718 return do_register_entry(CN_TIMERADD, f, buf, count, off); 719} 720 721static ssize_t scsi_dispatch_cmd_entry(struct file *f, 722 const char __user *buf, size_t count, loff_t *off) 723{ 724 return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off); 725} 726 727static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, 728 size_t count, loff_t *off) 729{ 730 return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off); 731} 732 733/* Special entry to just crash directly. Available without KPROBEs */ 734static ssize_t direct_entry(struct file *f, const char __user *user_buf, 735 size_t count, loff_t *off) 736{ 737 enum ctype type; 738 char *buf; 739 740 if (count >= PAGE_SIZE) 741 return -EINVAL; 742 if (count < 1) 743 return -EINVAL; 744 745 buf = (char *)__get_free_page(GFP_KERNEL); 746 if (!buf) 747 return -ENOMEM; 748 if (copy_from_user(buf, user_buf, count)) { 749 free_page((unsigned long) buf); 750 return -EFAULT; 751 } 752 /* NULL-terminate and remove enter */ 753 buf[count] = '\0'; 754 strim(buf); 755 756 type = parse_cp_type(buf, count); 757 free_page((unsigned long) buf); 758 if (type == CT_NONE) 759 return -EINVAL; 760 761 pr_info("Performing direct entry %s\n", cp_type_to_str(type)); 762 lkdtm_do_action(type); 763 *off += count; 764 765 return count; 766} 767 768struct crash_entry { 769 const char *name; 770 const struct file_operations fops; 771}; 772 773static const struct crash_entry crash_entries[] = { 774 {"DIRECT", {.read = lkdtm_debugfs_read, 775 .llseek = generic_file_llseek, 776 .open = lkdtm_debugfs_open, 777 .write = direct_entry} }, 778 {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, 779 .llseek = generic_file_llseek, 780 .open = lkdtm_debugfs_open, 781 .write = int_hardware_entry} }, 782 {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, 783 .llseek = generic_file_llseek, 784 .open = lkdtm_debugfs_open, 785 .write = int_hw_irq_en} }, 786 {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, 787 .llseek = generic_file_llseek, 788 .open = lkdtm_debugfs_open, 789 .write = int_tasklet_entry} }, 790 {"FS_DEVRW", {.read = lkdtm_debugfs_read, 791 .llseek = generic_file_llseek, 792 .open = lkdtm_debugfs_open, 793 .write = fs_devrw_entry} }, 794 {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, 795 .llseek = generic_file_llseek, 796 .open = lkdtm_debugfs_open, 797 .write = mem_swapout_entry} }, 798 {"TIMERADD", {.read = lkdtm_debugfs_read, 799 .llseek = generic_file_llseek, 800 .open = lkdtm_debugfs_open, 801 .write = timeradd_entry} }, 802 {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, 803 .llseek = generic_file_llseek, 804 .open = lkdtm_debugfs_open, 805 .write = scsi_dispatch_cmd_entry} }, 806 {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, 807 .llseek = generic_file_llseek, 808 .open = lkdtm_debugfs_open, 809 .write = ide_core_cp_entry} }, 810}; 811 812static struct dentry *lkdtm_debugfs_root; 813 814static int __init lkdtm_module_init(void) 815{ 816 int ret = -EINVAL; 817 int n_debugfs_entries = 1; /* Assume only the direct entry */ 818 int i; 819 820 /* Register debugfs interface */ 821 lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); 822 if (!lkdtm_debugfs_root) { 823 pr_err("creating root dir failed\n"); 824 return -ENODEV; 825 } 826 827#ifdef CONFIG_KPROBES 828 n_debugfs_entries = ARRAY_SIZE(crash_entries); 829#endif 830 831 for (i = 0; i < n_debugfs_entries; i++) { 832 const struct crash_entry *cur = &crash_entries[i]; 833 struct dentry *de; 834 835 de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, 836 NULL, &cur->fops); 837 if (de == NULL) { 838 pr_err("could not create %s\n", cur->name); 839 goto out_err; 840 } 841 } 842 843 if (lkdtm_parse_commandline() == -EINVAL) { 844 pr_info("Invalid command\n"); 845 goto out_err; 846 } 847 848 if (cpoint != CN_INVALID && cptype != CT_NONE) { 849 ret = lkdtm_register_cpoint(cpoint); 850 if (ret < 0) { 851 pr_info("Invalid crash point %d\n", cpoint); 852 goto out_err; 853 } 854 pr_info("Crash point %s of type %s registered\n", 855 cpoint_name, cpoint_type); 856 } else { 857 pr_info("No crash points registered, enable through debugfs\n"); 858 } 859 860 return 0; 861 862out_err: 863 debugfs_remove_recursive(lkdtm_debugfs_root); 864 return ret; 865} 866 867static void __exit lkdtm_module_exit(void) 868{ 869 debugfs_remove_recursive(lkdtm_debugfs_root); 870 871 unregister_jprobe(&lkdtm); 872 pr_info("Crash point unregistered\n"); 873} 874 875module_init(lkdtm_module_init); 876module_exit(lkdtm_module_exit); 877 878MODULE_LICENSE("GPL"); 879MODULE_DESCRIPTION("Kprobe module for testing crash dumps");