]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Apr 2017 12:39:54 +0000 (14:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Apr 2017 12:39:54 +0000 (14:39 +0200)
added patches:
ath9k-fix-null-pointer-dereference.patch
catc-combine-failure-cleanup-code-in-catc_probe.patch
catc-use-heap-buffer-for-memory-size-test.patch
crypto-ahash-fix-einprogress-notification-callback.patch
dvb-usb-don-t-use-stack-for-firmware-load.patch
dvb-usb-firmware-don-t-do-dma-on-stack.patch
dvb-usb-v2-avoid-use-after-free.patch
ext4-fix-inode-checksum-calculation-problem-if-i_extra_size-is-small.patch
mm-tighten-x86-dev-mem-with-zeroing-reads.patch
pegasus-use-heap-buffers-for-all-register-access.patch
platform-x86-acer-wmi-setup-accelerometer-when-machine-has-appropriate-notify-event.patch
powerpc-disable-hfscr-if-tm-is-not-supported.patch
rtc-tegra-implement-clock-handling.patch
rtl8150-use-heap-buffers-for-all-register-access.patch
virtio-console-avoid-dma-from-stack.patch

16 files changed:
queue-4.4/ath9k-fix-null-pointer-dereference.patch [new file with mode: 0644]
queue-4.4/catc-combine-failure-cleanup-code-in-catc_probe.patch [new file with mode: 0644]
queue-4.4/catc-use-heap-buffer-for-memory-size-test.patch [new file with mode: 0644]
queue-4.4/crypto-ahash-fix-einprogress-notification-callback.patch [new file with mode: 0644]
queue-4.4/dvb-usb-don-t-use-stack-for-firmware-load.patch [new file with mode: 0644]
queue-4.4/dvb-usb-firmware-don-t-do-dma-on-stack.patch [new file with mode: 0644]
queue-4.4/dvb-usb-v2-avoid-use-after-free.patch [new file with mode: 0644]
queue-4.4/ext4-fix-inode-checksum-calculation-problem-if-i_extra_size-is-small.patch [new file with mode: 0644]
queue-4.4/mm-tighten-x86-dev-mem-with-zeroing-reads.patch [new file with mode: 0644]
queue-4.4/pegasus-use-heap-buffers-for-all-register-access.patch [new file with mode: 0644]
queue-4.4/platform-x86-acer-wmi-setup-accelerometer-when-machine-has-appropriate-notify-event.patch [new file with mode: 0644]
queue-4.4/powerpc-disable-hfscr-if-tm-is-not-supported.patch [new file with mode: 0644]
queue-4.4/rtc-tegra-implement-clock-handling.patch [new file with mode: 0644]
queue-4.4/rtl8150-use-heap-buffers-for-all-register-access.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/virtio-console-avoid-dma-from-stack.patch [new file with mode: 0644]

diff --git a/queue-4.4/ath9k-fix-null-pointer-dereference.patch b/queue-4.4/ath9k-fix-null-pointer-dereference.patch
new file mode 100644 (file)
index 0000000..3753cd7
--- /dev/null
@@ -0,0 +1,80 @@
+From 40bea976c72b9ee60f8d097852deb53ccbeaffbe Mon Sep 17 00:00:00 2001
+From: Miaoqing Pan <miaoqing@codeaurora.org>
+Date: Wed, 16 Nov 2016 17:23:08 +0800
+Subject: ath9k: fix NULL pointer dereference
+
+From: Miaoqing Pan <miaoqing@codeaurora.org>
+
+commit 40bea976c72b9ee60f8d097852deb53ccbeaffbe upstream.
+
+relay_open() may return NULL, check the return value to avoid the crash.
+
+BUG: unable to handle kernel NULL pointer dereference at 0000000000000040
+IP: [<ffffffffa01a95c5>] ath_cmn_process_fft+0xd5/0x700 [ath9k_common]
+PGD 41cf28067 PUD 41be92067 PMD 0
+Oops: 0000 [#1] SMP
+CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.8.6+ #35
+Hardware name: Hewlett-Packard h8-1080t/2A86, BIOS 6.15    07/04/2011
+task: ffffffff81e0c4c0 task.stack: ffffffff81e00000
+RIP: 0010:[<ffffffffa01a95c5>] [<ffffffffa01a95c5>] ath_cmn_process_fft+0xd5/0x700 [ath9k_common]
+RSP: 0018:ffff88041f203ca0 EFLAGS: 00010293
+RAX: 0000000000000000 RBX: 000000000000059f RCX: 0000000000000000
+RDX: 0000000000000000 RSI: 0000000000000040 RDI: ffffffff81f0ca98
+RBP: ffff88041f203dc8 R08: ffffffffffffffff R09: 00000000000000ff
+R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
+R13: ffffffff81f0ca98 R14: 0000000000000000 R15: 0000000000000000
+FS:  0000000000000000(0000) GS:ffff88041f200000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 0000000000000040 CR3: 000000041b6ec000 CR4: 00000000000006f0
+Stack:
+0000000000000363 00000000000003f3 00000000000003f3 00000000000001f9
+000000000000049a 0000000001252c04 ffff88041f203e44 ffff880417b4bfd0
+0000000000000008 ffff88041785b9c0 0000000000000002 ffff88041613dc60
+
+Call Trace:
+<IRQ>
+[<ffffffffa01b6441>] ath9k_tasklet+0x1b1/0x220 [ath9k]
+[<ffffffff8105d8dd>] tasklet_action+0x4d/0xf0
+[<ffffffff8105dde2>] __do_softirq+0x92/0x2a0
+
+Reported-by: Devin Tuchsen <devin.tuchsen@gmail.com>
+Tested-by: Devin Tuchsen <devin.tuchsen@gmail.com>
+Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/ath/ath9k/common-spectral.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
++++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
+@@ -528,6 +528,9 @@ int ath_cmn_process_fft(struct ath_spec_
+       if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
+               return 0;
++      if (!spec_priv->rfs_chan_spec_scan)
++              return 1;
++
+       /* Output buffers are full, no need to process anything
+        * since there is no space to put the result anyway
+        */
+@@ -1072,7 +1075,7 @@ static struct rchan_callbacks rfs_spec_s
+ void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
+ {
+-      if (config_enabled(CONFIG_ATH9K_DEBUGFS)) {
++      if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) {
+               relay_close(spec_priv->rfs_chan_spec_scan);
+               spec_priv->rfs_chan_spec_scan = NULL;
+       }
+@@ -1086,6 +1089,9 @@ void ath9k_cmn_spectral_init_debug(struc
+                                           debugfs_phy,
+                                           1024, 256, &rfs_spec_scan_cb,
+                                           NULL);
++      if (!spec_priv->rfs_chan_spec_scan)
++              return;
++
+       debugfs_create_file("spectral_scan_ctl",
+                           S_IRUSR | S_IWUSR,
+                           debugfs_phy, spec_priv,
diff --git a/queue-4.4/catc-combine-failure-cleanup-code-in-catc_probe.patch b/queue-4.4/catc-combine-failure-cleanup-code-in-catc_probe.patch
new file mode 100644 (file)
index 0000000..3521802
--- /dev/null
@@ -0,0 +1,74 @@
+From d41149145f98fe26dcd0bfd1d6cc095e6e041418 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sat, 4 Feb 2017 16:56:56 +0000
+Subject: catc: Combine failure cleanup code in catc_probe()
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit d41149145f98fe26dcd0bfd1d6cc095e6e041418 upstream.
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/usb/catc.c |   33 +++++++++++++++++----------------
+ 1 file changed, 17 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/usb/catc.c
++++ b/drivers/net/usb/catc.c
+@@ -777,7 +777,7 @@ static int catc_probe(struct usb_interfa
+       struct net_device *netdev;
+       struct catc *catc;
+       u8 broadcast[ETH_ALEN];
+-      int i, pktsz;
++      int i, pktsz, ret;
+       if (usb_set_interface(usbdev,
+                       intf->altsetting->desc.bInterfaceNumber, 1)) {
+@@ -812,12 +812,8 @@ static int catc_probe(struct usb_interfa
+       if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
+           (!catc->rx_urb) || (!catc->irq_urb)) {
+               dev_err(&intf->dev, "No free urbs available.\n");
+-              usb_free_urb(catc->ctrl_urb);
+-              usb_free_urb(catc->tx_urb);
+-              usb_free_urb(catc->rx_urb);
+-              usb_free_urb(catc->irq_urb);
+-              free_netdev(netdev);
+-              return -ENOMEM;
++              ret = -ENOMEM;
++              goto fail_free;
+       }
+       /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */
+@@ -914,16 +910,21 @@ static int catc_probe(struct usb_interfa
+       usb_set_intfdata(intf, catc);
+       SET_NETDEV_DEV(netdev, &intf->dev);
+-      if (register_netdev(netdev) != 0) {
+-              usb_set_intfdata(intf, NULL);
+-              usb_free_urb(catc->ctrl_urb);
+-              usb_free_urb(catc->tx_urb);
+-              usb_free_urb(catc->rx_urb);
+-              usb_free_urb(catc->irq_urb);
+-              free_netdev(netdev);
+-              return -EIO;
+-      }
++      ret = register_netdev(netdev);
++      if (ret)
++              goto fail_clear_intfdata;
++
+       return 0;
++
++fail_clear_intfdata:
++      usb_set_intfdata(intf, NULL);
++fail_free:
++      usb_free_urb(catc->ctrl_urb);
++      usb_free_urb(catc->tx_urb);
++      usb_free_urb(catc->rx_urb);
++      usb_free_urb(catc->irq_urb);
++      free_netdev(netdev);
++      return ret;
+ }
+ static void catc_disconnect(struct usb_interface *intf)
diff --git a/queue-4.4/catc-use-heap-buffer-for-memory-size-test.patch b/queue-4.4/catc-use-heap-buffer-for-memory-size-test.patch
new file mode 100644 (file)
index 0000000..2f914e8
--- /dev/null
@@ -0,0 +1,73 @@
+From 2d6a0e9de03ee658a9adc3bfb2f0ca55dff1e478 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sat, 4 Feb 2017 16:57:04 +0000
+Subject: catc: Use heap buffer for memory size test
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit 2d6a0e9de03ee658a9adc3bfb2f0ca55dff1e478 upstream.
+
+Allocating USB buffers on the stack is not portable, and no longer
+works on x86_64 (with VMAP_STACK enabled as per default).
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Cc: Brad Spengler <spender@grsecurity.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/usb/catc.c |   25 ++++++++++++++++++-------
+ 1 file changed, 18 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/usb/catc.c
++++ b/drivers/net/usb/catc.c
+@@ -777,7 +777,7 @@ static int catc_probe(struct usb_interfa
+       struct net_device *netdev;
+       struct catc *catc;
+       u8 broadcast[ETH_ALEN];
+-      int i, pktsz, ret;
++      int pktsz, ret;
+       if (usb_set_interface(usbdev,
+                       intf->altsetting->desc.bInterfaceNumber, 1)) {
+@@ -841,15 +841,24 @@ static int catc_probe(struct usb_interfa
+                 catc->irq_buf, 2, catc_irq_done, catc, 1);
+       if (!catc->is_f5u011) {
++              u32 *buf;
++              int i;
++
+               dev_dbg(dev, "Checking memory size\n");
+-              i = 0x12345678;
+-              catc_write_mem(catc, 0x7a80, &i, 4);
+-              i = 0x87654321; 
+-              catc_write_mem(catc, 0xfa80, &i, 4);
+-              catc_read_mem(catc, 0x7a80, &i, 4);
++              buf = kmalloc(4, GFP_KERNEL);
++              if (!buf) {
++                      ret = -ENOMEM;
++                      goto fail_free;
++              }
++
++              *buf = 0x12345678;
++              catc_write_mem(catc, 0x7a80, buf, 4);
++              *buf = 0x87654321;
++              catc_write_mem(catc, 0xfa80, buf, 4);
++              catc_read_mem(catc, 0x7a80, buf, 4);
+         
+-              switch (i) {
++              switch (*buf) {
+               case 0x12345678:
+                       catc_set_reg(catc, TxBufCount, 8);
+                       catc_set_reg(catc, RxBufCount, 32);
+@@ -864,6 +873,8 @@ static int catc_probe(struct usb_interfa
+                       dev_dbg(dev, "32k Memory\n");
+                       break;
+               }
++
++              kfree(buf);
+         
+               dev_dbg(dev, "Getting MAC from SEEROM.\n");
+         
diff --git a/queue-4.4/crypto-ahash-fix-einprogress-notification-callback.patch b/queue-4.4/crypto-ahash-fix-einprogress-notification-callback.patch
new file mode 100644 (file)
index 0000000..5c7e619
--- /dev/null
@@ -0,0 +1,230 @@
+From ef0579b64e93188710d48667cb5e014926af9f1b Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Mon, 10 Apr 2017 17:27:57 +0800
+Subject: crypto: ahash - Fix EINPROGRESS notification callback
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit ef0579b64e93188710d48667cb5e014926af9f1b upstream.
+
+The ahash API modifies the request's callback function in order
+to clean up after itself in some corner cases (unaligned final
+and missing finup).
+
+When the request is complete ahash will restore the original
+callback and everything is fine.  However, when the request gets
+an EBUSY on a full queue, an EINPROGRESS callback is made while
+the request is still ongoing.
+
+In this case the ahash API will incorrectly call its own callback.
+
+This patch fixes the problem by creating a temporary request
+object on the stack which is used to relay EINPROGRESS back to
+the original completion function.
+
+This patch also adds code to preserve the original flags value.
+
+Fixes: ab6bf4e5e5e4 ("crypto: hash - Fix the pointer voodoo in...")
+Reported-by: Sabrina Dubroca <sd@queasysnail.net>
+Tested-by: Sabrina Dubroca <sd@queasysnail.net>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ crypto/ahash.c                 |   79 +++++++++++++++++++++++++----------------
+ include/crypto/internal/hash.h |   10 +++++
+ 2 files changed, 60 insertions(+), 29 deletions(-)
+
+--- a/crypto/ahash.c
++++ b/crypto/ahash.c
+@@ -31,6 +31,7 @@ struct ahash_request_priv {
+       crypto_completion_t complete;
+       void *data;
+       u8 *result;
++      u32 flags;
+       void *ubuf[] CRYPTO_MINALIGN_ATTR;
+ };
+@@ -270,6 +271,8 @@ static int ahash_save_req(struct ahash_r
+       priv->result = req->result;
+       priv->complete = req->base.complete;
+       priv->data = req->base.data;
++      priv->flags = req->base.flags;
++
+       /*
+        * WARNING: We do not backup req->priv here! The req->priv
+        *          is for internal use of the Crypto API and the
+@@ -284,38 +287,44 @@ static int ahash_save_req(struct ahash_r
+       return 0;
+ }
+-static void ahash_restore_req(struct ahash_request *req)
++static void ahash_restore_req(struct ahash_request *req, int err)
+ {
+       struct ahash_request_priv *priv = req->priv;
++      if (!err)
++              memcpy(priv->result, req->result,
++                     crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
++
+       /* Restore the original crypto request. */
+       req->result = priv->result;
+-      req->base.complete = priv->complete;
+-      req->base.data = priv->data;
++
++      ahash_request_set_callback(req, priv->flags,
++                                 priv->complete, priv->data);
+       req->priv = NULL;
+       /* Free the req->priv.priv from the ADJUSTED request. */
+       kzfree(priv);
+ }
+-static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
++static void ahash_notify_einprogress(struct ahash_request *req)
+ {
+       struct ahash_request_priv *priv = req->priv;
++      struct crypto_async_request oreq;
+-      if (err == -EINPROGRESS)
+-              return;
+-
+-      if (!err)
+-              memcpy(priv->result, req->result,
+-                     crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
++      oreq.data = priv->data;
+-      ahash_restore_req(req);
++      priv->complete(&oreq, -EINPROGRESS);
+ }
+ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
+ {
+       struct ahash_request *areq = req->data;
++      if (err == -EINPROGRESS) {
++              ahash_notify_einprogress(areq);
++              return;
++      }
++
+       /*
+        * Restore the original request, see ahash_op_unaligned() for what
+        * goes where.
+@@ -326,7 +335,7 @@ static void ahash_op_unaligned_done(stru
+        */
+       /* First copy req->result into req->priv.result */
+-      ahash_op_unaligned_finish(areq, err);
++      ahash_restore_req(areq, err);
+       /* Complete the ORIGINAL request. */
+       areq->base.complete(&areq->base, err);
+@@ -342,7 +351,12 @@ static int ahash_op_unaligned(struct aha
+               return err;
+       err = op(req);
+-      ahash_op_unaligned_finish(req, err);
++      if (err == -EINPROGRESS ||
++          (err == -EBUSY && (ahash_request_flags(req) &
++                             CRYPTO_TFM_REQ_MAY_BACKLOG)))
++              return err;
++
++      ahash_restore_req(req, err);
+       return err;
+ }
+@@ -377,25 +391,14 @@ int crypto_ahash_digest(struct ahash_req
+ }
+ EXPORT_SYMBOL_GPL(crypto_ahash_digest);
+-static void ahash_def_finup_finish2(struct ahash_request *req, int err)
++static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
+ {
+-      struct ahash_request_priv *priv = req->priv;
++      struct ahash_request *areq = req->data;
+       if (err == -EINPROGRESS)
+               return;
+-      if (!err)
+-              memcpy(priv->result, req->result,
+-                     crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+-
+-      ahash_restore_req(req);
+-}
+-
+-static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
+-{
+-      struct ahash_request *areq = req->data;
+-
+-      ahash_def_finup_finish2(areq, err);
++      ahash_restore_req(areq, err);
+       areq->base.complete(&areq->base, err);
+ }
+@@ -406,11 +409,15 @@ static int ahash_def_finup_finish1(struc
+               goto out;
+       req->base.complete = ahash_def_finup_done2;
+-      req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
++
+       err = crypto_ahash_reqtfm(req)->final(req);
++      if (err == -EINPROGRESS ||
++          (err == -EBUSY && (ahash_request_flags(req) &
++                             CRYPTO_TFM_REQ_MAY_BACKLOG)))
++              return err;
+ out:
+-      ahash_def_finup_finish2(req, err);
++      ahash_restore_req(req, err);
+       return err;
+ }
+@@ -418,7 +425,16 @@ static void ahash_def_finup_done1(struct
+ {
+       struct ahash_request *areq = req->data;
++      if (err == -EINPROGRESS) {
++              ahash_notify_einprogress(areq);
++              return;
++      }
++
++      areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
++
+       err = ahash_def_finup_finish1(areq, err);
++      if (areq->priv)
++              return;
+       areq->base.complete(&areq->base, err);
+ }
+@@ -433,6 +449,11 @@ static int ahash_def_finup(struct ahash_
+               return err;
+       err = tfm->update(req);
++      if (err == -EINPROGRESS ||
++          (err == -EBUSY && (ahash_request_flags(req) &
++                             CRYPTO_TFM_REQ_MAY_BACKLOG)))
++              return err;
++
+       return ahash_def_finup_finish1(req, err);
+ }
+--- a/include/crypto/internal/hash.h
++++ b/include/crypto/internal/hash.h
+@@ -173,6 +173,16 @@ static inline struct ahash_instance *aha
+       return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
+ }
++static inline void ahash_request_complete(struct ahash_request *req, int err)
++{
++      req->base.complete(&req->base, err);
++}
++
++static inline u32 ahash_request_flags(struct ahash_request *req)
++{
++      return req->base.flags;
++}
++
+ static inline struct crypto_ahash *crypto_spawn_ahash(
+       struct crypto_ahash_spawn *spawn)
+ {
diff --git a/queue-4.4/dvb-usb-don-t-use-stack-for-firmware-load.patch b/queue-4.4/dvb-usb-don-t-use-stack-for-firmware-load.patch
new file mode 100644 (file)
index 0000000..15abf75
--- /dev/null
@@ -0,0 +1,136 @@
+From 43fab9793c1f44e665b4f98035a14942edf03ddc Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Tue, 24 Jan 2017 08:13:11 -0200
+Subject: [media] dvb-usb: don't use stack for firmware load
+
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+
+commit 43fab9793c1f44e665b4f98035a14942edf03ddc upstream.
+
+As reported by Marc Duponcheel <marc@offline.be>, firmware load on
+dvb-usb is using the stack, with is not allowed anymore on default
+Kernel configurations:
+
+[ 1025.958836] dvb-usb: found a 'WideView WT-220U PenType Receiver (based on ZL353)' in cold state, will try to load a firmware
+[ 1025.958853] dvb-usb: downloading firmware from file 'dvb-usb-wt220u-zl0353-01.fw'
+[ 1025.958855] dvb-usb: could not stop the USB controller CPU.
+[ 1025.958856] dvb-usb: error while transferring firmware (transferred size: -11, block size: 3)
+[ 1025.958856] dvb-usb: firmware download failed at 8 with -22
+[ 1025.958867] usbcore: registered new interface driver dvb_usb_dtt200u
+
+[    2.789902] dvb-usb: downloading firmware from file 'dvb-usb-wt220u-zl0353-01.fw'
+[    2.789905] ------------[ cut here ]------------
+[    2.789911] WARNING: CPU: 3 PID: 2196 at drivers/usb/core/hcd.c:1584 usb_hcd_map_urb_for_dma+0x430/0x560 [usbcore]
+[    2.789912] transfer buffer not dma capable
+[    2.789912] Modules linked in: btusb dvb_usb_dtt200u(+) dvb_usb_af9035(+) btrtl btbcm dvb_usb dvb_usb_v2 btintel dvb_core bluetooth rc_core rfkill x86_pkg_temp_thermal intel_powerclamp coretemp crc32_pclmul aesni_intel aes_x86_64 glue_helper lrw gf128mul ablk_helper cryptd drm_kms_helper syscopyarea sysfillrect pcspkr i2c_i801 sysimgblt fb_sys_fops drm i2c_smbus i2c_core r8169 lpc_ich mfd_core mii thermal fan rtc_cmos video button acpi_cpufreq processor snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd crc32c_intel ahci libahci libata xhci_pci ehci_pci xhci_hcd ehci_hcd usbcore usb_common dm_mirror dm_region_hash dm_log dm_mod
+[    2.789936] CPU: 3 PID: 2196 Comm: systemd-udevd Not tainted 4.9.0-gentoo #1
+[    2.789937] Hardware name: ASUS All Series/H81I-PLUS, BIOS 0401 07/23/2013
+[    2.789938]  ffffc9000339b690 ffffffff812bd397 ffffc9000339b6e0 0000000000000000
+[    2.789939]  ffffc9000339b6d0 ffffffff81055c86 000006300339b6a0 ffff880116c0c000
+[    2.789941]  0000000000000000 0000000000000000 0000000000000001 ffff880116c08000
+[    2.789942] Call Trace:
+[    2.789945]  [<ffffffff812bd397>] dump_stack+0x4d/0x66
+[    2.789947]  [<ffffffff81055c86>] __warn+0xc6/0xe0
+[    2.789948]  [<ffffffff81055cea>] warn_slowpath_fmt+0x4a/0x50
+[    2.789952]  [<ffffffffa006d460>] usb_hcd_map_urb_for_dma+0x430/0x560 [usbcore]
+[    2.789954]  [<ffffffff814ed5a8>] ? io_schedule_timeout+0xd8/0x110
+[    2.789956]  [<ffffffffa006e09c>] usb_hcd_submit_urb+0x9c/0x980 [usbcore]
+[    2.789958]  [<ffffffff812d0ebf>] ? copy_page_to_iter+0x14f/0x2b0
+[    2.789960]  [<ffffffff81126818>] ? pagecache_get_page+0x28/0x240
+[    2.789962]  [<ffffffff8118c2a0>] ? touch_atime+0x20/0xa0
+[    2.789964]  [<ffffffffa006f7c4>] usb_submit_urb+0x2c4/0x520 [usbcore]
+[    2.789967]  [<ffffffffa006feca>] usb_start_wait_urb+0x5a/0xe0 [usbcore]
+[    2.789969]  [<ffffffffa007000c>] usb_control_msg+0xbc/0xf0 [usbcore]
+[    2.789970]  [<ffffffffa067903d>] usb_cypress_writemem+0x3d/0x40 [dvb_usb]
+[    2.789972]  [<ffffffffa06791cf>] usb_cypress_load_firmware+0x4f/0x130 [dvb_usb]
+[    2.789973]  [<ffffffff8109dbbe>] ? console_unlock+0x2fe/0x5d0
+[    2.789974]  [<ffffffff8109e10c>] ? vprintk_emit+0x27c/0x410
+[    2.789975]  [<ffffffff8109e40a>] ? vprintk_default+0x1a/0x20
+[    2.789976]  [<ffffffff81124d76>] ? printk+0x43/0x4b
+[    2.789977]  [<ffffffffa0679310>] dvb_usb_download_firmware+0x60/0xd0 [dvb_usb]
+[    2.789979]  [<ffffffffa0679898>] dvb_usb_device_init+0x3d8/0x610 [dvb_usb]
+[    2.789981]  [<ffffffffa069e302>] dtt200u_usb_probe+0x92/0xd0 [dvb_usb_dtt200u]
+[    2.789984]  [<ffffffffa007420c>] usb_probe_interface+0xfc/0x270 [usbcore]
+[    2.789985]  [<ffffffff8138bf95>] driver_probe_device+0x215/0x2d0
+[    2.789986]  [<ffffffff8138c0e6>] __driver_attach+0x96/0xa0
+[    2.789987]  [<ffffffff8138c050>] ? driver_probe_device+0x2d0/0x2d0
+[    2.789988]  [<ffffffff81389ffb>] bus_for_each_dev+0x5b/0x90
+[    2.789989]  [<ffffffff8138b7b9>] driver_attach+0x19/0x20
+[    2.789990]  [<ffffffff8138b33c>] bus_add_driver+0x11c/0x220
+[    2.789991]  [<ffffffff8138c91b>] driver_register+0x5b/0xd0
+[    2.789994]  [<ffffffffa0072f6c>] usb_register_driver+0x7c/0x130 [usbcore]
+[    2.789994]  [<ffffffffa06a5000>] ? 0xffffffffa06a5000
+[    2.789996]  [<ffffffffa06a501e>] dtt200u_usb_driver_init+0x1e/0x20 [dvb_usb_dtt200u]
+[    2.789997]  [<ffffffff81000408>] do_one_initcall+0x38/0x140
+[    2.789998]  [<ffffffff8116001c>] ? __vunmap+0x7c/0xc0
+[    2.789999]  [<ffffffff81124fb0>] ? do_init_module+0x22/0x1d2
+[    2.790000]  [<ffffffff81124fe8>] do_init_module+0x5a/0x1d2
+[    2.790002]  [<ffffffff810c96b1>] load_module+0x1e11/0x2580
+[    2.790003]  [<ffffffff810c68b0>] ? show_taint+0x30/0x30
+[    2.790004]  [<ffffffff81177250>] ? kernel_read_file+0x100/0x190
+[    2.790005]  [<ffffffff810c9ffa>] SyS_finit_module+0xba/0xc0
+[    2.790007]  [<ffffffff814f13e0>] entry_SYSCALL_64_fastpath+0x13/0x94
+[    2.790008] ---[ end trace c78a74e78baec6fc ]---
+
+So, allocate the structure dynamically.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 4.9: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/usb/dvb-usb/dvb-usb-firmware.c |   19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+--- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
++++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
+@@ -35,29 +35,34 @@ static int usb_cypress_writemem(struct u
+ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
+ {
+-      struct hexline hx;
++      struct hexline *hx;
+       u8 reset;
+       int ret,pos=0;
++      hx = kmalloc(sizeof(*hx), GFP_KERNEL);
++      if (!hx)
++              return -ENOMEM;
++
+       /* stop the CPU */
+       reset = 1;
+       if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+               err("could not stop the USB controller CPU.");
+-      while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
+-              deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
+-              ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
++      while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
++              deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk);
++              ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
+-              if (ret != hx.len) {
++              if (ret != hx->len) {
+                       err("error while transferring firmware "
+                               "(transferred size: %d, block size: %d)",
+-                              ret,hx.len);
++                              ret, hx->len);
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+       if (ret < 0) {
+               err("firmware download failed at %d with %d",pos,ret);
++              kfree(hx);
+               return ret;
+       }
+@@ -71,6 +76,8 @@ int usb_cypress_load_firmware(struct usb
+       } else
+               ret = -EIO;
++      kfree(hx);
++
+       return ret;
+ }
+ EXPORT_SYMBOL(usb_cypress_load_firmware);
diff --git a/queue-4.4/dvb-usb-firmware-don-t-do-dma-on-stack.patch b/queue-4.4/dvb-usb-firmware-don-t-do-dma-on-stack.patch
new file mode 100644 (file)
index 0000000..f9ed480
--- /dev/null
@@ -0,0 +1,80 @@
+From 67b0503db9c29b04eadfeede6bebbfe5ddad94ef Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
+Date: Sun, 12 Feb 2017 13:02:13 -0200
+Subject: [media] dvb-usb-firmware: don't do DMA on stack
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Brüns <stefan.bruens@rwth-aachen.de>
+
+commit 67b0503db9c29b04eadfeede6bebbfe5ddad94ef upstream.
+
+The buffer allocation for the firmware data was changed in
+commit 43fab9793c1f ("[media] dvb-usb: don't use stack for firmware load")
+but the same applies for the reset value.
+
+Fixes: 43fab9793c1f ("[media] dvb-usb: don't use stack for firmware load")
+Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Cc: Brad Spengler <spender@grsecurity.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/usb/dvb-usb/dvb-usb-firmware.c |   22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+--- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
++++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
+@@ -36,16 +36,18 @@ static int usb_cypress_writemem(struct u
+ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
+ {
+       struct hexline *hx;
+-      u8 reset;
+-      int ret,pos=0;
++      u8 *buf;
++      int ret, pos = 0;
++      u16 cpu_cs_register = cypress[type].cpu_cs_register;
+-      hx = kmalloc(sizeof(*hx), GFP_KERNEL);
+-      if (!hx)
++      buf = kmalloc(sizeof(*hx), GFP_KERNEL);
++      if (!buf)
+               return -ENOMEM;
++      hx = (struct hexline *)buf;
+       /* stop the CPU */
+-      reset = 1;
+-      if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
++      buf[0] = 1;
++      if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
+               err("could not stop the USB controller CPU.");
+       while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
+@@ -62,21 +64,21 @@ int usb_cypress_load_firmware(struct usb
+       }
+       if (ret < 0) {
+               err("firmware download failed at %d with %d",pos,ret);
+-              kfree(hx);
++              kfree(buf);
+               return ret;
+       }
+       if (ret == 0) {
+               /* restart the CPU */
+-              reset = 0;
+-              if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
++              buf[0] = 0;
++              if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
+                       err("could not restart the USB controller CPU.");
+                       ret = -EINVAL;
+               }
+       } else
+               ret = -EIO;
+-      kfree(hx);
++      kfree(buf);
+       return ret;
+ }
diff --git a/queue-4.4/dvb-usb-v2-avoid-use-after-free.patch b/queue-4.4/dvb-usb-v2-avoid-use-after-free.patch
new file mode 100644 (file)
index 0000000..298118b
--- /dev/null
@@ -0,0 +1,59 @@
+From 005145378c9ad7575a01b6ce1ba118fb427f583a Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Thu, 2 Feb 2017 12:36:01 -0200
+Subject: [media] dvb-usb-v2: avoid use-after-free
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+commit 005145378c9ad7575a01b6ce1ba118fb427f583a upstream.
+
+I ran into a stack frame size warning because of the on-stack copy of
+the USB device structure:
+
+drivers/media/usb/dvb-usb-v2/dvb_usb_core.c: In function 'dvb_usbv2_disconnect':
+drivers/media/usb/dvb-usb-v2/dvb_usb_core.c:1029:1: error: the frame size of 1104 bytes is larger than 1024 bytes [-Werror=frame-larger-than=]
+
+Copying a device structure like this is wrong for a number of other reasons
+too aside from the possible stack overflow. One of them is that the
+dev_info() call will print the name of the device later, but AFAICT
+we have only copied a pointer to the name earlier and the actual name
+has been freed by the time it gets printed.
+
+This removes the on-stack copy of the device and instead copies the
+device name using kstrdup(). I'm ignoring the possible failure here
+as both printk() and kfree() are able to deal with NULL pointers.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |    9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
++++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+@@ -1010,8 +1010,8 @@ EXPORT_SYMBOL(dvb_usbv2_probe);
+ void dvb_usbv2_disconnect(struct usb_interface *intf)
+ {
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+-      const char *name = d->name;
+-      struct device dev = d->udev->dev;
++      const char *devname = kstrdup(dev_name(&d->udev->dev), GFP_KERNEL);
++      const char *drvname = d->name;
+       dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
+                       intf->cur_altsetting->desc.bInterfaceNumber);
+@@ -1021,8 +1021,9 @@ void dvb_usbv2_disconnect(struct usb_int
+       dvb_usbv2_exit(d);
+-      dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
+-                      KBUILD_MODNAME, name);
++      pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n",
++              KBUILD_MODNAME, drvname, devname);
++      kfree(devname);
+ }
+ EXPORT_SYMBOL(dvb_usbv2_disconnect);
diff --git a/queue-4.4/ext4-fix-inode-checksum-calculation-problem-if-i_extra_size-is-small.patch b/queue-4.4/ext4-fix-inode-checksum-calculation-problem-if-i_extra_size-is-small.patch
new file mode 100644 (file)
index 0000000..76e40ea
--- /dev/null
@@ -0,0 +1,42 @@
+From 05ac5aa18abd7db341e54df4ae2b4c98ea0e43b7 Mon Sep 17 00:00:00 2001
+From: Daeho Jeong <daeho.jeong@samsung.com>
+Date: Thu, 1 Dec 2016 11:49:12 -0500
+Subject: ext4: fix inode checksum calculation problem if i_extra_size is small
+
+From: Daeho Jeong <daeho.jeong@samsung.com>
+
+commit 05ac5aa18abd7db341e54df4ae2b4c98ea0e43b7 upstream.
+
+We've fixed the race condition problem in calculating ext4 checksum
+value in commit b47820edd163 ("ext4: avoid modifying checksum fields
+directly during checksum veficationon"). However, by this change,
+when calculating the checksum value of inode whose i_extra_size is
+less than 4, we couldn't calculate the checksum value in a proper way.
+This problem was found and reported by Nix, Thank you.
+
+Reported-by: Nix <nix@esperi.org.uk>
+Signed-off-by: Daeho Jeong <daeho.jeong@samsung.com>
+Signed-off-by: Youngjin Gil <youngjin.gil@samsung.com>
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/inode.c |    5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -71,10 +71,9 @@ static __u32 ext4_inode_csum(struct inod
+                       csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
+                                          csum_size);
+                       offset += csum_size;
+-                      csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+-                                         EXT4_INODE_SIZE(inode->i_sb) -
+-                                         offset);
+               }
++              csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
++                                 EXT4_INODE_SIZE(inode->i_sb) - offset);
+       }
+       return csum;
diff --git a/queue-4.4/mm-tighten-x86-dev-mem-with-zeroing-reads.patch b/queue-4.4/mm-tighten-x86-dev-mem-with-zeroing-reads.patch
new file mode 100644 (file)
index 0000000..bfb60ab
--- /dev/null
@@ -0,0 +1,210 @@
+From a4866aa812518ed1a37d8ea0c881dc946409de94 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 5 Apr 2017 09:39:08 -0700
+Subject: mm: Tighten x86 /dev/mem with zeroing reads
+
+From: Kees Cook <keescook@chromium.org>
+
+commit a4866aa812518ed1a37d8ea0c881dc946409de94 upstream.
+
+Under CONFIG_STRICT_DEVMEM, reading System RAM through /dev/mem is
+disallowed. However, on x86, the first 1MB was always allowed for BIOS
+and similar things, regardless of it actually being System RAM. It was
+possible for heap to end up getting allocated in low 1MB RAM, and then
+read by things like x86info or dd, which would trip hardened usercopy:
+
+usercopy: kernel memory exposure attempt detected from ffff880000090000 (dma-kmalloc-256) (4096 bytes)
+
+This changes the x86 exception for the low 1MB by reading back zeros for
+System RAM areas instead of blindly allowing them. More work is needed to
+extend this to mmap, but currently mmap doesn't go through usercopy, so
+hardened usercopy won't Oops the kernel.
+
+Reported-by: Tommi Rantala <tommi.t.rantala@nokia.com>
+Tested-by: Tommi Rantala <tommi.t.rantala@nokia.com>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Cc: Brad Spengler <spender@grsecurity.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/mm/init.c |   41 +++++++++++++++++++-------
+ drivers/char/mem.c |   82 +++++++++++++++++++++++++++++++++--------------------
+ 2 files changed, 82 insertions(+), 41 deletions(-)
+
+--- a/arch/x86/mm/init.c
++++ b/arch/x86/mm/init.c
+@@ -628,21 +628,40 @@ void __init init_mem_mapping(void)
+  * devmem_is_allowed() checks to see if /dev/mem access to a certain address
+  * is valid. The argument is a physical page number.
+  *
+- *
+- * On x86, access has to be given to the first megabyte of ram because that area
+- * contains BIOS code and data regions used by X and dosemu and similar apps.
+- * Access has to be given to non-kernel-ram areas as well, these contain the PCI
+- * mmio resources as well as potential bios/acpi data regions.
++ * On x86, access has to be given to the first megabyte of RAM because that
++ * area traditionally contains BIOS code and data regions used by X, dosemu,
++ * and similar apps. Since they map the entire memory range, the whole range
++ * must be allowed (for mapping), but any areas that would otherwise be
++ * disallowed are flagged as being "zero filled" instead of rejected.
++ * Access has to be given to non-kernel-ram areas as well, these contain the
++ * PCI mmio resources as well as potential bios/acpi data regions.
+  */
+ int devmem_is_allowed(unsigned long pagenr)
+ {
+-      if (pagenr < 256)
+-              return 1;
+-      if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
++      if (page_is_ram(pagenr)) {
++              /*
++               * For disallowed memory regions in the low 1MB range,
++               * request that the page be shown as all zeros.
++               */
++              if (pagenr < 256)
++                      return 2;
++
++              return 0;
++      }
++
++      /*
++       * This must follow RAM test, since System RAM is considered a
++       * restricted resource under CONFIG_STRICT_IOMEM.
++       */
++      if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) {
++              /* Low 1MB bypasses iomem restrictions. */
++              if (pagenr < 256)
++                      return 1;
++
+               return 0;
+-      if (!page_is_ram(pagenr))
+-              return 1;
+-      return 0;
++      }
++
++      return 1;
+ }
+ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -59,6 +59,10 @@ static inline int valid_mmap_phys_addr_r
+ #endif
+ #ifdef CONFIG_STRICT_DEVMEM
++static inline int page_is_allowed(unsigned long pfn)
++{
++      return devmem_is_allowed(pfn);
++}
+ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+ {
+       u64 from = ((u64)pfn) << PAGE_SHIFT;
+@@ -78,6 +82,10 @@ static inline int range_is_allowed(unsig
+       return 1;
+ }
+ #else
++static inline int page_is_allowed(unsigned long pfn)
++{
++      return 1;
++}
+ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+ {
+       return 1;
+@@ -125,23 +133,31 @@ static ssize_t read_mem(struct file *fil
+       while (count > 0) {
+               unsigned long remaining;
++              int allowed;
+               sz = size_inside_page(p, count);
+-              if (!range_is_allowed(p >> PAGE_SHIFT, count))
++              allowed = page_is_allowed(p >> PAGE_SHIFT);
++              if (!allowed)
+                       return -EPERM;
++              if (allowed == 2) {
++                      /* Show zeros for restricted memory. */
++                      remaining = clear_user(buf, sz);
++              } else {
++                      /*
++                       * On ia64 if a page has been mapped somewhere as
++                       * uncached, then it must also be accessed uncached
++                       * by the kernel or data corruption may occur.
++                       */
++                      ptr = xlate_dev_mem_ptr(p);
++                      if (!ptr)
++                              return -EFAULT;
+-              /*
+-               * On ia64 if a page has been mapped somewhere as uncached, then
+-               * it must also be accessed uncached by the kernel or data
+-               * corruption may occur.
+-               */
+-              ptr = xlate_dev_mem_ptr(p);
+-              if (!ptr)
+-                      return -EFAULT;
++                      remaining = copy_to_user(buf, ptr, sz);
++
++                      unxlate_dev_mem_ptr(p, ptr);
++              }
+-              remaining = copy_to_user(buf, ptr, sz);
+-              unxlate_dev_mem_ptr(p, ptr);
+               if (remaining)
+                       return -EFAULT;
+@@ -184,30 +200,36 @@ static ssize_t write_mem(struct file *fi
+ #endif
+       while (count > 0) {
++              int allowed;
++
+               sz = size_inside_page(p, count);
+-              if (!range_is_allowed(p >> PAGE_SHIFT, sz))
++              allowed = page_is_allowed(p >> PAGE_SHIFT);
++              if (!allowed)
+                       return -EPERM;
+-              /*
+-               * On ia64 if a page has been mapped somewhere as uncached, then
+-               * it must also be accessed uncached by the kernel or data
+-               * corruption may occur.
+-               */
+-              ptr = xlate_dev_mem_ptr(p);
+-              if (!ptr) {
+-                      if (written)
+-                              break;
+-                      return -EFAULT;
+-              }
++              /* Skip actual writing when a page is marked as restricted. */
++              if (allowed == 1) {
++                      /*
++                       * On ia64 if a page has been mapped somewhere as
++                       * uncached, then it must also be accessed uncached
++                       * by the kernel or data corruption may occur.
++                       */
++                      ptr = xlate_dev_mem_ptr(p);
++                      if (!ptr) {
++                              if (written)
++                                      break;
++                              return -EFAULT;
++                      }
+-              copied = copy_from_user(ptr, buf, sz);
+-              unxlate_dev_mem_ptr(p, ptr);
+-              if (copied) {
+-                      written += sz - copied;
+-                      if (written)
+-                              break;
+-                      return -EFAULT;
++                      copied = copy_from_user(ptr, buf, sz);
++                      unxlate_dev_mem_ptr(p, ptr);
++                      if (copied) {
++                              written += sz - copied;
++                              if (written)
++                                      break;
++                              return -EFAULT;
++                      }
+               }
+               buf += sz;
diff --git a/queue-4.4/pegasus-use-heap-buffers-for-all-register-access.patch b/queue-4.4/pegasus-use-heap-buffers-for-all-register-access.patch
new file mode 100644 (file)
index 0000000..666c365
--- /dev/null
@@ -0,0 +1,96 @@
+From 5593523f968bc86d42a035c6df47d5e0979b5ace Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sat, 4 Feb 2017 16:56:03 +0000
+Subject: pegasus: Use heap buffers for all register access
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit 5593523f968bc86d42a035c6df47d5e0979b5ace upstream.
+
+Allocating USB buffers on the stack is not portable, and no longer
+works on x86_64 (with VMAP_STACK enabled as per default).
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+References: https://bugs.debian.org/852556
+Reported-by: Lisandro Damián Nicanor Pérez Meyer <lisandro@debian.org>
+Tested-by: Lisandro Damián Nicanor Pérez Meyer <lisandro@debian.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Cc: Brad Spengler <spender@grsecurity.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/usb/pegasus.c |   29 +++++++++++++++++++++++++----
+ 1 file changed, 25 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/usb/pegasus.c
++++ b/drivers/net/usb/pegasus.c
+@@ -126,40 +126,61 @@ static void async_ctrl_callback(struct u
+ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+ {
++      u8 *buf;
+       int ret;
++      buf = kmalloc(size, GFP_NOIO);
++      if (!buf)
++              return -ENOMEM;
++
+       ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0),
+                             PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0,
+-                            indx, data, size, 1000);
++                            indx, buf, size, 1000);
+       if (ret < 0)
+               netif_dbg(pegasus, drv, pegasus->net,
+                         "%s returned %d\n", __func__, ret);
++      else if (ret <= size)
++              memcpy(data, buf, ret);
++      kfree(buf);
+       return ret;
+ }
+-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
++static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
++                       const void *data)
+ {
++      u8 *buf;
+       int ret;
++      buf = kmemdup(data, size, GFP_NOIO);
++      if (!buf)
++              return -ENOMEM;
++
+       ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
+                             PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0,
+-                            indx, data, size, 100);
++                            indx, buf, size, 100);
+       if (ret < 0)
+               netif_dbg(pegasus, drv, pegasus->net,
+                         "%s returned %d\n", __func__, ret);
++      kfree(buf);
+       return ret;
+ }
+ static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
+ {
++      u8 *buf;
+       int ret;
++      buf = kmemdup(&data, 1, GFP_NOIO);
++      if (!buf)
++              return -ENOMEM;
++
+       ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
+                             PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data,
+-                            indx, &data, 1, 1000);
++                            indx, buf, 1, 1000);
+       if (ret < 0)
+               netif_dbg(pegasus, drv, pegasus->net,
+                         "%s returned %d\n", __func__, ret);
++      kfree(buf);
+       return ret;
+ }
diff --git a/queue-4.4/platform-x86-acer-wmi-setup-accelerometer-when-machine-has-appropriate-notify-event.patch b/queue-4.4/platform-x86-acer-wmi-setup-accelerometer-when-machine-has-appropriate-notify-event.patch
new file mode 100644 (file)
index 0000000..adf49bc
--- /dev/null
@@ -0,0 +1,84 @@
+From 98d610c3739ac354319a6590b915f4624d9151e6 Mon Sep 17 00:00:00 2001
+From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
+Date: Thu, 3 Nov 2016 08:18:52 +0800
+Subject: platform/x86: acer-wmi: setup accelerometer when machine has appropriate notify event
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lee, Chun-Yi <joeyli.kernel@gmail.com>
+
+commit 98d610c3739ac354319a6590b915f4624d9151e6 upstream.
+
+The accelerometer event relies on the ACERWMID_EVENT_GUID notify.
+So, this patch changes the codes to setup accelerometer input device
+when detected ACERWMID_EVENT_GUID. It avoids that the accel input
+device created on every Acer machines.
+
+In addition, patch adds a clearly parsing logic of accelerometer hid
+to acer_wmi_get_handle_cb callback function. It is positive matching
+the "SENR" name with "BST0001" device to avoid non-supported hardware.
+
+Reported-by: Bjørn Mork <bjorn@mork.no>
+Cc: Darren Hart <dvhart@infradead.org>
+Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
+[andy: slightly massage commit message]
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/platform/x86/acer-wmi.c |   22 ++++++++++++++++++----
+ 1 file changed, 18 insertions(+), 4 deletions(-)
+
+--- a/drivers/platform/x86/acer-wmi.c
++++ b/drivers/platform/x86/acer-wmi.c
+@@ -1816,11 +1816,24 @@ static int __init acer_wmi_enable_lm(voi
+       return status;
+ }
++#define ACER_WMID_ACCEL_HID   "BST0001"
++
+ static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
+                                               void *ctx, void **retval)
+ {
++      struct acpi_device *dev;
++
++      if (!strcmp(ctx, "SENR")) {
++              if (acpi_bus_get_device(ah, &dev))
++                      return AE_OK;
++              if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
++                      return AE_OK;
++      } else
++              return AE_OK;
++
+       *(acpi_handle *)retval = ah;
+-      return AE_OK;
++
++      return AE_CTRL_TERMINATE;
+ }
+ static int __init acer_wmi_get_handle(const char *name, const char *prop,
+@@ -1847,7 +1860,7 @@ static int __init acer_wmi_accel_setup(v
+ {
+       int err;
+-      err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
++      err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
+       if (err)
+               return err;
+@@ -2185,10 +2198,11 @@ static int __init acer_wmi_init(void)
+               err = acer_wmi_input_setup();
+               if (err)
+                       return err;
++              err = acer_wmi_accel_setup();
++              if (err)
++                      return err;
+       }
+-      acer_wmi_accel_setup();
+-
+       err = platform_driver_register(&acer_platform_driver);
+       if (err) {
+               pr_err("Unable to register platform driver\n");
diff --git a/queue-4.4/powerpc-disable-hfscr-if-tm-is-not-supported.patch b/queue-4.4/powerpc-disable-hfscr-if-tm-is-not-supported.patch
new file mode 100644 (file)
index 0000000..95bb0ff
--- /dev/null
@@ -0,0 +1,60 @@
+From 7ed23e1bae8bf7e37fd555066550a00b95a3a98b Mon Sep 17 00:00:00 2001
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Date: Mon, 20 Mar 2017 17:49:03 +1100
+Subject: powerpc: Disable HFSCR[TM] if TM is not supported
+
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+
+commit 7ed23e1bae8bf7e37fd555066550a00b95a3a98b upstream.
+
+On Power8 & Power9 the early CPU inititialisation in __init_HFSCR()
+turns on HFSCR[TM] (Hypervisor Facility Status and Control Register
+[Transactional Memory]), but that doesn't take into account that TM
+might be disabled by CPU features, or disabled by the kernel being built
+with CONFIG_PPC_TRANSACTIONAL_MEM=n.
+
+So later in boot, when we have setup the CPU features, clear HSCR[TM] if
+the TM CPU feature has been disabled. We use CPU_FTR_TM_COMP to account
+for the CONFIG_PPC_TRANSACTIONAL_MEM=n case.
+
+Without this a KVM guest might try use TM, even if told not to, and
+cause an oops in the host kernel. Typically the oops is seen in
+__kvmppc_vcore_entry() and may or may not be fatal to the host, but is
+always bad news.
+
+In practice all shipping CPU revisions do support TM, and all host
+kernels we are aware of build with TM support enabled, so no one should
+actually be able to hit this in the wild.
+
+Fixes: 2a3563b023e5 ("powerpc: Setup in HFSCR for POWER8")
+Cc: stable@vger.kernel.org # v3.10+
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Tested-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
+[mpe: Rewrite change log with input from Sam, add Fixes/stable]
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+[sb: Backported to linux-4.4.y: adjusted context]
+Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/powerpc/kernel/setup_64.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/arch/powerpc/kernel/setup_64.c
++++ b/arch/powerpc/kernel/setup_64.c
+@@ -220,6 +220,15 @@ static void cpu_ready_for_interrupts(voi
+               unsigned long lpcr = mfspr(SPRN_LPCR);
+               mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
+       }
++
++      /*
++       * Fixup HFSCR:TM based on CPU features. The bit is set by our
++       * early asm init because at that point we haven't updated our
++       * CPU features from firmware and device-tree. Here we have,
++       * so let's do it.
++       */
++      if (cpu_has_feature(CPU_FTR_HVMODE) && !cpu_has_feature(CPU_FTR_TM_COMP))
++              mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) & ~HFSCR_TM);
+ }
+ /*
diff --git a/queue-4.4/rtc-tegra-implement-clock-handling.patch b/queue-4.4/rtc-tegra-implement-clock-handling.patch
new file mode 100644 (file)
index 0000000..fc3026c
--- /dev/null
@@ -0,0 +1,125 @@
+From 5fa4086987506b2ab8c92f8f99f2295db9918856 Mon Sep 17 00:00:00 2001
+From: Thierry Reding <treding@nvidia.com>
+Date: Thu, 12 Jan 2017 17:07:43 +0100
+Subject: rtc: tegra: Implement clock handling
+
+From: Thierry Reding <treding@nvidia.com>
+
+commit 5fa4086987506b2ab8c92f8f99f2295db9918856 upstream.
+
+Accessing the registers of the RTC block on Tegra requires the module
+clock to be enabled. This only works because the RTC module clock will
+be enabled by default during early boot. However, because the clock is
+unused, the CCF will disable it at late_init time. This causes the RTC
+to become unusable afterwards. This can easily be reproduced by trying
+to use the RTC:
+
+       $ hwclock --rtc /dev/rtc1
+
+This will hang the system. I ran into this by following up on a report
+by Martin Michlmayr that reboot wasn't working on Tegra210 systems. It
+turns out that the rtc-tegra driver's ->shutdown() implementation will
+hang the CPU, because of the disabled clock, before the system can be
+rebooted.
+
+What confused me for a while is that the same driver is used on prior
+Tegra generations where the hang can not be observed. However, as Peter
+De Schrijver pointed out, this is because on 32-bit Tegra chips the RTC
+clock is enabled by the tegra20_timer.c clocksource driver, which uses
+the RTC to provide a persistent clock. This code is never enabled on
+64-bit Tegra because the persistent clock infrastructure does not exist
+on 64-bit ARM.
+
+The proper fix for this is to add proper clock handling to the RTC
+driver in order to ensure that the clock is enabled when the driver
+requires it. All device trees contain the clock already, therefore
+no additional changes are required.
+
+Reported-by: Martin Michlmayr <tbm@cyrius.com>
+Acked-By Peter De Schrijver <pdeschrijver@nvidia.com>
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+[bwh: Backported to 4.9: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/rtc/rtc-tegra.c |   28 ++++++++++++++++++++++++++--
+ 1 file changed, 26 insertions(+), 2 deletions(-)
+
+--- a/drivers/rtc/rtc-tegra.c
++++ b/drivers/rtc/rtc-tegra.c
+@@ -18,6 +18,7 @@
+  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+  */
+ #include <linux/kernel.h>
++#include <linux/clk.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+@@ -59,6 +60,7 @@ struct tegra_rtc_info {
+       struct platform_device  *pdev;
+       struct rtc_device       *rtc_dev;
+       void __iomem            *rtc_base; /* NULL if not initialized. */
++      struct clk              *clk;
+       int                     tegra_rtc_irq; /* alarm and periodic irq */
+       spinlock_t              tegra_rtc_lock;
+ };
+@@ -332,6 +334,14 @@ static int __init tegra_rtc_probe(struct
+       if (info->tegra_rtc_irq <= 0)
+               return -EBUSY;
++      info->clk = devm_clk_get(&pdev->dev, NULL);
++      if (IS_ERR(info->clk))
++              return PTR_ERR(info->clk);
++
++      ret = clk_prepare_enable(info->clk);
++      if (ret < 0)
++              return ret;
++
+       /* set context info. */
+       info->pdev = pdev;
+       spin_lock_init(&info->tegra_rtc_lock);
+@@ -352,7 +362,7 @@ static int __init tegra_rtc_probe(struct
+               ret = PTR_ERR(info->rtc_dev);
+               dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
+                       ret);
+-              return ret;
++              goto disable_clk;
+       }
+       ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
+@@ -362,12 +372,25 @@ static int __init tegra_rtc_probe(struct
+               dev_err(&pdev->dev,
+                       "Unable to request interrupt for device (err=%d).\n",
+                       ret);
+-              return ret;
++              goto disable_clk;
+       }
+       dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
+       return 0;
++
++disable_clk:
++      clk_disable_unprepare(info->clk);
++      return ret;
++}
++
++static int tegra_rtc_remove(struct platform_device *pdev)
++{
++      struct tegra_rtc_info *info = platform_get_drvdata(pdev);
++
++      clk_disable_unprepare(info->clk);
++
++      return 0;
+ }
+ #ifdef CONFIG_PM_SLEEP
+@@ -419,6 +442,7 @@ static void tegra_rtc_shutdown(struct pl
+ MODULE_ALIAS("platform:tegra_rtc");
+ static struct platform_driver tegra_rtc_driver = {
++      .remove         = tegra_rtc_remove,
+       .shutdown       = tegra_rtc_shutdown,
+       .driver         = {
+               .name   = "tegra_rtc",
diff --git a/queue-4.4/rtl8150-use-heap-buffers-for-all-register-access.patch b/queue-4.4/rtl8150-use-heap-buffers-for-all-register-access.patch
new file mode 100644 (file)
index 0000000..7b59f2b
--- /dev/null
@@ -0,0 +1,68 @@
+From 7926aff5c57b577ab0f43364ff0c59d968f6a414 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sat, 4 Feb 2017 16:56:32 +0000
+Subject: rtl8150: Use heap buffers for all register access
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit 7926aff5c57b577ab0f43364ff0c59d968f6a414 upstream.
+
+Allocating USB buffers on the stack is not portable, and no longer
+works on x86_64 (with VMAP_STACK enabled as per default).
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Cc: Brad Spengler <spender@grsecurity.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/usb/rtl8150.c |   34 +++++++++++++++++++++++++++-------
+ 1 file changed, 27 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/usb/rtl8150.c
++++ b/drivers/net/usb/rtl8150.c
+@@ -155,16 +155,36 @@ static const char driver_name [] = "rtl8
+ */
+ static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
+ {
+-      return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+-                             RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+-                             indx, 0, data, size, 500);
++      void *buf;
++      int ret;
++
++      buf = kmalloc(size, GFP_NOIO);
++      if (!buf)
++              return -ENOMEM;
++
++      ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
++                            RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
++                            indx, 0, buf, size, 500);
++      if (ret > 0 && ret <= size)
++              memcpy(data, buf, ret);
++      kfree(buf);
++      return ret;
+ }
+-static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
++static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data)
+ {
+-      return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+-                             RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+-                             indx, 0, data, size, 500);
++      void *buf;
++      int ret;
++
++      buf = kmemdup(data, size, GFP_NOIO);
++      if (!buf)
++              return -ENOMEM;
++
++      ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
++                            RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
++                            indx, 0, buf, size, 500);
++      kfree(buf);
++      return ret;
+ }
+ static void async_set_reg_cb(struct urb *urb)
index ad8f196c9f87887e82a5feb7a9c04d6a61e346c6..e5f877fc9be0988c71cecfd2776359ec0736e59a 100644 (file)
@@ -22,3 +22,18 @@ char-lack-of-bool-string-made-config_devport-always-on.patch
 revert-mips-lantiq-fix-cascaded-irq-setup.patch
 kvm-fix-page-struct-leak-in-handle_vmon.patch
 zram-do-not-use-copy_page-with-non-page-aligned-address.patch
+powerpc-disable-hfscr-if-tm-is-not-supported.patch
+crypto-ahash-fix-einprogress-notification-callback.patch
+ath9k-fix-null-pointer-dereference.patch
+dvb-usb-v2-avoid-use-after-free.patch
+ext4-fix-inode-checksum-calculation-problem-if-i_extra_size-is-small.patch
+platform-x86-acer-wmi-setup-accelerometer-when-machine-has-appropriate-notify-event.patch
+rtc-tegra-implement-clock-handling.patch
+mm-tighten-x86-dev-mem-with-zeroing-reads.patch
+dvb-usb-don-t-use-stack-for-firmware-load.patch
+dvb-usb-firmware-don-t-do-dma-on-stack.patch
+virtio-console-avoid-dma-from-stack.patch
+pegasus-use-heap-buffers-for-all-register-access.patch
+rtl8150-use-heap-buffers-for-all-register-access.patch
+catc-combine-failure-cleanup-code-in-catc_probe.patch
+catc-use-heap-buffer-for-memory-size-test.patch
diff --git a/queue-4.4/virtio-console-avoid-dma-from-stack.patch b/queue-4.4/virtio-console-avoid-dma-from-stack.patch
new file mode 100644 (file)
index 0000000..b1b4134
--- /dev/null
@@ -0,0 +1,52 @@
+From c4baad50297d84bde1a7ad45e50c73adae4a2192 Mon Sep 17 00:00:00 2001
+From: Omar Sandoval <osandov@fb.com>
+Date: Wed, 1 Feb 2017 00:02:27 -0800
+Subject: virtio-console: avoid DMA from stack
+
+From: Omar Sandoval <osandov@fb.com>
+
+commit c4baad50297d84bde1a7ad45e50c73adae4a2192 upstream.
+
+put_chars() stuffs the buffer it gets into an sg, but that buffer may be
+on the stack. This breaks with CONFIG_VMAP_STACK=y (for me, it
+manifested as printks getting turned into NUL bytes).
+
+Signed-off-by: Omar Sandoval <osandov@fb.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Reviewed-by: Amit Shah <amit.shah@redhat.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Cc: Brad Spengler <spender@grsecurity.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/virtio_console.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -1130,6 +1130,8 @@ static int put_chars(u32 vtermno, const
+ {
+       struct port *port;
+       struct scatterlist sg[1];
++      void *data;
++      int ret;
+       if (unlikely(early_put_chars))
+               return early_put_chars(vtermno, buf, count);
+@@ -1138,8 +1140,14 @@ static int put_chars(u32 vtermno, const
+       if (!port)
+               return -EPIPE;
+-      sg_init_one(sg, buf, count);
+-      return __send_to_port(port, sg, 1, count, (void *)buf, false);
++      data = kmemdup(buf, count, GFP_ATOMIC);
++      if (!data)
++              return -ENOMEM;
++
++      sg_init_one(sg, data, count);
++      ret = __send_to_port(port, sg, 1, count, data, false);
++      kfree(data);
++      return ret;
+ }
+ /*