Advertisement
xosski

USB URB debugging manipulation fun

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