]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 Jun 2023 18:45:52 +0000 (20:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 Jun 2023 18:45:52 +0000 (20:45 +0200)
added patches:
mm-fix-copy_from_user_nofault.patch
tpm-tpm_tis-claim-locality-in-interrupt-handler.patch
tpm_crb-add-support-for-crb-devices-based-on-pluton.patch

queue-6.1/mm-fix-copy_from_user_nofault.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/tpm-tpm_tis-claim-locality-in-interrupt-handler.patch [new file with mode: 0644]
queue-6.1/tpm_crb-add-support-for-crb-devices-based-on-pluton.patch [new file with mode: 0644]

diff --git a/queue-6.1/mm-fix-copy_from_user_nofault.patch b/queue-6.1/mm-fix-copy_from_user_nofault.patch
new file mode 100644 (file)
index 0000000..ba79c0f
--- /dev/null
@@ -0,0 +1,86 @@
+From d319f344561de23e810515d109c7278919bff7b0 Mon Sep 17 00:00:00 2001
+From: Alexei Starovoitov <ast@kernel.org>
+Date: Mon, 10 Apr 2023 19:43:44 +0200
+Subject: mm: Fix copy_from_user_nofault().
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+commit d319f344561de23e810515d109c7278919bff7b0 upstream.
+
+There are several issues with copy_from_user_nofault():
+
+- access_ok() is designed for user context only and for that reason
+it has WARN_ON_IN_IRQ() which triggers when bpf, kprobe, eprobe
+and perf on ppc are calling it from irq.
+
+- it's missing nmi_uaccess_okay() which is a nop on all architectures
+except x86 where it's required.
+The comment in arch/x86/mm/tlb.c explains the details why it's necessary.
+Calling copy_from_user_nofault() from bpf, [ke]probe without this check is not safe.
+
+- __copy_from_user_inatomic() under CONFIG_HARDENED_USERCOPY is calling
+check_object_size()->__check_object_size()->check_heap_object()->find_vmap_area()->spin_lock()
+which is not safe to do from bpf, [ke]probe and perf due to potential deadlock.
+
+Fix all three issues. At the end the copy_from_user_nofault() becomes
+equivalent to copy_from_user_nmi() from safety point of view with
+a difference in the return value.
+
+Reported-by: Hsin-Wei Hung <hsinweih@uci.edu>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Florian Lehner <dev@der-flo.net>
+Tested-by: Hsin-Wei Hung <hsinweih@uci.edu>
+Tested-by: Florian Lehner <dev@der-flo.net>
+Link: https://lore.kernel.org/r/20230410174345.4376-2-dev@der-flo.net
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Cc: Javier Honduvilla Coto <javierhonduco@gmail.com>
+Cc: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/maccess.c  |   16 +++++++++++-----
+ mm/usercopy.c |    2 +-
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+--- a/mm/maccess.c
++++ b/mm/maccess.c
+@@ -5,6 +5,7 @@
+ #include <linux/export.h>
+ #include <linux/mm.h>
+ #include <linux/uaccess.h>
++#include <asm/tlb.h>
+ bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src,
+               size_t size)
+@@ -113,11 +114,16 @@ Efault:
+ long copy_from_user_nofault(void *dst, const void __user *src, size_t size)
+ {
+       long ret = -EFAULT;
+-      if (access_ok(src, size)) {
+-              pagefault_disable();
+-              ret = __copy_from_user_inatomic(dst, src, size);
+-              pagefault_enable();
+-      }
++
++      if (!__access_ok(src, size))
++              return ret;
++
++      if (!nmi_uaccess_okay())
++              return ret;
++
++      pagefault_disable();
++      ret = __copy_from_user_inatomic(dst, src, size);
++      pagefault_enable();
+       if (ret)
+               return -EFAULT;
+--- a/mm/usercopy.c
++++ b/mm/usercopy.c
+@@ -172,7 +172,7 @@ static inline void check_heap_object(con
+               return;
+       }
+-      if (is_vmalloc_addr(ptr)) {
++      if (is_vmalloc_addr(ptr) && !pagefault_disabled()) {
+               struct vmap_area *area = find_vmap_area(addr);
+               if (!area)
index c212c16c409959f9edd818ecbed0984acb0bad16..7421d40dfaa895f861882261be54c304ebadcae2 100644 (file)
@@ -4,3 +4,6 @@ drm-amd-display-fix-the-system-hang-while-disable-ps.patch
 tty-serial-fsl_lpuart-make-rx_watermark-configurable.patch
 tty-serial-fsl_lpuart-reduce-rx-watermark-to-0-on-ls.patch
 ata-libata-scsi-avoid-deadlock-on-rescan-after-devic.patch
+mm-fix-copy_from_user_nofault.patch
+tpm-tpm_tis-claim-locality-in-interrupt-handler.patch
+tpm_crb-add-support-for-crb-devices-based-on-pluton.patch
diff --git a/queue-6.1/tpm-tpm_tis-claim-locality-in-interrupt-handler.patch b/queue-6.1/tpm-tpm_tis-claim-locality-in-interrupt-handler.patch
new file mode 100644 (file)
index 0000000..a6b9201
--- /dev/null
@@ -0,0 +1,39 @@
+From 0e069265bce5a40c4eee52e2364bbbd4dabee94a Mon Sep 17 00:00:00 2001
+From: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+Date: Thu, 24 Nov 2022 14:55:35 +0100
+Subject: tpm, tpm_tis: Claim locality in interrupt handler
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+
+commit 0e069265bce5a40c4eee52e2364bbbd4dabee94a upstream.
+
+Writing the TPM_INT_STATUS register in the interrupt handler to clear the
+interrupts only has effect if a locality is held. Since this is not
+guaranteed at the time the interrupt is fired, claim the locality
+explicitly in the handler.
+
+Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+Tested-by: Michael Niewöhner <linux@mniewoehner.de>
+Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
+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_tis_core.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/char/tpm/tpm_tis_core.c
++++ b/drivers/char/tpm/tpm_tis_core.c
+@@ -772,7 +772,9 @@ static irqreturn_t tis_int_handler(int d
+               wake_up_interruptible(&priv->int_queue);
+       /* Clear interrupts handled with TPM_EOI */
++      tpm_tis_request_locality(chip, 0);
+       rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt);
++      tpm_tis_relinquish_locality(chip, 0);
+       if (rc < 0)
+               return IRQ_NONE;
diff --git a/queue-6.1/tpm_crb-add-support-for-crb-devices-based-on-pluton.patch b/queue-6.1/tpm_crb-add-support-for-crb-devices-based-on-pluton.patch
new file mode 100644 (file)
index 0000000..629f32b
--- /dev/null
@@ -0,0 +1,244 @@
+From 4d2732882703791ea4b670df433f88fc4b40a5cb Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@srcf.ucam.org>
+Date: Sat, 31 Dec 2022 01:14:32 -0800
+Subject: tpm_crb: Add support for CRB devices based on Pluton
+
+From: Matthew Garrett <mjg59@srcf.ucam.org>
+
+commit 4d2732882703791ea4b670df433f88fc4b40a5cb upstream.
+
+Pluton is an integrated security processor present in some recent Ryzen
+parts. If it's enabled, it presents two devices - an MSFT0101 ACPI device
+that's broadly an implementation of a Command Response Buffer TPM2, and an
+MSFT0200 ACPI device whose functionality I haven't examined in detail yet.
+This patch only attempts to add support for the TPM device.
+
+There's a few things that need to be handled here. The first is that the
+TPM2 ACPI table uses a previously undefined start method identifier. The
+table format appears to include 16 bytes of startup data, which corresponds
+to one 64-bit address for a start message and one 64-bit address for a
+completion response. The second is that the ACPI tables on the Thinkpad Z13
+I'm testing this on don't define any memory windows in _CRS (or, more
+accurately, there are two empty memory windows). This check doesn't seem
+strictly necessary, so I've skipped that.
+
+Finally, it seems like chip needs to be explicitly asked to transition into
+ready status on every command. Failing to do this means that if two
+commands are sent in succession without an idle/ready transition in
+between, everything will appear to work fine but the response is simply the
+original command. I'm working without any docs here, so I'm not sure if
+this is actually the required behaviour or if I'm missing something
+somewhere else, but doing this results in the chip working reliably.
+
+Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Matthew Garrett <mjg59@srcf.ucam.org>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Cc: "Limonciello, Mario" <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/char/tpm/tpm_crb.c |  100 ++++++++++++++++++++++++++++++++++++++++-----
+ include/acpi/actbl3.h      |    1 
+ 2 files changed, 91 insertions(+), 10 deletions(-)
+
+--- a/drivers/char/tpm/tpm_crb.c
++++ b/drivers/char/tpm/tpm_crb.c
+@@ -98,6 +98,8 @@ struct crb_priv {
+       u8 __iomem *rsp;
+       u32 cmd_size;
+       u32 smc_func_id;
++      u32 __iomem *pluton_start_addr;
++      u32 __iomem *pluton_reply_addr;
+ };
+ struct tpm2_crb_smc {
+@@ -108,6 +110,11 @@ struct tpm2_crb_smc {
+       u32 smc_func_id;
+ };
++struct tpm2_crb_pluton {
++      u64 start_addr;
++      u64 reply_addr;
++};
++
+ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
+                               unsigned long timeout)
+ {
+@@ -127,6 +134,25 @@ static bool crb_wait_for_reg_32(u32 __io
+       return ((ioread32(reg) & mask) == value);
+ }
++static int crb_try_pluton_doorbell(struct crb_priv *priv, bool wait_for_complete)
++{
++      if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON)
++              return 0;
++
++      if (!crb_wait_for_reg_32(priv->pluton_reply_addr, ~0, 1, TPM2_TIMEOUT_C))
++              return -ETIME;
++
++      iowrite32(1, priv->pluton_start_addr);
++      if (wait_for_complete == false)
++              return 0;
++
++      if (!crb_wait_for_reg_32(priv->pluton_start_addr,
++                               0xffffffff, 0, 200))
++              return -ETIME;
++
++      return 0;
++}
++
+ /**
+  * __crb_go_idle - request tpm crb device to go the idle state
+  *
+@@ -145,6 +171,8 @@ static bool crb_wait_for_reg_32(u32 __io
+  */
+ static int __crb_go_idle(struct device *dev, struct crb_priv *priv)
+ {
++      int rc;
++
+       if ((priv->sm == ACPI_TPM2_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
+@@ -152,6 +180,10 @@ static int __crb_go_idle(struct device *
+       iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req);
++      rc = crb_try_pluton_doorbell(priv, true);
++      if (rc)
++              return rc;
++
+       if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req,
+                                CRB_CTRL_REQ_GO_IDLE/* mask */,
+                                0, /* value */
+@@ -188,12 +220,19 @@ static int crb_go_idle(struct tpm_chip *
+  */
+ static int __crb_cmd_ready(struct device *dev, struct crb_priv *priv)
+ {
++      int rc;
++
+       if ((priv->sm == ACPI_TPM2_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
+               return 0;
+       iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req);
++
++      rc = crb_try_pluton_doorbell(priv, true);
++      if (rc)
++              return rc;
++
+       if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req,
+                                CRB_CTRL_REQ_CMD_READY /* mask */,
+                                0, /* value */
+@@ -371,6 +410,10 @@ static int crb_send(struct tpm_chip *chi
+               return -E2BIG;
+       }
++      /* Seems to be necessary for every command */
++      if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON)
++              __crb_cmd_ready(&chip->dev, priv);
++
+       memcpy_toio(priv->cmd, buf, len);
+       /* Make sure that cmd is populated before issuing start. */
+@@ -394,7 +437,10 @@ static int crb_send(struct tpm_chip *chi
+               rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id);
+       }
+-      return rc;
++      if (rc)
++              return rc;
++
++      return crb_try_pluton_doorbell(priv, false);
+ }
+ static void crb_cancel(struct tpm_chip *chip)
+@@ -524,15 +570,18 @@ static int crb_map_io(struct acpi_device
+               return ret;
+       acpi_dev_free_resource_list(&acpi_resource_list);
+-      if (resource_type(iores_array) != IORESOURCE_MEM) {
+-              dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n");
+-              return -EINVAL;
+-      } else if (resource_type(iores_array + TPM_CRB_MAX_RESOURCES) ==
+-              IORESOURCE_MEM) {
+-              dev_warn(dev, "TPM2 ACPI table defines too many memory resources\n");
+-              memset(iores_array + TPM_CRB_MAX_RESOURCES,
+-                     0, sizeof(*iores_array));
+-              iores_array[TPM_CRB_MAX_RESOURCES].flags = 0;
++      /* Pluton doesn't appear to define ACPI memory regions */
++      if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) {
++              if (resource_type(iores_array) != IORESOURCE_MEM) {
++                      dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n");
++                      return -EINVAL;
++              } else if (resource_type(iores_array + TPM_CRB_MAX_RESOURCES) ==
++                         IORESOURCE_MEM) {
++                      dev_warn(dev, "TPM2 ACPI table defines too many memory resources\n");
++                      memset(iores_array + TPM_CRB_MAX_RESOURCES,
++                             0, sizeof(*iores_array));
++                      iores_array[TPM_CRB_MAX_RESOURCES].flags = 0;
++              }
+       }
+       iores = NULL;
+@@ -656,6 +705,22 @@ out_relinquish_locality:
+       return ret;
+ }
++static int crb_map_pluton(struct device *dev, struct crb_priv *priv,
++             struct acpi_table_tpm2 *buf, struct tpm2_crb_pluton *crb_pluton)
++{
++      priv->pluton_start_addr = crb_map_res(dev, NULL, NULL,
++                                            crb_pluton->start_addr, 4);
++      if (IS_ERR(priv->pluton_start_addr))
++              return PTR_ERR(priv->pluton_start_addr);
++
++      priv->pluton_reply_addr = crb_map_res(dev, NULL, NULL,
++                                            crb_pluton->reply_addr, 4);
++      if (IS_ERR(priv->pluton_reply_addr))
++              return PTR_ERR(priv->pluton_reply_addr);
++
++      return 0;
++}
++
+ static int crb_acpi_add(struct acpi_device *device)
+ {
+       struct acpi_table_tpm2 *buf;
+@@ -663,6 +728,7 @@ static int crb_acpi_add(struct acpi_devi
+       struct tpm_chip *chip;
+       struct device *dev = &device->dev;
+       struct tpm2_crb_smc *crb_smc;
++      struct tpm2_crb_pluton *crb_pluton;
+       acpi_status status;
+       u32 sm;
+       int rc;
+@@ -700,6 +766,20 @@ static int crb_acpi_add(struct acpi_devi
+               priv->smc_func_id = crb_smc->smc_func_id;
+       }
++      if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) {
++              if (buf->header.length < (sizeof(*buf) + sizeof(*crb_pluton))) {
++                      dev_err(dev,
++                              FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n",
++                              buf->header.length,
++                              ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON);
++                      return -EINVAL;
++              }
++              crb_pluton = ACPI_ADD_PTR(struct tpm2_crb_pluton, buf, sizeof(*buf));
++              rc = crb_map_pluton(dev, priv, buf, crb_pluton);
++              if (rc)
++                      return rc;
++      }
++
+       priv->sm = sm;
+       priv->hid = acpi_device_hid(device);
+--- a/include/acpi/actbl3.h
++++ b/include/acpi/actbl3.h
+@@ -443,6 +443,7 @@ struct acpi_tpm2_phy {
+ #define ACPI_TPM2_RESERVED10                        10
+ #define ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC       11        /* V1.2 Rev 8 */
+ #define ACPI_TPM2_RESERVED                          12
++#define ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON        13
+ /* Optional trailer appears after any start_method subtables */