lkdtm.c 14 KB

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