lkdtm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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. #include <linux/kernel.h>
  34. #include <linux/fs.h>
  35. #include <linux/module.h>
  36. #include <linux/buffer_head.h>
  37. #include <linux/kprobes.h>
  38. #include <linux/list.h>
  39. #include <linux/init.h>
  40. #include <linux/interrupt.h>
  41. #include <linux/hrtimer.h>
  42. #include <linux/slab.h>
  43. #include <scsi/scsi_cmnd.h>
  44. #include <linux/debugfs.h>
  45. #ifdef CONFIG_IDE
  46. #include <linux/ide.h>
  47. #endif
  48. #define DEFAULT_COUNT 10
  49. #define REC_NUM_DEFAULT 10
  50. enum cname {
  51. INVALID,
  52. INT_HARDWARE_ENTRY,
  53. INT_HW_IRQ_EN,
  54. INT_TASKLET_ENTRY,
  55. FS_DEVRW,
  56. MEM_SWAPOUT,
  57. TIMERADD,
  58. SCSI_DISPATCH_CMD,
  59. IDE_CORE_CP,
  60. DIRECT,
  61. };
  62. enum ctype {
  63. NONE,
  64. PANIC,
  65. BUG,
  66. EXCEPTION,
  67. LOOP,
  68. OVERFLOW,
  69. CORRUPT_STACK,
  70. UNALIGNED_LOAD_STORE_WRITE,
  71. OVERWRITE_ALLOCATION,
  72. WRITE_AFTER_FREE,
  73. };
  74. static char* cp_name[] = {
  75. "INT_HARDWARE_ENTRY",
  76. "INT_HW_IRQ_EN",
  77. "INT_TASKLET_ENTRY",
  78. "FS_DEVRW",
  79. "MEM_SWAPOUT",
  80. "TIMERADD",
  81. "SCSI_DISPATCH_CMD",
  82. "IDE_CORE_CP",
  83. "DIRECT",
  84. };
  85. static char* cp_type[] = {
  86. "PANIC",
  87. "BUG",
  88. "EXCEPTION",
  89. "LOOP",
  90. "OVERFLOW",
  91. "CORRUPT_STACK",
  92. "UNALIGNED_LOAD_STORE_WRITE",
  93. "OVERWRITE_ALLOCATION",
  94. "WRITE_AFTER_FREE",
  95. };
  96. static struct jprobe lkdtm;
  97. static int lkdtm_parse_commandline(void);
  98. static void lkdtm_handler(void);
  99. static char* cpoint_name;
  100. static char* cpoint_type;
  101. static int cpoint_count = DEFAULT_COUNT;
  102. static int recur_count = REC_NUM_DEFAULT;
  103. static enum cname cpoint = INVALID;
  104. static enum ctype cptype = NONE;
  105. static int count = DEFAULT_COUNT;
  106. module_param(recur_count, int, 0644);
  107. MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
  108. "default is 10");
  109. module_param(cpoint_name, charp, 0644);
  110. MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
  111. module_param(cpoint_type, charp, 0644);
  112. MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\
  113. "hitting the crash point");
  114. module_param(cpoint_count, int, 0644);
  115. MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
  116. "crash point is to be hit to trigger action");
  117. static unsigned int jp_do_irq(unsigned int irq)
  118. {
  119. lkdtm_handler();
  120. jprobe_return();
  121. return 0;
  122. }
  123. static irqreturn_t jp_handle_irq_event(unsigned int irq,
  124. struct irqaction *action)
  125. {
  126. lkdtm_handler();
  127. jprobe_return();
  128. return 0;
  129. }
  130. static void jp_tasklet_action(struct softirq_action *a)
  131. {
  132. lkdtm_handler();
  133. jprobe_return();
  134. }
  135. static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
  136. {
  137. lkdtm_handler();
  138. jprobe_return();
  139. }
  140. struct scan_control;
  141. static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
  142. struct zone *zone,
  143. struct scan_control *sc)
  144. {
  145. lkdtm_handler();
  146. jprobe_return();
  147. return 0;
  148. }
  149. static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
  150. const enum hrtimer_mode mode)
  151. {
  152. lkdtm_handler();
  153. jprobe_return();
  154. return 0;
  155. }
  156. static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
  157. {
  158. lkdtm_handler();
  159. jprobe_return();
  160. return 0;
  161. }
  162. #ifdef CONFIG_IDE
  163. int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
  164. struct block_device *bdev, unsigned int cmd,
  165. unsigned long arg)
  166. {
  167. lkdtm_handler();
  168. jprobe_return();
  169. return 0;
  170. }
  171. #endif
  172. /* Return the crashpoint number or NONE if the name is invalid */
  173. static enum ctype parse_cp_type(const char *what, size_t count)
  174. {
  175. int i;
  176. for (i = 0; i < ARRAY_SIZE(cp_type); i++) {
  177. if (!strcmp(what, cp_type[i]))
  178. return i + 1;
  179. }
  180. return NONE;
  181. }
  182. static const char *cp_type_to_str(enum ctype type)
  183. {
  184. if (type == NONE || type < 0 || type > ARRAY_SIZE(cp_type))
  185. return "None";
  186. return cp_type[type - 1];
  187. }
  188. static const char *cp_name_to_str(enum cname name)
  189. {
  190. if (name == INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
  191. return "INVALID";
  192. return cp_name[name - 1];
  193. }
  194. static int lkdtm_parse_commandline(void)
  195. {
  196. int i;
  197. if (cpoint_count < 1 || recur_count < 1)
  198. return -EINVAL;
  199. count = cpoint_count;
  200. /* No special parameters */
  201. if (!cpoint_type && !cpoint_name)
  202. return 0;
  203. /* Neither or both of these need to be set */
  204. if (!cpoint_type || !cpoint_name)
  205. return -EINVAL;
  206. cptype = parse_cp_type(cpoint_type, strlen(cpoint_type));
  207. if (cptype == NONE)
  208. return -EINVAL;
  209. for (i = 0; i < ARRAY_SIZE(cp_name); i++) {
  210. if (!strcmp(cpoint_name, cp_name[i])) {
  211. cpoint = i + 1;
  212. return 0;
  213. }
  214. }
  215. /* Could not find a valid crash point */
  216. return -EINVAL;
  217. }
  218. static int recursive_loop(int a)
  219. {
  220. char buf[1024];
  221. memset(buf,0xFF,1024);
  222. recur_count--;
  223. if (!recur_count)
  224. return 0;
  225. else
  226. return recursive_loop(a);
  227. }
  228. static void lkdtm_do_action(enum ctype which)
  229. {
  230. switch (which) {
  231. case PANIC:
  232. panic("dumptest");
  233. break;
  234. case BUG:
  235. BUG();
  236. break;
  237. case EXCEPTION:
  238. *((int *) 0) = 0;
  239. break;
  240. case LOOP:
  241. for (;;)
  242. ;
  243. break;
  244. case OVERFLOW:
  245. (void) recursive_loop(0);
  246. break;
  247. case CORRUPT_STACK: {
  248. volatile u32 data[8];
  249. volatile u32 *p = data;
  250. p[12] = 0x12345678;
  251. break;
  252. }
  253. case UNALIGNED_LOAD_STORE_WRITE: {
  254. static u8 data[5] __attribute__((aligned(4))) = {1, 2,
  255. 3, 4, 5};
  256. u32 *p;
  257. u32 val = 0x12345678;
  258. p = (u32 *)(data + 1);
  259. if (*p == 0)
  260. val = 0x87654321;
  261. *p = val;
  262. break;
  263. }
  264. case OVERWRITE_ALLOCATION: {
  265. size_t len = 1020;
  266. u32 *data = kmalloc(len, GFP_KERNEL);
  267. data[1024 / sizeof(u32)] = 0x12345678;
  268. kfree(data);
  269. break;
  270. }
  271. case WRITE_AFTER_FREE: {
  272. size_t len = 1024;
  273. u32 *data = kmalloc(len, GFP_KERNEL);
  274. kfree(data);
  275. schedule();
  276. memset(data, 0x78, len);
  277. break;
  278. }
  279. case NONE:
  280. default:
  281. break;
  282. }
  283. }
  284. static void lkdtm_handler(void)
  285. {
  286. count--;
  287. printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n",
  288. cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
  289. if (count == 0) {
  290. lkdtm_do_action(cptype);
  291. count = cpoint_count;
  292. }
  293. }
  294. static int lkdtm_register_cpoint(enum cname which)
  295. {
  296. int ret;
  297. cpoint = INVALID;
  298. if (lkdtm.entry != NULL)
  299. unregister_jprobe(&lkdtm);
  300. switch (which) {
  301. case DIRECT:
  302. lkdtm_do_action(cptype);
  303. return 0;
  304. case INT_HARDWARE_ENTRY:
  305. lkdtm.kp.symbol_name = "do_IRQ";
  306. lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
  307. break;
  308. case INT_HW_IRQ_EN:
  309. lkdtm.kp.symbol_name = "handle_IRQ_event";
  310. lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
  311. break;
  312. case INT_TASKLET_ENTRY:
  313. lkdtm.kp.symbol_name = "tasklet_action";
  314. lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
  315. break;
  316. case FS_DEVRW:
  317. lkdtm.kp.symbol_name = "ll_rw_block";
  318. lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
  319. break;
  320. case MEM_SWAPOUT:
  321. lkdtm.kp.symbol_name = "shrink_inactive_list";
  322. lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list;
  323. break;
  324. case TIMERADD:
  325. lkdtm.kp.symbol_name = "hrtimer_start";
  326. lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
  327. break;
  328. case SCSI_DISPATCH_CMD:
  329. lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
  330. lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
  331. break;
  332. case IDE_CORE_CP:
  333. #ifdef CONFIG_IDE
  334. lkdtm.kp.symbol_name = "generic_ide_ioctl";
  335. lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
  336. #else
  337. printk(KERN_INFO "lkdtm: Crash point not available\n");
  338. return -EINVAL;
  339. #endif
  340. break;
  341. default:
  342. printk(KERN_INFO "lkdtm: Invalid Crash Point\n");
  343. return -EINVAL;
  344. }
  345. cpoint = which;
  346. if ((ret = register_jprobe(&lkdtm)) < 0) {
  347. printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
  348. cpoint = INVALID;
  349. }
  350. return ret;
  351. }
  352. static ssize_t do_register_entry(enum cname which, struct file *f,
  353. const char __user *user_buf, size_t count, loff_t *off)
  354. {
  355. char *buf;
  356. int err;
  357. if (count >= PAGE_SIZE)
  358. return -EINVAL;
  359. buf = (char *)__get_free_page(GFP_KERNEL);
  360. if (!buf)
  361. return -ENOMEM;
  362. if (copy_from_user(buf, user_buf, count)) {
  363. free_page((unsigned long) buf);
  364. return -EFAULT;
  365. }
  366. /* NULL-terminate and remove enter */
  367. buf[count] = '\0';
  368. strim(buf);
  369. cptype = parse_cp_type(buf, count);
  370. free_page((unsigned long) buf);
  371. if (cptype == NONE)
  372. return -EINVAL;
  373. err = lkdtm_register_cpoint(which);
  374. if (err < 0)
  375. return err;
  376. *off += count;
  377. return count;
  378. }
  379. /* Generic read callback that just prints out the available crash types */
  380. static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf,
  381. size_t count, loff_t *off)
  382. {
  383. char *buf;
  384. int i, n, out;
  385. buf = (char *)__get_free_page(GFP_KERNEL);
  386. n = snprintf(buf, PAGE_SIZE, "Available crash types:\n");
  387. for (i = 0; i < ARRAY_SIZE(cp_type); i++)
  388. n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]);
  389. buf[n] = '\0';
  390. out = simple_read_from_buffer(user_buf, count, off,
  391. buf, n);
  392. free_page((unsigned long) buf);
  393. return out;
  394. }
  395. static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
  396. {
  397. return 0;
  398. }
  399. static ssize_t int_hardware_entry(struct file *f, const char __user *buf,
  400. size_t count, loff_t *off)
  401. {
  402. return do_register_entry(INT_HARDWARE_ENTRY, f, buf, count, off);
  403. }
  404. static ssize_t int_hw_irq_en(struct file *f, const char __user *buf,
  405. size_t count, loff_t *off)
  406. {
  407. return do_register_entry(INT_HW_IRQ_EN, f, buf, count, off);
  408. }
  409. static ssize_t int_tasklet_entry(struct file *f, const char __user *buf,
  410. size_t count, loff_t *off)
  411. {
  412. return do_register_entry(INT_TASKLET_ENTRY, f, buf, count, off);
  413. }
  414. static ssize_t fs_devrw_entry(struct file *f, const char __user *buf,
  415. size_t count, loff_t *off)
  416. {
  417. return do_register_entry(FS_DEVRW, f, buf, count, off);
  418. }
  419. static ssize_t mem_swapout_entry(struct file *f, const char __user *buf,
  420. size_t count, loff_t *off)
  421. {
  422. return do_register_entry(MEM_SWAPOUT, f, buf, count, off);
  423. }
  424. static ssize_t timeradd_entry(struct file *f, const char __user *buf,
  425. size_t count, loff_t *off)
  426. {
  427. return do_register_entry(TIMERADD, f, buf, count, off);
  428. }
  429. static ssize_t scsi_dispatch_cmd_entry(struct file *f,
  430. const char __user *buf, size_t count, loff_t *off)
  431. {
  432. return do_register_entry(SCSI_DISPATCH_CMD, f, buf, count, off);
  433. }
  434. static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf,
  435. size_t count, loff_t *off)
  436. {
  437. return do_register_entry(IDE_CORE_CP, f, buf, count, off);
  438. }
  439. /* Special entry to just crash directly. Available without KPROBEs */
  440. static ssize_t direct_entry(struct file *f, const char __user *user_buf,
  441. size_t count, loff_t *off)
  442. {
  443. enum ctype type;
  444. char *buf;
  445. if (count >= PAGE_SIZE)
  446. return -EINVAL;
  447. if (count < 1)
  448. return -EINVAL;
  449. buf = (char *)__get_free_page(GFP_KERNEL);
  450. if (!buf)
  451. return -ENOMEM;
  452. if (copy_from_user(buf, user_buf, count)) {
  453. free_page((unsigned long) buf);
  454. return -EFAULT;
  455. }
  456. /* NULL-terminate and remove enter */
  457. buf[count] = '\0';
  458. strim(buf);
  459. type = parse_cp_type(buf, count);
  460. free_page((unsigned long) buf);
  461. if (type == NONE)
  462. return -EINVAL;
  463. printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
  464. cp_type_to_str(type));
  465. lkdtm_do_action(type);
  466. *off += count;
  467. return count;
  468. }
  469. struct crash_entry {
  470. const char *name;
  471. const struct file_operations fops;
  472. };
  473. static const struct crash_entry crash_entries[] = {
  474. {"DIRECT", {.read = lkdtm_debugfs_read,
  475. .open = lkdtm_debugfs_open,
  476. .write = direct_entry} },
  477. {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read,
  478. .open = lkdtm_debugfs_open,
  479. .write = int_hardware_entry} },
  480. {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read,
  481. .open = lkdtm_debugfs_open,
  482. .write = int_hw_irq_en} },
  483. {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read,
  484. .open = lkdtm_debugfs_open,
  485. .write = int_tasklet_entry} },
  486. {"FS_DEVRW", {.read = lkdtm_debugfs_read,
  487. .open = lkdtm_debugfs_open,
  488. .write = fs_devrw_entry} },
  489. {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read,
  490. .open = lkdtm_debugfs_open,
  491. .write = mem_swapout_entry} },
  492. {"TIMERADD", {.read = lkdtm_debugfs_read,
  493. .open = lkdtm_debugfs_open,
  494. .write = timeradd_entry} },
  495. {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read,
  496. .open = lkdtm_debugfs_open,
  497. .write = scsi_dispatch_cmd_entry} },
  498. {"IDE_CORE_CP", {.read = lkdtm_debugfs_read,
  499. .open = lkdtm_debugfs_open,
  500. .write = ide_core_cp_entry} },
  501. };
  502. static struct dentry *lkdtm_debugfs_root;
  503. static int __init lkdtm_module_init(void)
  504. {
  505. int ret = -EINVAL;
  506. int n_debugfs_entries = 1; /* Assume only the direct entry */
  507. int i;
  508. /* Register debugfs interface */
  509. lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
  510. if (!lkdtm_debugfs_root) {
  511. printk(KERN_ERR "lkdtm: creating root dir failed\n");
  512. return -ENODEV;
  513. }
  514. #ifdef CONFIG_KPROBES
  515. n_debugfs_entries = ARRAY_SIZE(crash_entries);
  516. #endif
  517. for (i = 0; i < n_debugfs_entries; i++) {
  518. const struct crash_entry *cur = &crash_entries[i];
  519. struct dentry *de;
  520. de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
  521. NULL, &cur->fops);
  522. if (de == NULL) {
  523. printk(KERN_ERR "lkdtm: could not create %s\n",
  524. cur->name);
  525. goto out_err;
  526. }
  527. }
  528. if (lkdtm_parse_commandline() == -EINVAL) {
  529. printk(KERN_INFO "lkdtm: Invalid command\n");
  530. goto out_err;
  531. }
  532. if (cpoint != INVALID && cptype != NONE) {
  533. ret = lkdtm_register_cpoint(cpoint);
  534. if (ret < 0) {
  535. printk(KERN_INFO "lkdtm: Invalid crash point %d\n",
  536. cpoint);
  537. goto out_err;
  538. }
  539. printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n",
  540. cpoint_name, cpoint_type);
  541. } else {
  542. printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n");
  543. }
  544. return 0;
  545. out_err:
  546. debugfs_remove_recursive(lkdtm_debugfs_root);
  547. return ret;
  548. }
  549. static void __exit lkdtm_module_exit(void)
  550. {
  551. debugfs_remove_recursive(lkdtm_debugfs_root);
  552. unregister_jprobe(&lkdtm);
  553. printk(KERN_INFO "lkdtm: Crash point unregistered\n");
  554. }
  555. module_init(lkdtm_module_init);
  556. module_exit(lkdtm_module_exit);
  557. MODULE_LICENSE("GPL");