]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 15 Nov 2021 12:28:17 +0000 (13:28 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 15 Nov 2021 12:28:17 +0000 (13:28 +0100)
added patches:
fuse-fix-page-stealing.patch
usb-chipidea-fix-interrupt-deadlock.patch

queue-4.4/fuse-fix-page-stealing.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/usb-chipidea-fix-interrupt-deadlock.patch [new file with mode: 0644]

diff --git a/queue-4.4/fuse-fix-page-stealing.patch b/queue-4.4/fuse-fix-page-stealing.patch
new file mode 100644 (file)
index 0000000..33cd2bb
--- /dev/null
@@ -0,0 +1,61 @@
+From 712a951025c0667ff00b25afc360f74e639dfabe Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Tue, 2 Nov 2021 11:10:37 +0100
+Subject: fuse: fix page stealing
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+commit 712a951025c0667ff00b25afc360f74e639dfabe upstream.
+
+It is possible to trigger a crash by splicing anon pipe bufs to the fuse
+device.
+
+The reason for this is that anon_pipe_buf_release() will reuse buf->page if
+the refcount is 1, but that page might have already been stolen and its
+flags modified (e.g. PG_lru added).
+
+This happens in the unlikely case of fuse_dev_splice_write() getting around
+to calling pipe_buf_release() after a page has been stolen, added to the
+page cache and removed from the page cache.
+
+Fix by calling pipe_buf_release() right after the page was inserted into
+the page cache.  In this case the page has an elevated refcount so any
+release function will know that the page isn't reusable.
+
+Reported-by: Frank Dinoff <fdinoff@google.com>
+Link: https://lore.kernel.org/r/CAAmZXrsGg2xsP1CK+cbuEMumtrqdvD-NKnWzhNcvn71RV3c1yw@mail.gmail.com/
+Fixes: dd3bb14f44a6 ("fuse: support splice() writing to fuse device")
+Cc: <stable@vger.kernel.org> # v2.6.35
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/fuse/dev.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/fs/fuse/dev.c
++++ b/fs/fuse/dev.c
+@@ -922,6 +922,13 @@ static int fuse_try_move_page(struct fus
+               return err;
+       }
++      /*
++       * Release while we have extra ref on stolen page.  Otherwise
++       * anon_pipe_buf_release() might think the page can be reused.
++       */
++      buf->ops->release(cs->pipe, buf);
++      buf->ops = NULL;
++
+       page_cache_get(newpage);
+       if (!(buf->flags & PIPE_BUF_FLAG_LRU))
+@@ -2090,7 +2097,8 @@ static ssize_t fuse_dev_splice_write(str
+ out_free:
+       for (idx = 0; idx < nbuf; idx++) {
+               struct pipe_buffer *buf = &bufs[idx];
+-              buf->ops->release(pipe, buf);
++              if (buf->ops)
++                      buf->ops->release(pipe, buf);
+       }
+       pipe_unlock(pipe);
index 1ba27d67b78f8312fee0aa57ef1012f04a810cb7..81cb972e2bb483df6ba44cacf3ad7f216143b8a1 100644 (file)
@@ -106,3 +106,5 @@ bonding-fix-a-use-after-free-problem-when-bond_sysfs.patch
 llc-fix-out-of-bound-array-index-in-llc_sk_dev_hash.patch
 nfc-pn533-fix-double-free-when-pn533_fill_fragment_s.patch
 vsock-prevent-unnecessary-refcnt-inc-for-nonblocking.patch
+fuse-fix-page-stealing.patch
+usb-chipidea-fix-interrupt-deadlock.patch
diff --git a/queue-4.4/usb-chipidea-fix-interrupt-deadlock.patch b/queue-4.4/usb-chipidea-fix-interrupt-deadlock.patch
new file mode 100644 (file)
index 0000000..4e055d2
--- /dev/null
@@ -0,0 +1,97 @@
+From 9aaa81c3366e8393a62374e3a1c67c69edc07b8a Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Thu, 21 Oct 2021 10:34:47 +0200
+Subject: USB: chipidea: fix interrupt deadlock
+
+From: Johan Hovold <johan@kernel.org>
+
+commit 9aaa81c3366e8393a62374e3a1c67c69edc07b8a upstream.
+
+Chipidea core was calling the interrupt handler from non-IRQ context
+with interrupts enabled, something which can lead to a deadlock if
+there's an actual interrupt trying to take a lock that's already held
+(e.g. the controller lock in udc_irq()).
+
+Add a wrapper that can be used to fake interrupts instead of calling the
+handler directly.
+
+Fixes: 3ecb3e09b042 ("usb: chipidea: Use extcon framework for VBUS and ID detect")
+Fixes: 876d4e1e8298 ("usb: chipidea: core: add wakeup support for extcon")
+Cc: Peter Chen <peter.chen@kernel.org>
+Cc: stable@vger.kernel.org      # 4.4
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://lore.kernel.org/r/20211021083447.20078-1-johan@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/chipidea/core.c |   21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/chipidea/core.c
++++ b/drivers/usb/chipidea/core.c
+@@ -518,7 +518,7 @@ int hw_device_reset(struct ci_hdrc *ci)
+       return 0;
+ }
+-static irqreturn_t ci_irq(int irq, void *data)
++static irqreturn_t ci_irq_handler(int irq, void *data)
+ {
+       struct ci_hdrc *ci = data;
+       irqreturn_t ret = IRQ_NONE;
+@@ -571,6 +571,15 @@ static irqreturn_t ci_irq(int irq, void
+       return ret;
+ }
++static void ci_irq(struct ci_hdrc *ci)
++{
++      unsigned long flags;
++
++      local_irq_save(flags);
++      ci_irq_handler(ci->irq, ci);
++      local_irq_restore(flags);
++}
++
+ static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event,
+                           void *ptr)
+ {
+@@ -584,7 +593,7 @@ static int ci_vbus_notifier(struct notif
+       vbus->changed = true;
+-      ci_irq(ci->irq, ci);
++      ci_irq(ci);
+       return NOTIFY_DONE;
+ }
+@@ -601,7 +610,7 @@ static int ci_id_notifier(struct notifie
+       id->changed = true;
+-      ci_irq(ci->irq, ci);
++      ci_irq(ci);
+       return NOTIFY_DONE;
+ }
+@@ -1023,7 +1032,7 @@ static int ci_hdrc_probe(struct platform
+       }
+       platform_set_drvdata(pdev, ci);
+-      ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
++      ret = devm_request_irq(dev, ci->irq, ci_irq_handler, IRQF_SHARED,
+                       ci->platdata->name, ci);
+       if (ret)
+               goto stop;
+@@ -1138,11 +1147,11 @@ static void ci_extcon_wakeup_int(struct
+       if (!IS_ERR(cable_id->edev) && ci->is_otg &&
+               (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
+-              ci_irq(ci->irq, ci);
++              ci_irq(ci);
+       if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
+               (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
+-              ci_irq(ci->irq, ci);
++              ci_irq(ci);
+ }
+ static int ci_controller_resume(struct device *dev)