]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 31 Mar 2022 06:24:48 +0000 (08:24 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 31 Mar 2022 06:24:48 +0000 (08:24 +0200)
added patches:
block-add-a-helper-to-validate-the-block-size.patch
tpm-fix-reference-counting-for-struct-tpm_chip.patch
virtio-blk-use-blk_validate_block_size-to-validate-block-size.patch

queue-5.4/block-add-a-helper-to-validate-the-block-size.patch [new file with mode: 0644]
queue-5.4/series
queue-5.4/tpm-fix-reference-counting-for-struct-tpm_chip.patch [new file with mode: 0644]
queue-5.4/virtio-blk-use-blk_validate_block_size-to-validate-block-size.patch [new file with mode: 0644]

diff --git a/queue-5.4/block-add-a-helper-to-validate-the-block-size.patch b/queue-5.4/block-add-a-helper-to-validate-the-block-size.patch
new file mode 100644 (file)
index 0000000..bd600a8
--- /dev/null
@@ -0,0 +1,40 @@
+From 570b1cac477643cbf01a45fa5d018430a1fddbce Mon Sep 17 00:00:00 2001
+From: Xie Yongji <xieyongji@bytedance.com>
+Date: Tue, 26 Oct 2021 22:40:12 +0800
+Subject: block: Add a helper to validate the block size
+
+From: Xie Yongji <xieyongji@bytedance.com>
+
+commit 570b1cac477643cbf01a45fa5d018430a1fddbce upstream.
+
+There are some duplicated codes to validate the block
+size in block drivers. This limitation actually comes
+from block layer, so this patch tries to add a new block
+layer helper for that.
+
+Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
+Link: https://lore.kernel.org/r/20211026144015.188-2-xieyongji@bytedance.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/blkdev.h |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -59,6 +59,14 @@ struct blk_stat_callback;
+  */
+ #define BLKCG_MAX_POLS                5
++static inline int blk_validate_block_size(unsigned int bsize)
++{
++      if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
++              return -EINVAL;
++
++      return 0;
++}
++
+ typedef void (rq_end_io_fn)(struct request *, blk_status_t);
+ /*
index 2b8b8e3cd1ebcf166fa025d585f056c8118685bc..c81b1acb2b6c639d0f85ae3aff1f000dd5eaab22 100644 (file)
@@ -13,3 +13,6 @@ spi-fix-erroneous-sgs-value-with-min_t.patch
 af_key-add-__gfp_zero-flag-for-compose_sadb_supporte.patch
 net-dsa-microchip-add-spi_device_id-tables.patch
 iommu-iova-improve-32-bit-free-space-estimate.patch
+tpm-fix-reference-counting-for-struct-tpm_chip.patch
+block-add-a-helper-to-validate-the-block-size.patch
+virtio-blk-use-blk_validate_block_size-to-validate-block-size.patch
diff --git a/queue-5.4/tpm-fix-reference-counting-for-struct-tpm_chip.patch b/queue-5.4/tpm-fix-reference-counting-for-struct-tpm_chip.patch
new file mode 100644 (file)
index 0000000..d78ce87
--- /dev/null
@@ -0,0 +1,273 @@
+From 7e0438f83dc769465ee663bb5dcf8cc154940712 Mon Sep 17 00:00:00 2001
+From: Lino Sanfilippo <LinoSanfilippo@gmx.de>
+Date: Wed, 2 Mar 2022 10:43:53 +0100
+Subject: tpm: fix reference counting for struct tpm_chip
+
+From: Lino Sanfilippo <LinoSanfilippo@gmx.de>
+
+commit 7e0438f83dc769465ee663bb5dcf8cc154940712 upstream.
+
+The following sequence of operations results in a refcount warning:
+
+1. Open device /dev/tpmrm.
+2. Remove module tpm_tis_spi.
+3. Write a TPM command to the file descriptor opened at step 1.
+
+------------[ cut here ]------------
+WARNING: CPU: 3 PID: 1161 at lib/refcount.c:25 kobject_get+0xa0/0xa4
+refcount_t: addition on 0; use-after-free.
+Modules linked in: tpm_tis_spi tpm_tis_core tpm mdio_bcm_unimac brcmfmac
+sha256_generic libsha256 sha256_arm hci_uart btbcm bluetooth cfg80211 vc4
+brcmutil ecdh_generic ecc snd_soc_core crc32_arm_ce libaes
+raspberrypi_hwmon ac97_bus snd_pcm_dmaengine bcm2711_thermal snd_pcm
+snd_timer genet snd phy_generic soundcore [last unloaded: spi_bcm2835]
+CPU: 3 PID: 1161 Comm: hold_open Not tainted 5.10.0ls-main-dirty #2
+Hardware name: BCM2711
+[<c0410c3c>] (unwind_backtrace) from [<c040b580>] (show_stack+0x10/0x14)
+[<c040b580>] (show_stack) from [<c1092174>] (dump_stack+0xc4/0xd8)
+[<c1092174>] (dump_stack) from [<c0445a30>] (__warn+0x104/0x108)
+[<c0445a30>] (__warn) from [<c0445aa8>] (warn_slowpath_fmt+0x74/0xb8)
+[<c0445aa8>] (warn_slowpath_fmt) from [<c08435d0>] (kobject_get+0xa0/0xa4)
+[<c08435d0>] (kobject_get) from [<bf0a715c>] (tpm_try_get_ops+0x14/0x54 [tpm])
+[<bf0a715c>] (tpm_try_get_ops [tpm]) from [<bf0a7d6c>] (tpm_common_write+0x38/0x60 [tpm])
+[<bf0a7d6c>] (tpm_common_write [tpm]) from [<c05a7ac0>] (vfs_write+0xc4/0x3c0)
+[<c05a7ac0>] (vfs_write) from [<c05a7ee4>] (ksys_write+0x58/0xcc)
+[<c05a7ee4>] (ksys_write) from [<c04001a0>] (ret_fast_syscall+0x0/0x4c)
+Exception stack(0xc226bfa8 to 0xc226bff0)
+bfa0:                   00000000 000105b4 00000003 beafe664 00000014 00000000
+bfc0: 00000000 000105b4 000103f8 00000004 00000000 00000000 b6f9c000 beafe684
+bfe0: 0000006c beafe648 0001056c b6eb6944
+---[ end trace d4b8409def9b8b1f ]---
+
+The reason for this warning is the attempt to get the chip->dev reference
+in tpm_common_write() although the reference counter is already zero.
+
+Since commit 8979b02aaf1d ("tpm: Fix reference count to main device") the
+extra reference used to prevent a premature zero counter is never taken,
+because the required TPM_CHIP_FLAG_TPM2 flag is never set.
+
+Fix this by moving the TPM 2 character device handling from
+tpm_chip_alloc() to tpm_add_char_device() which is called at a later point
+in time when the flag has been set in case of TPM2.
+
+Commit fdc915f7f719 ("tpm: expose spaces via a device link /dev/tpmrm<n>")
+already introduced function tpm_devs_release() to release the extra
+reference but did not implement the required put on chip->devs that results
+in the call of this function.
+
+Fix this by putting chip->devs in tpm_chip_unregister().
+
+Finally move the new implementation for the TPM 2 handling into a new
+function to avoid multiple checks for the TPM_CHIP_FLAG_TPM2 flag in the
+good case and error cases.
+
+Cc: stable@vger.kernel.org
+Fixes: fdc915f7f719 ("tpm: expose spaces via a device link /dev/tpmrm<n>")
+Fixes: 8979b02aaf1d ("tpm: Fix reference count to main device")
+Co-developed-by: Jason Gunthorpe <jgg@ziepe.ca>
+Signed-off-by: Jason Gunthorpe <jgg@ziepe.ca>
+Signed-off-by: Lino Sanfilippo <LinoSanfilippo@gmx.de>
+Tested-by: Stefan Berger <stefanb@linux.ibm.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/char/tpm/tpm-chip.c   |   46 +++++------------------------
+ drivers/char/tpm/tpm.h        |    2 +
+ drivers/char/tpm/tpm2-space.c |   65 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 75 insertions(+), 38 deletions(-)
+
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -274,14 +274,6 @@ static void tpm_dev_release(struct devic
+       kfree(chip);
+ }
+-static void tpm_devs_release(struct device *dev)
+-{
+-      struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
+-
+-      /* release the master device reference */
+-      put_device(&chip->dev);
+-}
+-
+ /**
+  * tpm_class_shutdown() - prepare the TPM device for loss of power.
+  * @dev: device to which the chip is associated.
+@@ -344,7 +336,6 @@ struct tpm_chip *tpm_chip_alloc(struct d
+       chip->dev_num = rc;
+       device_initialize(&chip->dev);
+-      device_initialize(&chip->devs);
+       chip->dev.class = tpm_class;
+       chip->dev.class->shutdown_pre = tpm_class_shutdown;
+@@ -352,39 +343,20 @@ struct tpm_chip *tpm_chip_alloc(struct d
+       chip->dev.parent = pdev;
+       chip->dev.groups = chip->groups;
+-      chip->devs.parent = pdev;
+-      chip->devs.class = tpmrm_class;
+-      chip->devs.release = tpm_devs_release;
+-      /* get extra reference on main device to hold on
+-       * behalf of devs.  This holds the chip structure
+-       * while cdevs is in use.  The corresponding put
+-       * is in the tpm_devs_release (TPM2 only)
+-       */
+-      if (chip->flags & TPM_CHIP_FLAG_TPM2)
+-              get_device(&chip->dev);
+-
+       if (chip->dev_num == 0)
+               chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
+       else
+               chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
+-      chip->devs.devt =
+-              MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
+-
+       rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num);
+       if (rc)
+               goto out;
+-      rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
+-      if (rc)
+-              goto out;
+       if (!pdev)
+               chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
+       cdev_init(&chip->cdev, &tpm_fops);
+-      cdev_init(&chip->cdevs, &tpmrm_fops);
+       chip->cdev.owner = THIS_MODULE;
+-      chip->cdevs.owner = THIS_MODULE;
+       rc = tpm2_init_space(&chip->work_space, TPM2_SPACE_BUFFER_SIZE);
+       if (rc) {
+@@ -396,7 +368,6 @@ struct tpm_chip *tpm_chip_alloc(struct d
+       return chip;
+ out:
+-      put_device(&chip->devs);
+       put_device(&chip->dev);
+       return ERR_PTR(rc);
+ }
+@@ -445,14 +416,9 @@ static int tpm_add_char_device(struct tp
+       }
+       if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+-              rc = cdev_device_add(&chip->cdevs, &chip->devs);
+-              if (rc) {
+-                      dev_err(&chip->devs,
+-                              "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
+-                              dev_name(&chip->devs), MAJOR(chip->devs.devt),
+-                              MINOR(chip->devs.devt), rc);
+-                      return rc;
+-              }
++              rc = tpm_devs_add(chip);
++              if (rc)
++                      goto err_del_cdev;
+       }
+       /* Make the chip available. */
+@@ -460,6 +426,10 @@ static int tpm_add_char_device(struct tp
+       idr_replace(&dev_nums_idr, chip, chip->dev_num);
+       mutex_unlock(&idr_lock);
++      return 0;
++
++err_del_cdev:
++      cdev_device_del(&chip->cdev, &chip->dev);
+       return rc;
+ }
+@@ -641,7 +611,7 @@ void tpm_chip_unregister(struct tpm_chip
+               hwrng_unregister(&chip->hwrng);
+       tpm_bios_log_teardown(chip);
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+-              cdev_device_del(&chip->cdevs, &chip->devs);
++              tpm_devs_remove(chip);
+       tpm_del_char_device(chip);
+ }
+ EXPORT_SYMBOL_GPL(tpm_chip_unregister);
+--- a/drivers/char/tpm/tpm.h
++++ b/drivers/char/tpm/tpm.h
+@@ -466,6 +466,8 @@ int tpm2_prepare_space(struct tpm_chip *
+                      size_t cmdsiz);
+ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf,
+                     size_t *bufsiz);
++int tpm_devs_add(struct tpm_chip *chip);
++void tpm_devs_remove(struct tpm_chip *chip);
+ void tpm_bios_log_setup(struct tpm_chip *chip);
+ void tpm_bios_log_teardown(struct tpm_chip *chip);
+--- a/drivers/char/tpm/tpm2-space.c
++++ b/drivers/char/tpm/tpm2-space.c
+@@ -574,3 +574,68 @@ out:
+       dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
+       return rc;
+ }
++
++/*
++ * Put the reference to the main device.
++ */
++static void tpm_devs_release(struct device *dev)
++{
++      struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
++
++      /* release the master device reference */
++      put_device(&chip->dev);
++}
++
++/*
++ * Remove the device file for exposed TPM spaces and release the device
++ * reference. This may also release the reference to the master device.
++ */
++void tpm_devs_remove(struct tpm_chip *chip)
++{
++      cdev_device_del(&chip->cdevs, &chip->devs);
++      put_device(&chip->devs);
++}
++
++/*
++ * Add a device file to expose TPM spaces. Also take a reference to the
++ * main device.
++ */
++int tpm_devs_add(struct tpm_chip *chip)
++{
++      int rc;
++
++      device_initialize(&chip->devs);
++      chip->devs.parent = chip->dev.parent;
++      chip->devs.class = tpmrm_class;
++
++      /*
++       * Get extra reference on main device to hold on behalf of devs.
++       * This holds the chip structure while cdevs is in use. The
++       * corresponding put is in the tpm_devs_release.
++       */
++      get_device(&chip->dev);
++      chip->devs.release = tpm_devs_release;
++      chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
++      cdev_init(&chip->cdevs, &tpmrm_fops);
++      chip->cdevs.owner = THIS_MODULE;
++
++      rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
++      if (rc)
++              goto err_put_devs;
++
++      rc = cdev_device_add(&chip->cdevs, &chip->devs);
++      if (rc) {
++              dev_err(&chip->devs,
++                      "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
++                      dev_name(&chip->devs), MAJOR(chip->devs.devt),
++                      MINOR(chip->devs.devt), rc);
++              goto err_put_devs;
++      }
++
++      return 0;
++
++err_put_devs:
++      put_device(&chip->devs);
++
++      return rc;
++}
diff --git a/queue-5.4/virtio-blk-use-blk_validate_block_size-to-validate-block-size.patch b/queue-5.4/virtio-blk-use-blk_validate_block_size-to-validate-block-size.patch
new file mode 100644 (file)
index 0000000..a874406
--- /dev/null
@@ -0,0 +1,72 @@
+From 57a13a5b8157d9a8606490aaa1b805bafe6c37e1 Mon Sep 17 00:00:00 2001
+From: Xie Yongji <xieyongji@bytedance.com>
+Date: Tue, 26 Oct 2021 22:40:15 +0800
+Subject: virtio-blk: Use blk_validate_block_size() to validate block size
+
+From: Xie Yongji <xieyongji@bytedance.com>
+
+commit 57a13a5b8157d9a8606490aaa1b805bafe6c37e1 upstream.
+
+The block layer can't support a block size larger than
+page size yet. And a block size that's too small or
+not a power of two won't work either. If a misconfigured
+device presents an invalid block size in configuration space,
+it will result in the kernel crash something like below:
+
+[  506.154324] BUG: kernel NULL pointer dereference, address: 0000000000000008
+[  506.160416] RIP: 0010:create_empty_buffers+0x24/0x100
+[  506.174302] Call Trace:
+[  506.174651]  create_page_buffers+0x4d/0x60
+[  506.175207]  block_read_full_page+0x50/0x380
+[  506.175798]  ? __mod_lruvec_page_state+0x60/0xa0
+[  506.176412]  ? __add_to_page_cache_locked+0x1b2/0x390
+[  506.177085]  ? blkdev_direct_IO+0x4a0/0x4a0
+[  506.177644]  ? scan_shadow_nodes+0x30/0x30
+[  506.178206]  ? lru_cache_add+0x42/0x60
+[  506.178716]  do_read_cache_page+0x695/0x740
+[  506.179278]  ? read_part_sector+0xe0/0xe0
+[  506.179821]  read_part_sector+0x36/0xe0
+[  506.180337]  adfspart_check_ICS+0x32/0x320
+[  506.180890]  ? snprintf+0x45/0x70
+[  506.181350]  ? read_part_sector+0xe0/0xe0
+[  506.181906]  bdev_disk_changed+0x229/0x5c0
+[  506.182483]  blkdev_get_whole+0x6d/0x90
+[  506.183013]  blkdev_get_by_dev+0x122/0x2d0
+[  506.183562]  device_add_disk+0x39e/0x3c0
+[  506.184472]  virtblk_probe+0x3f8/0x79b [virtio_blk]
+[  506.185461]  virtio_dev_probe+0x15e/0x1d0 [virtio]
+
+So let's use a block layer helper to validate the block size.
+
+Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Link: https://lore.kernel.org/r/20211026144015.188-5-xieyongji@bytedance.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/virtio_blk.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/block/virtio_blk.c
++++ b/drivers/block/virtio_blk.c
+@@ -936,9 +936,17 @@ static int virtblk_probe(struct virtio_d
+       err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
+                                  struct virtio_blk_config, blk_size,
+                                  &blk_size);
+-      if (!err)
++      if (!err) {
++              err = blk_validate_block_size(blk_size);
++              if (err) {
++                      dev_err(&vdev->dev,
++                              "virtio_blk: invalid block size: 0x%x\n",
++                              blk_size);
++                      goto out_free_tags;
++              }
++
+               blk_queue_logical_block_size(q, blk_size);
+-      else
++      } else
+               blk_size = queue_logical_block_size(q);
+       /* Use topology information if available */