ref: a327175a3c01d18e3e4c061ce4579cc420ee3561
parent: 6d199d6a314d268d10b1e4b4c70c26f0b36a6f75
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Sep 30 13:06:58 EDT 2023
nusb/usbd: attach spam protection for reset loops and flanky devices When attach happens on a port within Attachdelay (3 seconds), we count it as a repeated attach and if this happens Attachcount (5) times in a row, we print an error and refuse to attach the device. Ori needs this as he has a usb hid device rgb led controller in his computer that just gives read errors and causes a continuous reset loop on the port, spamming the console.
--- a/sys/src/cmd/nusb/usbd/dat.h
+++ b/sys/src/cmd/nusb/usbd/dat.h
@@ -54,14 +54,14 @@
Pconfiged,
/* Delays, timeouts (ms) */
- Spawndelay = 250, /* how often may we re-spawn a driver */
Resetdelay = 20, /* how much to wait after a reset */
Enabledelay = 20, /* how much to wait after an enable */
Powerdelay = 100, /* after powering up ports */
Pollms = 250, /* port poll interval */
- Chgdelay = 100, /* waiting for port become stable */
- Chgtmout = 1000, /* ...but at most this much */
+ Attachdelay = 3000, /* attach considered repeated if within Attachdelay */
+ Attachcount = 5, /* maximum number of repeated attaches before giving up */
+
/*
* device tab for embedded usb drivers.
*/
@@ -91,6 +91,8 @@
{
int state; /* state of the device */
u32int sts; /* old port status */
+ ulong atime; /* time of last attach in milliseconds */
+ int acount; /* rapid attach counter */
uchar removable;
uchar pwrctl;
Dev *dev; /* attached device (if non-nil) */
--- a/sys/src/cmd/nusb/usbd/hub.c
+++ b/sys/src/cmd/nusb/usbd/hub.c
@@ -10,6 +10,7 @@
static int nhubs;
static int mustdump;
static int pollms = Pollms;
+static ulong nowms;
static char *dsname[] = { "disabled", "attached", "configed" };
@@ -358,6 +359,20 @@
d = h->dev;
pp = &h->port[p];
nd = nil;
+
+ /*
+ * prevent repeated attaches in short succession as it is a indication
+ * for a reset loop or a very flanky device.
+ */
+ if(pp->acount && nowms - pp->atime >= Attachdelay)
+ pp->acount = 0;
+ pp->atime = nowms;
+ if(++pp->acount > Attachcount){
+ fprint(2, "%s: %s: port %d: too many attaches in short succession\n",
+ argv0, d->dir, p);
+ goto Fail;
+ }
+
pp->state = Pattached;
dprint(2, "%s: %s: port %d attach sts %#ux\n", argv0, d->dir, p, sts);
if(h->dev->isusb3){
@@ -558,7 +573,12 @@
dprint(2, "%s: %s: port %d: unsuspend: %r\n", argv0, d->dir, p);
sleep(Enabledelay);
sts = portstatus(h, p);
- fprint(2, "%s: %s: port %d: unsuspended (sts %#ux)\n", argv0, d->dir, p, sts);
+ if(sts == -1){
+ hubfail(h);
+ return -1;
+ }
+ fprint(2, "%s: %s: port %d: unsuspended sts: %s %#ux\n", argv0, d->dir, p,
+ stsstr(sts, h->dev->isusb3), sts);
}
}
if((pp->sts & PSpresent) == 0 && (sts & PSpresent) != 0){
@@ -568,7 +588,7 @@
}else if(portgone(pp, sts)){
portdetach(h, p);
}else if(portresetwanted(h, p)){
- portdetach(h, p);
+ portdetach(h, p);
if(!d->isusb3)
portfeature(h, p, Fportenable, 0);
/* pretend it is gone, causing a re-attach and port reset */
@@ -614,7 +634,7 @@
* Do not use hub interrupt endpoint because we
* have to poll the root hub(s) in any case.
*/
- for(;;){
+ for(;;nowms += pollms){
qlock(&hublock);
Again:
for(h = hubs; h != nil; h = h->next)