Advertisement
xosski

USB Debug logging

Dec 26th, 2024
9
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.34 KB | None | 0 0
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/kprobes.h>
  4. #include <linux/usb.h>
  5. #include <linux/slab.h>
  6. #include <linux/debugfs.h>
  7. #include <linux/uaccess.h>
  8. #include <linux/spinlock.h>
  9. #include <linux/seq_file.h>
  10. #include <linux/jiffies.h> // For timestamping
  11.  
  12. MODULE_LICENSE("GPL");
  13. MODULE_AUTHOR("Nediakin");
  14. MODULE_DESCRIPTION("USB URB send logger via kprobe with debugfs interface and ring buffer");
  15.  
  16. // Module parameters for flexibility
  17. static int ring_buffer_size = 1024;
  18. module_param(ring_buffer_size, int, 0444);
  19. MODULE_PARM_DESC(ring_buffer_size, "Number of URB log entries in ring buffer");
  20.  
  21. static int max_data_dump = 64;
  22. module_param(max_data_dump, int, 0444);
  23. MODULE_PARM_DESC(max_data_dump, "Maximum number of data bytes to log per URB");
  24.  
  25. static bool logging_enabled = true;
  26. module_param(logging_enabled, bool, 0644);
  27. MODULE_PARM_DESC(logging_enabled, "Enable or disable logging");
  28.  
  29. // Structure for logging URB entries
  30. struct urb_log_entry {
  31. u64 timestamp;
  32. struct urb *urb;
  33. struct usb_device *dev;
  34. unsigned int pipe;
  35. unsigned int length;
  36. bool has_setup;
  37. __u8 setup[8];
  38. unsigned int data_len;
  39. __u8 data[64];
  40. };
  41.  
  42. // Ring buffer for log entries
  43. static struct urb_log_entry *log_buffer;
  44. static unsigned int log_head;
  45. static unsigned int log_tail;
  46. static spinlock_t log_lock;
  47.  
  48. // Debugfs entries
  49. static struct dentry *debug_dir;
  50. static struct dentry *debug_file;
  51.  
  52. // Function declarations
  53. static int handler_pre(struct kprobe *p, struct pt_regs *regs);
  54. static void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags);
  55.  
  56. // Kprobe definition
  57. static struct kprobe kp = {
  58. .symbol_name = "usb_submit_urb",
  59. .pre_handler = handler_pre,
  60. .post_handler = handler_post,
  61. };
  62.  
  63. // Function to add URB log entry to the ring buffer
  64. static void add_urb_log_entry(struct urb *urb)
  65. {
  66. unsigned long flags;
  67. unsigned int next;
  68. struct urb_log_entry *entry;
  69. unsigned int len_to_copy;
  70.  
  71. spin_lock_irqsave(&log_lock, flags);
  72.  
  73. // Handle buffer full situation - dynamic resizing
  74. next = (log_head + 1) % ring_buffer_size;
  75. if (next == log_tail) {
  76. // Buffer full, resize it
  77. pr_info("[USB_KPROBE] Buffer full, resizing to %d entries\n", ring_buffer_size * 2);
  78. unsigned int new_size = ring_buffer_size * 2;
  79. struct urb_log_entry *new_buffer = krealloc(log_buffer, sizeof(struct urb_log_entry) * new_size, GFP_KERNEL);
  80. if (new_buffer) {
  81. log_buffer = new_buffer;
  82. ring_buffer_size = new_size;
  83. } else {
  84. pr_err("[USB_KPROBE] Failed to resize buffer\n");
  85. }
  86. log_tail = (log_tail + 1) % ring_buffer_size; // Advance the tail to ensure we don't lose data
  87. }
  88.  
  89. entry = &log_buffer[log_head];
  90. entry->timestamp = jiffies;
  91. entry->urb = urb;
  92. entry->dev = urb->dev;
  93. entry->pipe = urb->pipe;
  94. entry->length = urb->transfer_buffer_length;
  95.  
  96. if (urb->setup_packet) {
  97. entry->has_setup = true;
  98. memcpy(entry->setup, urb->setup_packet, 8);
  99. } else {
  100. entry->has_setup = false;
  101. }
  102.  
  103. if (urb->transfer_buffer && urb->transfer_buffer_length > 0) {
  104. len_to_copy = (urb->transfer_buffer_length > max_data_dump) ? max_data_dump : urb->transfer_buffer_length;
  105. memcpy(entry->data, urb->transfer_buffer, len_to_copy);
  106. entry->data_len = len_to_copy;
  107. } else {
  108. entry->data_len = 0;
  109. }
  110.  
  111. log_head = next;
  112. spin_unlock_irqrestore(&log_lock, flags);
  113. }
  114.  
  115. // Kprobe pre-handler
  116. static int handler_pre(struct kprobe *p, struct pt_regs *regs)
  117. {
  118. struct urb *urb = (struct urb *)regs->di;
  119.  
  120. if (logging_enabled && urb) {
  121. add_urb_log_entry(urb);
  122. }
  123.  
  124. return 0;
  125. }
  126.  
  127. // Kprobe post-handler
  128. static void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
  129. {
  130. // Post-handler implementation if needed
  131. }
  132.  
  133. // Seq_file operations to display log entries
  134. static void *urb_log_seq_start(struct seq_file *s, loff_t *pos)
  135. {
  136. unsigned long flags;
  137. unsigned int count;
  138. void *ret = NULL;
  139.  
  140. spin_lock_irqsave(&log_lock, flags);
  141. count = (log_head >= log_tail) ? (log_head - log_tail) : (ring_buffer_size - log_tail + log_head);
  142.  
  143. if (*pos < count) {
  144. unsigned int idx = (log_tail + *pos) % ring_buffer_size;
  145. ret = &log_buffer[idx];
  146. }
  147. spin_unlock_irqrestore(&log_lock, flags);
  148.  
  149. return ret;
  150. }
  151.  
  152. static void *urb_log_seq_next(struct seq_file *s, void *v, loff_t *pos)
  153. {
  154. unsigned long flags;
  155. unsigned int count;
  156. void *ret = NULL;
  157.  
  158. (*pos)++;
  159. spin_lock_irqsave(&log_lock, flags);
  160. count = (log_head >= log_tail) ? (log_head - log_tail) : (ring_buffer_size - log_tail + log_head);
  161.  
  162. if (*pos < count) {
  163. unsigned int idx = (log_tail + *pos) % ring_buffer_size;
  164. ret = &log_buffer[idx];
  165. }
  166. spin_unlock_irqrestore(&log_lock, flags);
  167.  
  168. return ret;
  169. }
  170.  
  171. static void urb_log_seq_stop(struct seq_file *s, void *v)
  172. {
  173. // Nothing to do
  174. }
  175.  
  176. static int urb_log_seq_show(struct seq_file *s, void *v)
  177. {
  178. struct urb_log_entry *entry = v;
  179. const char *manufacturer = NULL;
  180. const char *product = NULL;
  181. int i;
  182.  
  183. if (entry->dev) {
  184. manufacturer = entry->dev->manufacturer;
  185. product = entry->dev->product;
  186. }
  187.  
  188. seq_printf(s, "Time: %llu | urb=%p dev=%p pipe=0x%x length=%u\n",
  189. (unsigned long long)entry->timestamp, entry->urb, entry->dev,
  190. entry->pipe, entry->length);
  191.  
  192. if (manufacturer) {
  193. seq_printf(s, " Manufacturer: %s\n", manufacturer);
  194. } else {
  195. seq_printf(s, " Manufacturer: N/A\n");
  196. }
  197.  
  198. if (product) {
  199. seq_printf(s, " Product: %s\n", product);
  200. } else {
  201. seq_printf(s, " Product: N/A\n");
  202. }
  203.  
  204. if (entry->has_setup) {
  205. seq_printf(s, " Setup: ");
  206. for (i = 0; i < 8; i++)
  207. seq_printf(s, "%02X ", entry->setup[i]);
  208. seq_putc(s, '\n');
  209. }
  210.  
  211. if (entry->data_len > 0) {
  212. seq_printf(s, " Data (%u bytes): ", entry->data_len);
  213. for (i = 0; i < entry->data_len; i++)
  214. seq_printf(s, "%02X ", entry->data[i]);
  215. seq_putc(s, '\n');
  216. }
  217.  
  218. seq_puts(s, "\n");
  219. return 0;
  220. }
  221.  
  222. static const struct seq_operations urb_log_seq_ops = {
  223. .start = urb_log_seq_start,
  224. .next = urb_log_seq_next,
  225. .stop = urb_log_seq_stop,
  226. .show = urb_log_seq_show,
  227. };
  228.  
  229. static int urb_log_open(struct inode *inode, struct file *file)
  230. {
  231. return seq_open(file, &urb_log_seq_ops);
  232. }
  233.  
  234. static const struct file_operations urb_log_fops = {
  235. .owner = THIS_MODULE,
  236. .open = urb_log_open,
  237. .read = seq_read,
  238. .llseek = seq_lseek,
  239. .release = seq_release,
  240. };
  241.  
  242. // Module initialization
  243. static int __init usb_kprobe_init(void)
  244. {
  245. int ret;
  246.  
  247. if (ring_buffer_size <= 0)
  248. ring_buffer_size = 1024; // Default value if invalid
  249.  
  250. log_buffer = kzalloc(sizeof(struct urb_log_entry) * ring_buffer_size, GFP_KERNEL);
  251. if (!log_buffer)
  252. return -ENOMEM;
  253.  
  254. spin_lock_init(&log_lock);
  255. log_head = 0;
  256. log_tail = 0;
  257.  
  258. // Create debugfs entries
  259. debug_dir = debugfs_create_dir("usb_kprobe", NULL);
  260. if (!debug_dir) {
  261. kfree(log_buffer);
  262. return -ENOMEM;
  263. }
  264.  
  265. debug_file = debugfs_create_file("usb_kprobe_logs", 0444, debug_dir, NULL, &urb_log_fops);
  266. if (!debug_file) {
  267. debugfs_remove_recursive(debug_dir);
  268. kfree(log_buffer);
  269. return -ENOMEM;
  270. }
  271.  
  272. // Register the kprobe
  273. ret = register_kprobe(&kp);
  274. if (ret < 0) {
  275. debugfs_remove_recursive(debug_dir);
  276. kfree(log_buffer);
  277. printk(KERN_ERR "[USB_KPROBE] register_kprobe failed, returned %d\n", ret);
  278. return ret;
  279. }
  280.  
  281. printk(KERN_INFO "[USB_KPROBE] Module loaded, kprobe on usb_submit_urb installed\n");
  282. printk(KERN_INFO "[USB_KPROBE] Use `cat /sys/kernel/debug/usb_kprobe/usb_kprobe_logs` to view logs.\n");
  283. return 0;
  284. }
  285.  
  286. // Module exit function
  287. static void __exit usb_kprobe_exit(void)
  288. {
  289. unregister_kprobe(&kp);
  290. debugfs_remove_recursive(debug_dir);
  291. kfree(log_buffer);
  292. printk(KERN_INFO "[USB_KPROBE] Module unloaded, kprobe removed\n");
  293. }
  294.  
  295. module_init(usb_kprobe_init);
  296. module_exit(usb_kprobe_exit);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement