tracer_main.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include "linux/gfp.h"
  3. #include "linux/personality.h"
  4. #include "linux/pid.h"
  5. #include "linux/rcupdate.h"
  6. #include "linux/sched.h"
  7. #include "linux/spinlock.h"
  8. #include "linux/wait.h"
  9. #include <linux/spinlock_types.h>
  10. #include <linux/kernel.h>
  11. #include <linux/export.h>
  12. #include <linux/cdev.h>
  13. #include <linux/types.h>
  14. #include <linux/seq_file.h>
  15. #include <linux/printk.h>
  16. #include <linux/module.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/kprobes.h>
  19. #include <linux/miscdevice.h>
  20. #include <linux/fs.h>
  21. #include <linux/hashtable.h>
  22. #include <linux/slab.h>
  23. #include <linux/kthread.h>
  24. #include <linux/string.h>
  25. #include <asm/atomic.h>
  26. #include "tracer.h"
  27. #include "ktracer.h"
  28. #include "kmodules.h"
  29. #define PRINT_ALERT_FORMAT "%s %s\n"
  30. #define IOCTL_ENTRY "[tracer_ioctl]"
  31. #define WRONG_PID "Process not found."
  32. wait_queue_head_t wq;
  33. spinlock_t events_lock;
  34. LIST_HEAD(events_list);
  35. DEFINE_HASHTABLE(procs_table, PROCS_TABLE_SIZE);
  36. DEFINE_HASHTABLE(addr_table, PROCS_TABLE_SIZE);
  37. static struct proc_dir_entry *tracer_proc;
  38. static struct kretprobe *probes[] = { &kmalloc_probe, &kfree_probe,
  39. &sched_probe, &lock_probe,
  40. &unlock_probe, &up_probe,
  41. &down_probe };
  42. static inline void tracer_init_data(struct tracer_data *data, pid_t tgid)
  43. {
  44. init_mem_data(&data->kmalloc_data);
  45. init_mem_data(&data->kfree_data);
  46. arch_atomic_set(&data->sched_calls, 0);
  47. arch_atomic_set(&data->lock_calls, 0);
  48. arch_atomic_set(&data->unlock_calls, 0);
  49. arch_atomic_set(&data->up_calls, 0);
  50. arch_atomic_set(&data->down_calls, 0);
  51. data->tgid = tgid;
  52. }
  53. static int tracer_proc_show(struct seq_file *m, void *v)
  54. {
  55. struct tracer_data *crt;
  56. struct hlist_node *tmp;
  57. int i;
  58. seq_printf(m, PRINT_FORMAT, PRINT_PID, PRINT_KMALLOC, PRINT_KFREE,
  59. PRINT_KMALLOC_MEM, PRINT_KFREE_MEM, PRINT_SCHED, PRINT_UP,
  60. PRINT_DOWN, PRINT_LOCK, PRINT_UNLOCK);
  61. hash_for_each_safe(procs_table, i, tmp, crt, node) {
  62. seq_printf(m, PRINT_HASH_FORMAT, crt->tgid,
  63. arch_atomic_read(&crt->kmalloc_data.calls),
  64. arch_atomic_read(&crt->kfree_data.calls),
  65. arch_atomic_read(&crt->kmalloc_data.mem),
  66. arch_atomic_read(&crt->kfree_data.mem),
  67. arch_atomic_read(&crt->sched_calls),
  68. arch_atomic_read(&crt->up_calls),
  69. arch_atomic_read(&crt->down_calls),
  70. arch_atomic_read(&crt->lock_calls),
  71. arch_atomic_read(&crt->unlock_calls));
  72. }
  73. return 0;
  74. }
  75. static int tracer_proc_open(struct inode *inode, struct file *file)
  76. {
  77. if (inode == NULL || file == NULL)
  78. return -EINVAL;
  79. return single_open(file, tracer_proc_show, NULL);
  80. }
  81. static inline long tracer_add_proc(unsigned long arg)
  82. {
  83. struct task_struct *task;
  84. struct tracer_data *data;
  85. task = get_proc(arg);
  86. if (task == NULL) {
  87. pr_alert(PRINT_ALERT_FORMAT, IOCTL_ENTRY, WRONG_PID);
  88. return -ESRCH;
  89. }
  90. data = kmalloc(sizeof(struct tracer_data), GFP_NOWAIT);
  91. if (data == NULL)
  92. return -ENOMEM;
  93. tracer_init_data(data, arg);
  94. hash_add(procs_table, &data->node, arg);
  95. return 0;
  96. }
  97. static inline long tracer_rm_proc(unsigned long arg)
  98. {
  99. struct tracer_data *data;
  100. struct hlist_node *tmp;
  101. int i;
  102. hash_for_each_safe(procs_table, i, tmp, data, node) {
  103. if (data->tgid == arg) {
  104. hash_del(&data->node);
  105. kfree(data);
  106. return 0;
  107. }
  108. }
  109. pr_alert(PRINT_ALERT_FORMAT, IOCTL_ENTRY, WRONG_PID);
  110. return -ESRCH;
  111. }
  112. static long tracer_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  113. {
  114. if (cmd == TRACER_ADD_PROCESS)
  115. return tracer_add_proc(arg);
  116. else if (cmd == TRACER_REMOVE_PROCESS)
  117. return tracer_rm_proc(arg);
  118. return -EPERM;
  119. }
  120. static inline int tracer_init_watchers(void)
  121. {
  122. int n = ARRAY_SIZE(probes);
  123. int i;
  124. int ret;
  125. for (i = 0; i < n; i++) {
  126. ret = register_kretprobe(probes[i]);
  127. if (ret < 0)
  128. return ret;
  129. }
  130. return 0;
  131. }
  132. static inline void tracer_remove_watchers(void)
  133. {
  134. int n;
  135. int i;
  136. n = ARRAY_SIZE(probes);
  137. for (i = 0; i < n; i++)
  138. unregister_kretprobe(probes[i]);
  139. }
  140. static inline void tracer_clear_hashtables(void)
  141. {
  142. struct tracer_data *data_t;
  143. struct addr_data *data_a;
  144. struct hlist_node *tmp;
  145. int i;
  146. hash_for_each_safe(procs_table, i, tmp, data_t, node) {
  147. kfree(data_t);
  148. }
  149. hash_for_each_safe(addr_table, i, tmp, data_a, node) {
  150. kfree(data_a);
  151. }
  152. }
  153. static const struct file_operations tracer_ops = { .unlocked_ioctl =
  154. tracer_ioctl };
  155. static const struct proc_ops tracer_proc_ops = { .proc_open = tracer_proc_open,
  156. .proc_read = seq_read,
  157. .proc_release =
  158. single_release };
  159. static struct miscdevice tracer_device = { .minor = TRACER_DEV_MINOR,
  160. .name = TRACER_DEV_NAME,
  161. .fops = &tracer_ops };
  162. static int tracer_init(void)
  163. {
  164. int err;
  165. tracer_proc =
  166. proc_create(TRACER_DEV_NAME, PROC_MODE, NULL, &tracer_proc_ops);
  167. if (!tracer_proc)
  168. return -ENOMEM;
  169. err = misc_register(&tracer_device);
  170. if (err < 0)
  171. return err;
  172. tracer_init_watchers();
  173. hash_init(procs_table);
  174. hash_init(addr_table);
  175. return 0;
  176. }
  177. static void tracer_exit(void)
  178. {
  179. misc_deregister(&tracer_device);
  180. proc_remove(tracer_proc);
  181. tracer_remove_watchers();
  182. tracer_clear_hashtables();
  183. }
  184. module_init(tracer_init);
  185. module_exit(tracer_exit);
  186. MODULE_DESCRIPTION("Linux kernel tracer");
  187. MODULE_AUTHOR("Anton Puiu <anton.puiu@email.com>");
  188. MODULE_LICENSE("GPL v2");