// autogenerated by syzkaller (https://github.com/google/syzkaller) #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #define MAX_FUNC_NUM 2 #define MAX_DEVICE_NUM 8 union usbg_function_attr { int default_attr; struct usbg_f_midi_attrs midi_attr; struct usbg_f_ms_attrs ms_attr; struct usbg_f_net_attrs net_attr; struct usbg_f_printer_attrs printer_attr; struct usbg_f_loopback_attrs loopback_attr; }; struct usbg_func_config { usbg_function_type f_type; union usbg_function_attr f_attrs; }; struct usb_gadget_device { struct usbg_gadget_attrs* g_attrs; struct usbg_config_attrs* c_attrs; int func_num; struct usbg_func_config func_conf[MAX_FUNC_NUM]; }; struct usb_gadget_device usb_device[MAX_DEVICE_NUM]; struct usbg_gadget_strs g_strs = { .manufacturer = (char*)"Foo Inc.", .product = (char*)"Bar Gadget", .serial = (char*)"12345678"}; struct usbg_config_strs c_strs = { .configuration = (char*)"1xconf"}; static volatile long syz_attach_gadget_impl(struct usb_gadget_device* dev, int uid) { usbg_state* s; usbg_gadget* g; usbg_config* c; usbg_function* f[MAX_FUNC_NUM]; usbg_udc* u; int ret = -1; int usbg_ret; char g_name[10]; sprintf(g_name, "g%d", uid); usbg_ret = usbg_init("/sys/kernel/config", &s); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on usbg init\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out1; } usbg_ret = usbg_create_gadget(s, g_name, dev->g_attrs, &g_strs, &g); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on creating gadget\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out2; } for (int i = 0; i < dev->func_num; i++) { char f_name[10]; sprintf(f_name, "func%d", i); if (dev->func_conf[i].f_attrs.default_attr == 0xffff) usbg_ret = usbg_create_function(g, dev->func_conf[i].f_type, (char*)f_name, NULL, &f[i]); else usbg_ret = usbg_create_function(g, dev->func_conf[i].f_type, (char*)f_name, &(dev->func_conf[i].f_attrs), &f[i]); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on creating gadget func\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out2; } } usbg_ret = usbg_create_config(g, 1, "The only one config", dev->c_attrs, &c_strs, &c); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on creating gadget config\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out2; } for (int i = 0; i < dev->func_num; i++) { char f_name[10]; sprintf(f_name, "f_name.%d", i); usbg_ret = usbg_add_config_function(c, (char*)f_name, f[i]); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on adding func to config\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out2; } } u = usbg_get_first_udc(s); if (uid > 0) { for (int i = 0; i < uid; i++) { u = usbg_get_next_udc(u); } } usbg_ret = usbg_enable_gadget(g, u); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on enabling udc\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out2; } ret = 0; out2: usbg_cleanup(s); out1: return ret; } static int remove_gadget(usbg_gadget* g) { int usbg_ret; usbg_udc* u; u = usbg_get_gadget_udc(g); if (u) { usbg_ret = usbg_disable_gadget(g); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on disable gadget udc\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out; } } usbg_ret = usbg_rm_gadget(g, USBG_RM_RECURSE); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on gadget remove\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); } out: return usbg_ret; } static volatile long syz_detach_gadget_impl(int uid) { int usbg_ret; int ret = -1; usbg_state* s; usbg_gadget* g; const char* g_name; char g_name_target[10]; sprintf(g_name_target, "g%d", uid); usbg_ret = usbg_init("/sys/kernel/config", &s); if (usbg_ret != USBG_SUCCESS) { fprintf(stderr, "Error on USB state init\n"); fprintf(stderr, "Error: %s : %s\n", usbg_error_name((usbg_error)usbg_ret), usbg_strerror((usbg_error)usbg_ret)); goto out1; } g = usbg_get_first_gadget(s); while (g != NULL) { g_name = usbg_get_gadget_name(g); if (strcmp(g_name, g_name_target) == 0) { usbg_gadget* g_next = usbg_get_next_gadget(g); usbg_ret = remove_gadget(g); if (usbg_ret != USBG_SUCCESS) goto out2; g = g_next; } else { g = usbg_get_next_gadget(g); } } usleep(500000); ret = 0; out2: usbg_cleanup(s); out1: return ret; } static void parse_dev_descriptors(const char* buffer, struct usb_gadget_device* dev) { memset(dev, 0, sizeof(*dev)); dev->g_attrs = (struct usbg_gadget_attrs*)buffer; dev->c_attrs = (struct usbg_config_attrs*)(buffer + sizeof(struct usbg_gadget_attrs)); dev->func_num = *(int*)(buffer + sizeof(struct usbg_gadget_attrs) + sizeof(struct usbg_config_attrs) + sizeof(int16_t)); int start_attr = sizeof(struct usbg_gadget_attrs) + sizeof(struct usbg_config_attrs) + sizeof(int16_t) + 2 * sizeof(int32_t); int conf_size = 40; printf("conf_size: %x\n", conf_size); for (int i = 0; i < dev->func_num; i++) { dev->func_conf[i] = *(struct usbg_func_config*)(buffer + start_attr + i * conf_size); } } static volatile long syz_attach_gadget(volatile long a0, volatile long a1) { const char* dev = (const char*)a0; uint64_t uid = a1; parse_dev_descriptors(dev, &usb_device[uid]); return syz_attach_gadget_impl(&usb_device[uid], uid); } static volatile long syz_detach_gadget(volatile long a0) { int uid = a0; return syz_detach_gadget_impl(uid); } #include #include #include #include #include #include #include #include int main(void) { syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul); syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); syz_detach_gadget(5); *(uint16_t*)0x20000000 = 0x320; *(uint8_t*)0x20000002 = 0; *(uint8_t*)0x20000003 = 0; *(uint8_t*)0x20000004 = 0; *(uint8_t*)0x20000005 = 0x50; *(uint16_t*)0x20000006 = 0x45e; *(uint16_t*)0x20000008 = 0x6d; *(uint16_t*)0x2000000a = 0; *(uint8_t*)0x2000000c = 0xc0; *(uint8_t*)0x2000000d = 0xaa; *(uint32_t*)0x20000010 = 1; *(uint8_t*)0x20000018 = 0xc; *(uint32_t*)0x20000020 = 0xffff; syz_attach_gadget(0x20000000, 5); return 0; }