Download raw body.
ihidev ibuf malloc sequence fix
kirill@ did discover a sequencing issue in ihidev, where we first
establish the interrupts, which require the sc->sc_ibuf buffer, and
afterwards we only allocate that buffer. In most of the cases this
didn't cause an issue apparently, but if a device shots an interrupt
before we allocate the buffer, the ihidev interrupt handler will try
to write in to an un-allocated pointer.
The NetBSD driver, which initially was an import of our driver, did fix
this sequencing right at the import:
https://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/dev/i2c/ihidev.c?rev=1.1;content-type=text%2Fx-csrc
sc->sc_ibuf = kmem_zalloc(sc->sc_isize, KM_NOSLEEP);
#if NACPICA > 0
{
char buf[100];
sc->sc_ih = acpi_intr_establish(self, sc->sc_phandle, ihidev_intr, sc);
if (sc->sc_ih == NULL)
aprint_error_dev(self, "can't establish interrupt\n");
aprint_normal_dev(self, "interrupting at %s\n",
acpi_intr_string(sc->sc_ih, buf, sizeof(buf)));
}
#endif
The following patch re-shuffles the ordering so that we first allocate
the buffer, and then establish the interrupt handler.
It shouldn't change any functionality, nor the dmesg output.
Some initial testing was going well, but I would like to have a bit a
wider regression testing. If you have an ihidev device, I would be
glad if you can give it a spin and report back.
Feedback, comments, and eventually OKs are welcome!
Index: sys/dev/i2c/ihidev.c
===================================================================
RCS file: /cvs/src/sys/dev/i2c/ihidev.c,v
diff -u -p -u -p -r1.33 ihidev.c
--- sys/dev/i2c/ihidev.c 18 Oct 2024 12:53:49 -0000 1.33
+++ sys/dev/i2c/ihidev.c 2 Jan 2025 13:41:20 -0000
@@ -118,32 +118,10 @@ ihidev_attach(struct device *parent, str
return;
}
- if (ia->ia_intr) {
- printf(" %s", iic_intr_string(sc->sc_tag, ia->ia_intr));
-
- sc->sc_ih = iic_intr_establish(sc->sc_tag, ia->ia_intr,
- IPL_TTY, ihidev_intr, sc, sc->sc_dev.dv_xname);
- if (sc->sc_ih == NULL)
- printf(", can't establish interrupt");
- }
-
- if (ia->ia_poll || !sc->sc_ih) {
- printf(" (polling)");
- sc->sc_poll = 1;
- sc->sc_fastpoll = 1;
- }
-
- printf(", vendor 0x%x product 0x%x, %s\n",
- letoh16(sc->hid_desc.wVendorID), letoh16(sc->hid_desc.wProductID),
- (char *)ia->ia_cookie);
-
sc->sc_nrepid = ihidev_maxrepid(sc->sc_report, sc->sc_reportlen);
if (sc->sc_nrepid < 0)
return;
- printf("%s: %d report id%s\n", sc->sc_dev.dv_xname, sc->sc_nrepid,
- sc->sc_nrepid > 1 ? "s" : "");
-
sc->sc_nrepid++;
sc->sc_subdevs = mallocarray(sc->sc_nrepid, sizeof(struct ihidev *),
M_DEVBUF, M_WAITOK | M_ZERO);
@@ -161,6 +139,29 @@ ihidev_attach(struct device *parent, str
repid, repsz));
}
sc->sc_ibuf = malloc(sc->sc_isize, M_DEVBUF, M_WAITOK | M_ZERO);
+
+ if (ia->ia_intr) {
+ printf(" %s", iic_intr_string(sc->sc_tag, ia->ia_intr));
+
+ sc->sc_ih = iic_intr_establish(sc->sc_tag, ia->ia_intr,
+ IPL_TTY, ihidev_intr, sc, sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL)
+ printf("%s: can't establish interrupt\n",
+ sc->sc_dev.dv_xname);
+ }
+
+ if (ia->ia_poll || !sc->sc_ih) {
+ printf(" (polling)");
+ sc->sc_poll = 1;
+ sc->sc_fastpoll = 1;
+ }
+
+ printf(", vendor 0x%x product 0x%x, %s\n",
+ letoh16(sc->hid_desc.wVendorID), letoh16(sc->hid_desc.wProductID),
+ (char *)ia->ia_cookie);
+
+ printf("%s: %d report id%s\n", sc->sc_dev.dv_xname, (sc->sc_nrepid - 1),
+ (sc->sc_nrepid - 1) > 1 ? "s" : "");
iha.iaa = ia;
iha.parent = sc;
ihidev ibuf malloc sequence fix