--- /dev/null
+From 13b47cfcfc60495cde216eef4c01040d76174cbe Mon Sep 17 00:00:00 2001
+From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Date: Tue, 20 Jun 2017 11:38:02 +0200
+Subject: tpm: fix a kernel memory leak in tpm-sysfs.c
+
+From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+
+commit 13b47cfcfc60495cde216eef4c01040d76174cbe upstream.
+
+While cleaning up sysfs callback that prints EK we discovered a kernel
+memory leak. This commit fixes the issue by zeroing the buffer used for
+TPM command/response.
+
+The leak happen when we use either tpm_vtpm_proxy, tpm_ibmvtpm or
+xen-tpmfront.
+
+Fixes: 0883743825e3 ("TPM: sysfs functions consolidation")
+Reported-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+Tested-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Signed-off-by: James Morris <james.l.morris@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/char/tpm/tpm-sysfs.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/char/tpm/tpm-sysfs.c
++++ b/drivers/char/tpm/tpm-sysfs.c
+@@ -38,6 +38,8 @@ static ssize_t pubek_show(struct device
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
++ memset(&tpm_cmd, 0, sizeof(tpm_cmd));
++
+ tpm_cmd.header.in = tpm_readpubek_header;
+ err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0,
+ "attempting to read the PUBEK");
--- /dev/null
+From 15516788e581eb32ec1c50e5f00aba3faf95d817 Mon Sep 17 00:00:00 2001
+From: Stefan Berger <stefanb@linux.vnet.ibm.com>
+Date: Mon, 29 Feb 2016 08:53:02 -0500
+Subject: tpm: Replace device number bitmap with IDR
+
+From: Stefan Berger <stefanb@linux.vnet.ibm.com>
+
+commit 15516788e581eb32ec1c50e5f00aba3faf95d817 upstream.
+
+Replace the device number bitmap with IDR. Extend the number of devices we
+can create to 64k.
+Since an IDR allows us to associate a pointer with an ID, we use this now
+to rewrite tpm_chip_find_get() to simply look up the chip pointer by the
+given device ID.
+
+Protect the IDR calls with a mutex.
+
+Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
+Reviewed-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/tpm/tpm-chip.c | 84 ++++++++++++++++++++-------------------
+ drivers/char/tpm/tpm-interface.c | 1
+ drivers/char/tpm/tpm.h | 5 --
+ 3 files changed, 48 insertions(+), 42 deletions(-)
+
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -29,9 +29,8 @@
+ #include "tpm.h"
+ #include "tpm_eventlog.h"
+
+-static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
+-static LIST_HEAD(tpm_chip_list);
+-static DEFINE_SPINLOCK(driver_lock);
++DEFINE_IDR(dev_nums_idr);
++static DEFINE_MUTEX(idr_lock);
+
+ struct class *tpm_class;
+ dev_t tpm_devt;
+@@ -92,20 +91,30 @@ EXPORT_SYMBOL_GPL(tpm_put_ops);
+ */
+ struct tpm_chip *tpm_chip_find_get(int chip_num)
+ {
+- struct tpm_chip *pos, *chip = NULL;
++ struct tpm_chip *chip, *res = NULL;
++ int chip_prev;
+
+- rcu_read_lock();
+- list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
+- if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
+- continue;
+-
+- /* rcu prevents chip from being free'd */
+- if (!tpm_try_get_ops(pos))
+- chip = pos;
+- break;
++ mutex_lock(&idr_lock);
++
++ if (chip_num == TPM_ANY_NUM) {
++ chip_num = 0;
++ do {
++ chip_prev = chip_num;
++ chip = idr_get_next(&dev_nums_idr, &chip_num);
++ if (chip && !tpm_try_get_ops(chip)) {
++ res = chip;
++ break;
++ }
++ } while (chip_prev != chip_num);
++ } else {
++ chip = idr_find_slowpath(&dev_nums_idr, chip_num);
++ if (chip && !tpm_try_get_ops(chip))
++ res = chip;
+ }
+- rcu_read_unlock();
+- return chip;
++
++ mutex_unlock(&idr_lock);
++
++ return res;
+ }
+
+ /**
+@@ -118,9 +127,10 @@ static void tpm_dev_release(struct devic
+ {
+ struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+
+- spin_lock(&driver_lock);
+- clear_bit(chip->dev_num, dev_mask);
+- spin_unlock(&driver_lock);
++ mutex_lock(&idr_lock);
++ idr_remove(&dev_nums_idr, chip->dev_num);
++ mutex_unlock(&idr_lock);
++
+ kfree(chip);
+ }
+
+@@ -180,21 +190,18 @@ struct tpm_chip *tpmm_chip_alloc(struct
+
+ mutex_init(&chip->tpm_mutex);
+ init_rwsem(&chip->ops_sem);
+- INIT_LIST_HEAD(&chip->list);
+
+ chip->ops = ops;
+
+- spin_lock(&driver_lock);
+- chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
+- spin_unlock(&driver_lock);
+-
+- if (chip->dev_num >= TPM_NUM_DEVICES) {
++ mutex_lock(&idr_lock);
++ rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL);
++ mutex_unlock(&idr_lock);
++ if (rc < 0) {
+ dev_err(dev, "No available tpm device numbers\n");
+ kfree(chip);
+- return ERR_PTR(-ENOMEM);
++ return ERR_PTR(rc);
+ }
+-
+- set_bit(chip->dev_num, dev_mask);
++ chip->dev_num = rc;
+
+ scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num);
+
+@@ -252,19 +259,28 @@ static int tpm_add_char_device(struct tp
+ return rc;
+ }
+
++ /* Make the chip available. */
++ mutex_lock(&idr_lock);
++ idr_replace(&dev_nums_idr, chip, chip->dev_num);
++ mutex_unlock(&idr_lock);
++
+ return rc;
+ }
+
+ static void tpm_del_char_device(struct tpm_chip *chip)
+ {
+ cdev_del(&chip->cdev);
++ device_del(&chip->dev);
++
++ /* Make the chip unavailable. */
++ mutex_lock(&idr_lock);
++ idr_replace(&dev_nums_idr, NULL, chip->dev_num);
++ mutex_unlock(&idr_lock);
+
+ /* Make the driver uncallable. */
+ down_write(&chip->ops_sem);
+ chip->ops = NULL;
+ up_write(&chip->ops_sem);
+-
+- device_del(&chip->dev);
+ }
+
+ static int tpm1_chip_register(struct tpm_chip *chip)
+@@ -319,11 +335,6 @@ int tpm_chip_register(struct tpm_chip *c
+ if (rc)
+ goto out_err;
+
+- /* Make the chip available. */
+- spin_lock(&driver_lock);
+- list_add_tail_rcu(&chip->list, &tpm_chip_list);
+- spin_unlock(&driver_lock);
+-
+ chip->flags |= TPM_CHIP_FLAG_REGISTERED;
+
+ if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+@@ -360,11 +371,6 @@ void tpm_chip_unregister(struct tpm_chip
+ if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED))
+ return;
+
+- spin_lock(&driver_lock);
+- list_del_rcu(&chip->list);
+- spin_unlock(&driver_lock);
+- synchronize_rcu();
+-
+ if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
+ sysfs_remove_link(&chip->dev.parent->kobj, "ppi");
+
+--- a/drivers/char/tpm/tpm-interface.c
++++ b/drivers/char/tpm/tpm-interface.c
+@@ -1127,6 +1127,7 @@ static int __init tpm_init(void)
+
+ static void __exit tpm_exit(void)
+ {
++ idr_destroy(&dev_nums_idr);
+ class_destroy(tpm_class);
+ unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
+ }
+--- a/drivers/char/tpm/tpm.h
++++ b/drivers/char/tpm/tpm.h
+@@ -34,7 +34,7 @@
+ enum tpm_const {
+ TPM_MINOR = 224, /* officially assigned */
+ TPM_BUFSIZE = 4096,
+- TPM_NUM_DEVICES = 256,
++ TPM_NUM_DEVICES = 65536,
+ TPM_RETRY = 50, /* 5 seconds */
+ };
+
+@@ -200,8 +200,6 @@ struct tpm_chip {
+ acpi_handle acpi_dev_handle;
+ char ppi_version[TPM_PPI_VERSION_LEN + 1];
+ #endif /* CONFIG_ACPI */
+-
+- struct list_head list;
+ };
+
+ #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
+@@ -497,6 +495,7 @@ static inline void tpm_buf_append_u32(st
+ extern struct class *tpm_class;
+ extern dev_t tpm_devt;
+ extern const struct file_operations tpm_fops;
++extern struct idr dev_nums_idr;
+
+ enum tpm_transmit_flags {
+ TPM_TRANSMIT_UNLOCKED = BIT(0),
--- /dev/null
+From 71df1d7ccad1c36f7321d6b3b48f2ea42681c363 Mon Sep 17 00:00:00 2001
+From: Juergen Gross <jgross@suse.com>
+Date: Thu, 18 May 2017 17:28:48 +0200
+Subject: xen/blkback: don't free be structure too early
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Juergen Gross <jgross@suse.com>
+
+commit 71df1d7ccad1c36f7321d6b3b48f2ea42681c363 upstream.
+
+The be structure must not be freed when freeing the blkif structure
+isn't done. Otherwise a use-after-free of be when unmapping the ring
+used for communicating with the frontend will occur in case of a
+late call of xenblk_disconnect() (e.g. due to an I/O still active
+when trying to disconnect).
+
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Tested-by: Steven Haigh <netwiz@crc.id.au>
+Acked-by: Roger Pau Monné <roger.pau@citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/xen-blkback/xenbus.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/block/xen-blkback/xenbus.c
++++ b/drivers/block/xen-blkback/xenbus.c
+@@ -266,9 +266,10 @@ static int xen_blkif_disconnect(struct x
+
+ static void xen_blkif_free(struct xen_blkif *blkif)
+ {
+-
+- xen_blkif_disconnect(blkif);
++ WARN_ON(xen_blkif_disconnect(blkif));
+ xen_vbd_free(&blkif->vbd);
++ kfree(blkif->be->mode);
++ kfree(blkif->be);
+
+ /* Make sure everything is drained before shutting down */
+ BUG_ON(blkif->persistent_gnt_c != 0);
+@@ -445,8 +446,6 @@ static int xen_blkbk_remove(struct xenbu
+ xen_blkif_put(be->blkif);
+ }
+
+- kfree(be->mode);
+- kfree(be);
+ return 0;
+ }
+
--- /dev/null
+From a24fa22ce22ae302b3bf8f7008896d52d5d57b8d Mon Sep 17 00:00:00 2001
+From: Juergen Gross <jgross@suse.com>
+Date: Thu, 18 May 2017 17:28:49 +0200
+Subject: xen/blkback: don't use xen_blkif_get() in xen-blkback kthread
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Juergen Gross <jgross@suse.com>
+
+commit a24fa22ce22ae302b3bf8f7008896d52d5d57b8d upstream.
+
+There is no need to use xen_blkif_get()/xen_blkif_put() in the kthread
+of xen-blkback. Thread stopping is synchronous and using the blkif
+reference counting in the kthread will avoid to ever let the reference
+count drop to zero at the end of an I/O running concurrent to
+disconnecting and multiple rings.
+
+Setting ring->xenblkd to NULL after stopping the kthread isn't needed
+as the kthread does this already.
+
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Tested-by: Steven Haigh <netwiz@crc.id.au>
+Acked-by: Roger Pau Monné <roger.pau@citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/xen-blkback/blkback.c | 3 ---
+ drivers/block/xen-blkback/xenbus.c | 1 -
+ 2 files changed, 4 deletions(-)
+
+--- a/drivers/block/xen-blkback/blkback.c
++++ b/drivers/block/xen-blkback/blkback.c
+@@ -595,8 +595,6 @@ int xen_blkif_schedule(void *arg)
+ unsigned long timeout;
+ int ret;
+
+- xen_blkif_get(blkif);
+-
+ while (!kthread_should_stop()) {
+ if (try_to_freeze())
+ continue;
+@@ -650,7 +648,6 @@ purge_gnt_list:
+ print_stats(blkif);
+
+ blkif->xenblkd = NULL;
+- xen_blkif_put(blkif);
+
+ return 0;
+ }
+--- a/drivers/block/xen-blkback/xenbus.c
++++ b/drivers/block/xen-blkback/xenbus.c
+@@ -221,7 +221,6 @@ static int xen_blkif_disconnect(struct x
+ if (blkif->xenblkd) {
+ kthread_stop(blkif->xenblkd);
+ wake_up(&blkif->shutdown_wq);
+- blkif->xenblkd = NULL;
+ }
+
+ /* The above kthread_stop() guarantees that at this point we