From: Greg Kroah-Hartman Date: Thu, 13 Jan 2022 10:52:30 +0000 (+0100) Subject: 4.19-stable patches X-Git-Tag: v5.16.1~39 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=949b53a1172007afcd452d3f2a4003db92965b2f;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-stable patches added patches: bluetooth-bfusb-fix-division-by-zero-in-send-path.patch can-bcm-switch-timer-to-hrtimer_mode_soft-and-remove-hrtimer_tasklet.patch usb-core-fix-bug-in-resuming-hub-s-handling-of-wakeup-requests.patch usb-fix-slab-out-of-bounds-write-bug-in-usb_hcd_poll_rh_status.patch --- diff --git a/queue-4.19/bluetooth-bfusb-fix-division-by-zero-in-send-path.patch b/queue-4.19/bluetooth-bfusb-fix-division-by-zero-in-send-path.patch new file mode 100644 index 00000000000..201f71e765c --- /dev/null +++ b/queue-4.19/bluetooth-bfusb-fix-division-by-zero-in-send-path.patch @@ -0,0 +1,38 @@ +From b5e6fa7a12572c82f1e7f2f51fbb02a322291291 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 25 Oct 2021 13:39:44 +0200 +Subject: Bluetooth: bfusb: fix division by zero in send path + +From: Johan Hovold + +commit b5e6fa7a12572c82f1e7f2f51fbb02a322291291 upstream. + +Add the missing bulk-out endpoint sanity check to probe() to avoid +division by zero in bfusb_send_frame() in case a malicious device has +broken descriptors (or when doing descriptor fuzz testing). + +Note that USB core will reject URBs submitted for endpoints with zero +wMaxPacketSize but that drivers doing packet-size calculations still +need to handle this (cf. commit 2548288b4fb0 ("USB: Fix: Don't skip +endpoint descriptors with maxpacket=0")). + +Cc: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Marcel Holtmann +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bluetooth/bfusb.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bluetooth/bfusb.c ++++ b/drivers/bluetooth/bfusb.c +@@ -644,6 +644,9 @@ static int bfusb_probe(struct usb_interf + data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress; + data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize); + ++ if (!data->bulk_pkt_size) ++ goto done; ++ + rwlock_init(&data->lock); + + data->reassembly = NULL; diff --git a/queue-4.19/can-bcm-switch-timer-to-hrtimer_mode_soft-and-remove-hrtimer_tasklet.patch b/queue-4.19/can-bcm-switch-timer-to-hrtimer_mode_soft-and-remove-hrtimer_tasklet.patch new file mode 100644 index 00000000000..7462846f37b --- /dev/null +++ b/queue-4.19/can-bcm-switch-timer-to-hrtimer_mode_soft-and-remove-hrtimer_tasklet.patch @@ -0,0 +1,318 @@ +From bf74aa86e111aa3b2fbb25db37e3a3fab71b5b68 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 12 Aug 2019 14:57:14 +0200 +Subject: can: bcm: switch timer to HRTIMER_MODE_SOFT and remove hrtimer_tasklet + +From: Thomas Gleixner + +commit bf74aa86e111aa3b2fbb25db37e3a3fab71b5b68 upstream. + +This patch switches the timer to HRTIMER_MODE_SOFT, which executed the +timer callback in softirq context and removes the hrtimer_tasklet. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Gleixner +Acked-by: Oliver Hartkopp +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Ziyang Xuan +Signed-off-by: Greg Kroah-Hartman +--- + net/can/bcm.c | 156 +++++++++++++++++++--------------------------------------- + 1 file changed, 52 insertions(+), 104 deletions(-) + +--- a/net/can/bcm.c ++++ b/net/can/bcm.c +@@ -105,7 +105,6 @@ struct bcm_op { + unsigned long frames_abs, frames_filtered; + struct bcm_timeval ival1, ival2; + struct hrtimer timer, thrtimer; +- struct tasklet_struct tsklet, thrtsklet; + ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg; + int rx_ifindex; + int cfsiz; +@@ -374,25 +373,34 @@ static void bcm_send_to_user(struct bcm_ + } + } + +-static void bcm_tx_start_timer(struct bcm_op *op) ++static bool bcm_tx_set_expiry(struct bcm_op *op, struct hrtimer *hrt) + { ++ ktime_t ival; ++ + if (op->kt_ival1 && op->count) +- hrtimer_start(&op->timer, +- ktime_add(ktime_get(), op->kt_ival1), +- HRTIMER_MODE_ABS); ++ ival = op->kt_ival1; + else if (op->kt_ival2) +- hrtimer_start(&op->timer, +- ktime_add(ktime_get(), op->kt_ival2), +- HRTIMER_MODE_ABS); ++ ival = op->kt_ival2; ++ else ++ return false; ++ ++ hrtimer_set_expires(hrt, ktime_add(ktime_get(), ival)); ++ return true; + } + +-static void bcm_tx_timeout_tsklet(unsigned long data) ++static void bcm_tx_start_timer(struct bcm_op *op) + { +- struct bcm_op *op = (struct bcm_op *)data; ++ if (bcm_tx_set_expiry(op, &op->timer)) ++ hrtimer_start_expires(&op->timer, HRTIMER_MODE_ABS_SOFT); ++} ++ ++/* bcm_tx_timeout_handler - performs cyclic CAN frame transmissions */ ++static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) ++{ ++ struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); + struct bcm_msg_head msg_head; + + if (op->kt_ival1 && (op->count > 0)) { +- + op->count--; + if (!op->count && (op->flags & TX_COUNTEVT)) { + +@@ -410,22 +418,12 @@ static void bcm_tx_timeout_tsklet(unsign + } + bcm_can_tx(op); + +- } else if (op->kt_ival2) ++ } else if (op->kt_ival2) { + bcm_can_tx(op); ++ } + +- bcm_tx_start_timer(op); +-} +- +-/* +- * bcm_tx_timeout_handler - performs cyclic CAN frame transmissions +- */ +-static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) +-{ +- struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); +- +- tasklet_schedule(&op->tsklet); +- +- return HRTIMER_NORESTART; ++ return bcm_tx_set_expiry(op, &op->timer) ? ++ HRTIMER_RESTART : HRTIMER_NORESTART; + } + + /* +@@ -492,7 +490,7 @@ static void bcm_rx_update_and_send(struc + /* do not send the saved data - only start throttle timer */ + hrtimer_start(&op->thrtimer, + ktime_add(op->kt_lastmsg, op->kt_ival2), +- HRTIMER_MODE_ABS); ++ HRTIMER_MODE_ABS_SOFT); + return; + } + +@@ -551,14 +549,21 @@ static void bcm_rx_starttimer(struct bcm + return; + + if (op->kt_ival1) +- hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL); ++ hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL_SOFT); + } + +-static void bcm_rx_timeout_tsklet(unsigned long data) ++/* bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out */ ++static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer) + { +- struct bcm_op *op = (struct bcm_op *)data; ++ struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); + struct bcm_msg_head msg_head; + ++ /* if user wants to be informed, when cyclic CAN-Messages come back */ ++ if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) { ++ /* clear received CAN frames to indicate 'nothing received' */ ++ memset(op->last_frames, 0, op->nframes * op->cfsiz); ++ } ++ + /* create notification to user */ + memset(&msg_head, 0, sizeof(msg_head)); + msg_head.opcode = RX_TIMEOUT; +@@ -570,25 +575,6 @@ static void bcm_rx_timeout_tsklet(unsign + msg_head.nframes = 0; + + bcm_send_to_user(op, &msg_head, NULL, 0); +-} +- +-/* +- * bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out +- */ +-static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer) +-{ +- struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); +- +- /* schedule before NET_RX_SOFTIRQ */ +- tasklet_hi_schedule(&op->tsklet); +- +- /* no restart of the timer is done here! */ +- +- /* if user wants to be informed, when cyclic CAN-Messages come back */ +- if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) { +- /* clear received CAN frames to indicate 'nothing received' */ +- memset(op->last_frames, 0, op->nframes * op->cfsiz); +- } + + return HRTIMER_NORESTART; + } +@@ -596,14 +582,12 @@ static enum hrtimer_restart bcm_rx_timeo + /* + * bcm_rx_do_flush - helper for bcm_rx_thr_flush + */ +-static inline int bcm_rx_do_flush(struct bcm_op *op, int update, +- unsigned int index) ++static inline int bcm_rx_do_flush(struct bcm_op *op, unsigned int index) + { + struct canfd_frame *lcf = op->last_frames + op->cfsiz * index; + + if ((op->last_frames) && (lcf->flags & RX_THR)) { +- if (update) +- bcm_rx_changed(op, lcf); ++ bcm_rx_changed(op, lcf); + return 1; + } + return 0; +@@ -611,11 +595,8 @@ static inline int bcm_rx_do_flush(struct + + /* + * bcm_rx_thr_flush - Check for throttled data and send it to the userspace +- * +- * update == 0 : just check if throttled data is available (any irq context) +- * update == 1 : check and send throttled data to userspace (soft_irq context) + */ +-static int bcm_rx_thr_flush(struct bcm_op *op, int update) ++static int bcm_rx_thr_flush(struct bcm_op *op) + { + int updated = 0; + +@@ -624,24 +605,16 @@ static int bcm_rx_thr_flush(struct bcm_o + + /* for MUX filter we start at index 1 */ + for (i = 1; i < op->nframes; i++) +- updated += bcm_rx_do_flush(op, update, i); ++ updated += bcm_rx_do_flush(op, i); + + } else { + /* for RX_FILTER_ID and simple filter */ +- updated += bcm_rx_do_flush(op, update, 0); ++ updated += bcm_rx_do_flush(op, 0); + } + + return updated; + } + +-static void bcm_rx_thr_tsklet(unsigned long data) +-{ +- struct bcm_op *op = (struct bcm_op *)data; +- +- /* push the changed data to the userspace */ +- bcm_rx_thr_flush(op, 1); +-} +- + /* + * bcm_rx_thr_handler - the time for blocked content updates is over now: + * Check for throttled data and send it to the userspace +@@ -650,9 +623,7 @@ static enum hrtimer_restart bcm_rx_thr_h + { + struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer); + +- tasklet_schedule(&op->thrtsklet); +- +- if (bcm_rx_thr_flush(op, 0)) { ++ if (bcm_rx_thr_flush(op)) { + hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); + return HRTIMER_RESTART; + } else { +@@ -748,23 +719,8 @@ static struct bcm_op *bcm_find_op(struct + + static void bcm_remove_op(struct bcm_op *op) + { +- if (op->tsklet.func) { +- while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) || +- test_bit(TASKLET_STATE_RUN, &op->tsklet.state) || +- hrtimer_active(&op->timer)) { +- hrtimer_cancel(&op->timer); +- tasklet_kill(&op->tsklet); +- } +- } +- +- if (op->thrtsklet.func) { +- while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) || +- test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) || +- hrtimer_active(&op->thrtimer)) { +- hrtimer_cancel(&op->thrtimer); +- tasklet_kill(&op->thrtsklet); +- } +- } ++ hrtimer_cancel(&op->timer); ++ hrtimer_cancel(&op->thrtimer); + + if ((op->frames) && (op->frames != &op->sframe)) + kfree(op->frames); +@@ -998,15 +954,13 @@ static int bcm_tx_setup(struct bcm_msg_h + op->ifindex = ifindex; + + /* initialize uninitialized (kzalloc) structure */ +- hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ hrtimer_init(&op->timer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL_SOFT); + op->timer.function = bcm_tx_timeout_handler; + +- /* initialize tasklet for tx countevent notification */ +- tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet, +- (unsigned long) op); +- + /* currently unused in tx_ops */ +- hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL_SOFT); + + /* add this bcm_op to the list of the tx_ops */ + list_add(&op->list, &bo->tx_ops); +@@ -1175,20 +1129,14 @@ static int bcm_rx_setup(struct bcm_msg_h + op->rx_ifindex = ifindex; + + /* initialize uninitialized (kzalloc) structure */ +- hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ hrtimer_init(&op->timer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL_SOFT); + op->timer.function = bcm_rx_timeout_handler; + +- /* initialize tasklet for rx timeout notification */ +- tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet, +- (unsigned long) op); +- +- hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL_SOFT); + op->thrtimer.function = bcm_rx_thr_handler; + +- /* initialize tasklet for rx throttle handling */ +- tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet, +- (unsigned long) op); +- + /* add this bcm_op to the list of the rx_ops */ + list_add(&op->list, &bo->rx_ops); + +@@ -1234,12 +1182,12 @@ static int bcm_rx_setup(struct bcm_msg_h + */ + op->kt_lastmsg = 0; + hrtimer_cancel(&op->thrtimer); +- bcm_rx_thr_flush(op, 1); ++ bcm_rx_thr_flush(op); + } + + if ((op->flags & STARTTIMER) && op->kt_ival1) + hrtimer_start(&op->timer, op->kt_ival1, +- HRTIMER_MODE_REL); ++ HRTIMER_MODE_REL_SOFT); + } + + /* now we can register for can_ids, if we added a new bcm_op */ diff --git a/queue-4.19/series b/queue-4.19/series index e69de29bb2d..71e683acc0e 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -0,0 +1,4 @@ +bluetooth-bfusb-fix-division-by-zero-in-send-path.patch +usb-core-fix-bug-in-resuming-hub-s-handling-of-wakeup-requests.patch +usb-fix-slab-out-of-bounds-write-bug-in-usb_hcd_poll_rh_status.patch +can-bcm-switch-timer-to-hrtimer_mode_soft-and-remove-hrtimer_tasklet.patch diff --git a/queue-4.19/usb-core-fix-bug-in-resuming-hub-s-handling-of-wakeup-requests.patch b/queue-4.19/usb-core-fix-bug-in-resuming-hub-s-handling-of-wakeup-requests.patch new file mode 100644 index 00000000000..bb90805b015 --- /dev/null +++ b/queue-4.19/usb-core-fix-bug-in-resuming-hub-s-handling-of-wakeup-requests.patch @@ -0,0 +1,69 @@ +From 0f663729bb4afc92a9986b66131ebd5b8a9254d1 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Sat, 1 Jan 2022 14:52:14 -0500 +Subject: USB: core: Fix bug in resuming hub's handling of wakeup requests + +From: Alan Stern + +commit 0f663729bb4afc92a9986b66131ebd5b8a9254d1 upstream. + +Bugzilla #213839 reports a 7-port hub that doesn't work properly when +devices are plugged into some of the ports; the kernel goes into an +unending disconnect/reinitialize loop as shown in the bug report. + +This "7-port hub" comprises two four-port hubs with one plugged into +the other; the failures occur when a device is plugged into one of the +downstream hub's ports. (These hubs have other problems too. For +example, they bill themselves as USB-2.0 compliant but they only run +at full speed.) + +It turns out that the failures are caused by bugs in both the kernel +and the hub. The hub's bug is that it reports a different +bmAttributes value in its configuration descriptor following a remote +wakeup (0xe0 before, 0xc0 after -- the wakeup-support bit has +changed). + +The kernel's bug is inside the hub driver's resume handler. When +hub_activate() sees that one of the hub's downstream ports got a +wakeup request from a child device, it notes this fact by setting the +corresponding bit in the hub->change_bits variable. But this variable +is meant for connection changes, not wakeup events; setting it causes +the driver to believe the downstream port has been disconnected and +then connected again (in addition to having received a wakeup +request). + +Because of this, the hub driver then tries to check whether the device +currently plugged into the downstream port is the same as the device +that had been attached there before. Normally this check succeeds and +wakeup handling continues with no harm done (which is why the bug +remained undetected until now). But with these dodgy hubs, the check +fails because the config descriptor has changed. This causes the hub +driver to reinitialize the child device, leading to the +disconnect/reinitialize loop described in the bug report. + +The proper way to note reception of a downstream wakeup request is +to set a bit in the hub->event_bits variable instead of +hub->change_bits. That way the hub driver will realize that something +has happened to the port but will not think the port and child device +have been disconnected. This patch makes that change. + +Cc: +Tested-by: Jonathan McDowell +Signed-off-by: Alan Stern +Link: https://lore.kernel.org/r/YdCw7nSfWYPKWQoD@rowland.harvard.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/hub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -1197,7 +1197,7 @@ static void hub_activate(struct usb_hub + */ + if (portchange || (hub_is_superspeed(hub->hdev) && + port_resumed)) +- set_bit(port1, hub->change_bits); ++ set_bit(port1, hub->event_bits); + + } else if (udev->persist_enabled) { + #ifdef CONFIG_PM diff --git a/queue-4.19/usb-fix-slab-out-of-bounds-write-bug-in-usb_hcd_poll_rh_status.patch b/queue-4.19/usb-fix-slab-out-of-bounds-write-bug-in-usb_hcd_poll_rh_status.patch new file mode 100644 index 00000000000..68a42e706f0 --- /dev/null +++ b/queue-4.19/usb-fix-slab-out-of-bounds-write-bug-in-usb_hcd_poll_rh_status.patch @@ -0,0 +1,65 @@ +From 1d7d4c07932e04355d6e6528d44a2f2c9e354346 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 31 Dec 2021 21:07:12 -0500 +Subject: USB: Fix "slab-out-of-bounds Write" bug in usb_hcd_poll_rh_status + +From: Alan Stern + +commit 1d7d4c07932e04355d6e6528d44a2f2c9e354346 upstream. + +When the USB core code for getting root-hub status reports was +originally written, it was assumed that the hub driver would be its +only caller. But this isn't true now; user programs can use usbfs to +communicate with root hubs and get status reports. When they do this, +they may use a transfer_buffer that is smaller than the data returned +by the HCD, which will lead to a buffer overflow error when +usb_hcd_poll_rh_status() tries to store the status data. This was +discovered by syzbot: + +BUG: KASAN: slab-out-of-bounds in memcpy include/linux/fortify-string.h:225 [inline] +BUG: KASAN: slab-out-of-bounds in usb_hcd_poll_rh_status+0x5f4/0x780 drivers/usb/core/hcd.c:776 +Write of size 2 at addr ffff88801da403c0 by task syz-executor133/4062 + +This patch fixes the bug by reducing the amount of status data if it +won't fit in the transfer_buffer. If some data gets discarded then +the URB's completion status is set to -EOVERFLOW rather than 0, to let +the user know what happened. + +Reported-and-tested-by: syzbot+3ae6a2b06f131ab9849f@syzkaller.appspotmail.com +Signed-off-by: Alan Stern +Cc: +Link: https://lore.kernel.org/r/Yc+3UIQJ2STbxNua@rowland.harvard.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/hcd.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -750,6 +750,7 @@ void usb_hcd_poll_rh_status(struct usb_h + { + struct urb *urb; + int length; ++ int status; + unsigned long flags; + char buffer[6]; /* Any root hubs with > 31 ports? */ + +@@ -767,11 +768,17 @@ void usb_hcd_poll_rh_status(struct usb_h + if (urb) { + clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags); + hcd->status_urb = NULL; ++ if (urb->transfer_buffer_length >= length) { ++ status = 0; ++ } else { ++ status = -EOVERFLOW; ++ length = urb->transfer_buffer_length; ++ } + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); + + usb_hcd_unlink_urb_from_ep(hcd, urb); +- usb_hcd_giveback_urb(hcd, urb, 0); ++ usb_hcd_giveback_urb(hcd, urb, status); + } else { + length = 0; + set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);