Skip to content

Instantly share code, notes, and snippets.

@nefigtut
Last active October 3, 2018 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nefigtut/33d56e3870b67493cc867344aed2a062 to your computer and use it in GitHub Desktop.
Save nefigtut/33d56e3870b67493cc867344aed2a062 to your computer and use it in GitHub Desktop.
hid debug ring buffer fuzzer
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 63247ac4a9ce..3d2b11923151 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -35,11 +35,13 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
+#include <linux/random.h>
#include <linux/hid.h>
#include <linux/hid-debug.h>
static struct dentry *hid_debug_root;
+void hid_debug_fuzz(struct hid_device *);
struct hid_usage_entry {
unsigned page;
@@ -730,6 +732,30 @@ void hid_debug_event(struct hid_device *hdev, char *buf)
}
EXPORT_SYMBOL_GPL(hid_debug_event);
+/* FUZZ */
+void hid_debug_fuzz(struct hid_device *hdev)
+{
+ unsigned char n, i, seq, buf[512];
+ unsigned short j, wsize[10];
+
+ get_random_bytes(&n, 1);
+ n = n % 9 + 1;
+ get_random_bytes(wsize, 20);
+
+ for(i=0; i<n; i++) {
+ seq = 1;
+ for(j=0; j<wsize[i]%500; j++) {
+ if (seq == 15) seq = 1; else seq++;
+ buf[j] = (seq << 4) | (i + 1);
+ }
+ buf[j] = 255;
+ buf[j+1] = 0;
+
+ hid_debug_event(hdev, buf);
+ }
+}
+
+
void hid_dump_report(struct hid_device *hid, int type, u8 *data,
int size)
{
@@ -1154,6 +1180,8 @@ static int hid_debug_events_open(struct inode *inode, struct file *file)
list_add_tail(&list->node, &list->hdev->debug_list);
spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags);
+hid_debug_event(list->hdev, "FUZZ.TEST.START\n");
+
out:
return err;
}
@@ -1262,6 +1290,9 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
ret = -EFAULT;
kfree(tmpbuf);
+ /* FUZZ */
+ hid_debug_fuzz(list->hdev);
+
out:
mutex_unlock(&list->read_mutex);
return ret;
/* This is a HID debug ring buffer fuzzing reader. It reads random-sized chunks and
verifies they are not damaged. As the ring buffer overwrites the oldest data, just
calculating CRC won't work. The proper data is where higher nibble is increasing by
one and the lower one is constant until 0xff.
The system must have at least one HID debug directory in /sys/kernel/debug/hid
*/
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define HID_DEBUG_FILE "/sys/kernel/debug/hid/%s/events"
#define MAX_BUF_SIZE 600
void main(int argc, char *argv[])
{
DIR *hiddir;
struct dirent *de;
unsigned char name[128], buf[MAX_BUF_SIZE];
size_t size;
int fd, ret, dnum, i, j, fail, n;
unsigned char prevseq, seq, previd, id;
if (argc > 1) {
snprintf(name, sizeof(name), HID_DEBUG_FILE, argv[1]);
printf("using hid device debug event file: %s\n", name);
} else {
hiddir = opendir("/sys/kernel/debug/hid");
if (!hiddir) {
perror("opendir(/sys/kernel/debug/hid)");
goto out;
}
dnum = 0;
while ((de = readdir(hiddir)) != NULL) {
if (de->d_type != DT_DIR) continue;
if(!strcmp(de->d_name, ".")) continue;
if(!strcmp(de->d_name, "..")) continue;
dnum++;
printf("dnum = %d, found hid debug dir %s\n", dnum, de->d_name);
snprintf(name, sizeof(name), HID_DEBUG_FILE, de->d_name);
}
if (dnum == 0) {
printf("dnum = %d, no hid device debug dirs found\n", dnum);
goto out_close_dir;
}
if (dnum > 1) {
printf("dnum = %d, more that 1 hid device debug dir found\n", dnum);
printf("specify needed one as the 1st argument\n", dnum);
goto out_close_dir;
}
printf("using hid device debug event file: %s\n", name);
}
fd = open(name, O_RDONLY);
if (fd < 0) {
perror("open()");
goto out_close_dir;
}
j = 0;
while(1) {
size = rand() % (MAX_BUF_SIZE - 1) + 1;
ret = read(fd, buf, size);
if (ret < 0) {
perror("read()");
goto out_close;
}
if (ret == 0) {
printf("read() ret is 0, this is fine\n");
continue;
}
if (ret > size) printf("\nuser buffer >>> OVERWRITE <<<\n\n");
/* skip the fuzzer header */
i = 0;
if (!strncmp(buf, "FUZZ.TEST.", 10)) i+=16;
/* verify the read content */
fail = prevseq = seq = previd = id = 0;
while(i < ret) {
if (buf[i] == 255) {
i++;
prevseq = seq = id = 0;
//printf("| ");
continue;
}
seq = buf[i] >> 4;
id = buf[i] & 0x0f;
//printf("%2.2x ", buf[i]);
i++;
if (prevseq == 0) {
prevseq = seq;
previd = id;
continue;
}
if (prevseq == 15)
prevseq = 1;
else
prevseq++;
if ((id != previd) || (prevseq != seq)) {
fail = 1;
printf("/id:%x pid:%x seq:%x pseq:%x/ ", id, previd, seq, prevseq);
break;
} else {
prevseq = seq;
previd = id;
}
}
printf("loop = %d, requested size = %d, ret = %d ", j, size, ret);
j++;
if (fail) {
printf("CRC FAIL\n");
break;
}
else printf("crc ok\n");
}
out_close:
close(fd);
out_close_dir:
closedir(hiddir);
out:
return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment