]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.2-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Mar 2023 18:54:40 +0000 (19:54 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Mar 2023 18:54:40 +0000 (19:54 +0100)
added patches:
crypto-qat-fix-out-of-bounds-read.patch
irqdomain-drop-bogus-fwspec-mapping-error-handling.patch
irqdomain-fix-association-race.patch
irqdomain-fix-disassociation-race.patch
irqdomain-fix-domain-registration-race.patch
irqdomain-fix-mapping-creation-race.patch
irqdomain-look-for-existing-mapping-only-once.patch
irqdomain-refactor-__irq_domain_alloc_irqs.patch

queue-6.2/crypto-qat-fix-out-of-bounds-read.patch [new file with mode: 0644]
queue-6.2/irqdomain-drop-bogus-fwspec-mapping-error-handling.patch [new file with mode: 0644]
queue-6.2/irqdomain-fix-association-race.patch [new file with mode: 0644]
queue-6.2/irqdomain-fix-disassociation-race.patch [new file with mode: 0644]
queue-6.2/irqdomain-fix-domain-registration-race.patch [new file with mode: 0644]
queue-6.2/irqdomain-fix-mapping-creation-race.patch [new file with mode: 0644]
queue-6.2/irqdomain-look-for-existing-mapping-only-once.patch [new file with mode: 0644]
queue-6.2/irqdomain-refactor-__irq_domain_alloc_irqs.patch [new file with mode: 0644]
queue-6.2/series

diff --git a/queue-6.2/crypto-qat-fix-out-of-bounds-read.patch b/queue-6.2/crypto-qat-fix-out-of-bounds-read.patch
new file mode 100644 (file)
index 0000000..cf12785
--- /dev/null
@@ -0,0 +1,61 @@
+From f6044cc3030e139f60c281386f28bda6e3049d66 Mon Sep 17 00:00:00 2001
+From: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
+Date: Wed, 1 Feb 2023 15:59:44 +0000
+Subject: crypto: qat - fix out-of-bounds read
+
+From: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
+
+commit f6044cc3030e139f60c281386f28bda6e3049d66 upstream.
+
+When preparing an AER-CTR request, the driver copies the key provided by
+the user into a data structure that is accessible by the firmware.
+If the target device is QAT GEN4, the key size is rounded up by 16 since
+a rounded up size is expected by the device.
+If the key size is rounded up before the copy, the size used for copying
+the key might be bigger than the size of the region containing the key,
+causing an out-of-bounds read.
+
+Fix by doing the copy first and then update the keylen.
+
+This is to fix the following warning reported by KASAN:
+
+       [  138.150574] BUG: KASAN: global-out-of-bounds in qat_alg_skcipher_init_com.isra.0+0x197/0x250 [intel_qat]
+       [  138.150641] Read of size 32 at addr ffffffff88c402c0 by task cryptomgr_test/2340
+
+       [  138.150651] CPU: 15 PID: 2340 Comm: cryptomgr_test Not tainted 6.2.0-rc1+ #45
+       [  138.150659] Hardware name: Intel Corporation ArcherCity/ArcherCity, BIOS EGSDCRB1.86B.0087.D13.2208261706 08/26/2022
+       [  138.150663] Call Trace:
+       [  138.150668]  <TASK>
+       [  138.150922]  kasan_check_range+0x13a/0x1c0
+       [  138.150931]  memcpy+0x1f/0x60
+       [  138.150940]  qat_alg_skcipher_init_com.isra.0+0x197/0x250 [intel_qat]
+       [  138.151006]  qat_alg_skcipher_init_sessions+0xc1/0x240 [intel_qat]
+       [  138.151073]  crypto_skcipher_setkey+0x82/0x160
+       [  138.151085]  ? prepare_keybuf+0xa2/0xd0
+       [  138.151095]  test_skcipher_vec_cfg+0x2b8/0x800
+
+Fixes: 67916c951689 ("crypto: qat - add AES-CTR support for QAT GEN4 devices")
+Cc: <stable@vger.kernel.org>
+Reported-by: Vladis Dronov <vdronov@redhat.com>
+Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
+Reviewed-by: Fiona Trahe <fiona.trahe@intel.com>
+Reviewed-by: Vladis Dronov <vdronov@redhat.com>
+Tested-by: Vladis Dronov <vdronov@redhat.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/qat/qat_common/qat_algs.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/crypto/qat/qat_common/qat_algs.c
++++ b/drivers/crypto/qat/qat_common/qat_algs.c
+@@ -435,8 +435,8 @@ static void qat_alg_skcipher_init_com(st
+       } else if (aes_v2_capable && mode == ICP_QAT_HW_CIPHER_CTR_MODE) {
+               ICP_QAT_FW_LA_SLICE_TYPE_SET(header->serv_specif_flags,
+                                            ICP_QAT_FW_LA_USE_UCS_SLICE_TYPE);
+-              keylen = round_up(keylen, 16);
+               memcpy(cd->ucs_aes.key, key, keylen);
++              keylen = round_up(keylen, 16);
+       } else {
+               memcpy(cd->aes.key, key, keylen);
+       }
diff --git a/queue-6.2/irqdomain-drop-bogus-fwspec-mapping-error-handling.patch b/queue-6.2/irqdomain-drop-bogus-fwspec-mapping-error-handling.patch
new file mode 100644 (file)
index 0000000..a563247
--- /dev/null
@@ -0,0 +1,46 @@
+From e3b7ab025e931accdc2c12acf9b75c6197f1c062 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 13 Feb 2023 11:42:45 +0100
+Subject: irqdomain: Drop bogus fwspec-mapping error handling
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit e3b7ab025e931accdc2c12acf9b75c6197f1c062 upstream.
+
+In case a newly allocated IRQ ever ends up not having any associated
+struct irq_data it would not even be possible to dispose the mapping.
+
+Replace the bogus disposal with a WARN_ON().
+
+This will also be used to fix a shared-interrupt mapping race, hence the
+CC-stable tag.
+
+Fixes: 1e2a7d78499e ("irqdomain: Don't set type when mapping an IRQ")
+Cc: stable@vger.kernel.org      # 4.8
+Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Tested-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230213104302.17307-4-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/irq/irqdomain.c |    7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -853,13 +853,8 @@ unsigned int irq_create_fwspec_mapping(s
+       }
+       irq_data = irq_get_irq_data(virq);
+-      if (!irq_data) {
+-              if (irq_domain_is_hierarchy(domain))
+-                      irq_domain_free_irqs(virq, 1);
+-              else
+-                      irq_dispose_mapping(virq);
++      if (WARN_ON(!irq_data))
+               return 0;
+-      }
+       /* Store trigger type */
+       irqd_set_trigger_type(irq_data, type);
diff --git a/queue-6.2/irqdomain-fix-association-race.patch b/queue-6.2/irqdomain-fix-association-race.patch
new file mode 100644 (file)
index 0000000..8520974
--- /dev/null
@@ -0,0 +1,83 @@
+From b06730a571a9ff1ba5bd6b20bf9e50e5a12f1ec6 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 13 Feb 2023 11:42:43 +0100
+Subject: irqdomain: Fix association race
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit b06730a571a9ff1ba5bd6b20bf9e50e5a12f1ec6 upstream.
+
+The sanity check for an already mapped virq is done outside of the
+irq_domain_mutex-protected section which means that an (unlikely) racing
+association may not be detected.
+
+Fix this by factoring out the association implementation, which will
+also be used in a follow-on change to fix a shared-interrupt mapping
+race.
+
+Fixes: ddaf144c61da ("irqdomain: Refactor irq_domain_associate_many()")
+Cc: stable@vger.kernel.org      # 3.11
+Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Tested-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230213104302.17307-2-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/irq/irqdomain.c |   19 ++++++++++++++-----
+ 1 file changed, 14 insertions(+), 5 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -559,8 +559,8 @@ static void irq_domain_disassociate(stru
+       irq_domain_clear_mapping(domain, hwirq);
+ }
+-int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
+-                       irq_hw_number_t hwirq)
++static int irq_domain_associate_locked(struct irq_domain *domain, unsigned int virq,
++                                     irq_hw_number_t hwirq)
+ {
+       struct irq_data *irq_data = irq_get_irq_data(virq);
+       int ret;
+@@ -573,7 +573,6 @@ int irq_domain_associate(struct irq_doma
+       if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
+               return -EINVAL;
+-      mutex_lock(&irq_domain_mutex);
+       irq_data->hwirq = hwirq;
+       irq_data->domain = domain;
+       if (domain->ops->map) {
+@@ -590,7 +589,6 @@ int irq_domain_associate(struct irq_doma
+                       }
+                       irq_data->domain = NULL;
+                       irq_data->hwirq = 0;
+-                      mutex_unlock(&irq_domain_mutex);
+                       return ret;
+               }
+@@ -601,12 +599,23 @@ int irq_domain_associate(struct irq_doma
+       domain->mapcount++;
+       irq_domain_set_mapping(domain, hwirq, irq_data);
+-      mutex_unlock(&irq_domain_mutex);
+       irq_clear_status_flags(virq, IRQ_NOREQUEST);
+       return 0;
+ }
++
++int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
++                       irq_hw_number_t hwirq)
++{
++      int ret;
++
++      mutex_lock(&irq_domain_mutex);
++      ret = irq_domain_associate_locked(domain, virq, hwirq);
++      mutex_unlock(&irq_domain_mutex);
++
++      return ret;
++}
+ EXPORT_SYMBOL_GPL(irq_domain_associate);
+ void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
diff --git a/queue-6.2/irqdomain-fix-disassociation-race.patch b/queue-6.2/irqdomain-fix-disassociation-race.patch
new file mode 100644 (file)
index 0000000..b0eaf84
--- /dev/null
@@ -0,0 +1,51 @@
+From 3f883c38f5628f46b30bccf090faec054088e262 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 13 Feb 2023 11:42:44 +0100
+Subject: irqdomain: Fix disassociation race
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit 3f883c38f5628f46b30bccf090faec054088e262 upstream.
+
+The global irq_domain_mutex is held when mapping interrupts from
+non-hierarchical domains but currently not when disposing them.
+
+This specifically means that updates of the domain mapcount is racy
+(currently only used for statistics in debugfs).
+
+Make sure to hold the global irq_domain_mutex also when disposing
+mappings from non-hierarchical domains.
+
+Fixes: 9dc6be3d4193 ("genirq/irqdomain: Add map counter")
+Cc: stable@vger.kernel.org      # 4.13
+Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Tested-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230213104302.17307-3-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/irq/irqdomain.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -538,6 +538,9 @@ static void irq_domain_disassociate(stru
+               return;
+       hwirq = irq_data->hwirq;
++
++      mutex_lock(&irq_domain_mutex);
++
+       irq_set_status_flags(irq, IRQ_NOREQUEST);
+       /* remove chip and handler */
+@@ -557,6 +560,8 @@ static void irq_domain_disassociate(stru
+       /* Clear reverse map for this hwirq */
+       irq_domain_clear_mapping(domain, hwirq);
++
++      mutex_unlock(&irq_domain_mutex);
+ }
+ static int irq_domain_associate_locked(struct irq_domain *domain, unsigned int virq,
diff --git a/queue-6.2/irqdomain-fix-domain-registration-race.patch b/queue-6.2/irqdomain-fix-domain-registration-race.patch
new file mode 100644 (file)
index 0000000..9ce7f94
--- /dev/null
@@ -0,0 +1,129 @@
+From 8932c32c3053accd50702b36e944ac2016cd103c Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <maz@kernel.org>
+Date: Mon, 13 Feb 2023 11:42:49 +0100
+Subject: irqdomain: Fix domain registration race
+
+From: Marc Zyngier <maz@kernel.org>
+
+commit 8932c32c3053accd50702b36e944ac2016cd103c upstream.
+
+Hierarchical domains created using irq_domain_create_hierarchy() are
+currently added to the domain list before having been fully initialised.
+
+This specifically means that a racing allocation request might fail to
+allocate irq data for the inner domains of a hierarchy in case the
+parent domain pointer has not yet been set up.
+
+Note that this is not really any issue for irqchip drivers that are
+registered early (e.g. via IRQCHIP_DECLARE() or IRQCHIP_ACPI_DECLARE())
+but could potentially cause trouble with drivers that are registered
+later (e.g. modular drivers using IRQCHIP_PLATFORM_DRIVER_BEGIN(),
+gpiochip drivers, etc.).
+
+Fixes: afb7da83b9f4 ("irqdomain: Introduce helper function irq_domain_add_hierarchy()")
+Cc: stable@vger.kernel.org      # 3.19
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+[ johan: add commit message ]
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230213104302.17307-8-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/irq/irqdomain.c |   62 +++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 43 insertions(+), 19 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -126,23 +126,12 @@ void irq_domain_free_fwnode(struct fwnod
+ }
+ EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
+-/**
+- * __irq_domain_add() - Allocate a new irq_domain data structure
+- * @fwnode: firmware node for the interrupt controller
+- * @size: Size of linear map; 0 for radix mapping only
+- * @hwirq_max: Maximum number of interrupts supported by controller
+- * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
+- *              direct mapping
+- * @ops: domain callbacks
+- * @host_data: Controller private data pointer
+- *
+- * Allocates and initializes an irq_domain structure.
+- * Returns pointer to IRQ domain, or NULL on failure.
+- */
+-struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
+-                                  irq_hw_number_t hwirq_max, int direct_max,
+-                                  const struct irq_domain_ops *ops,
+-                                  void *host_data)
++static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode,
++                                            unsigned int size,
++                                            irq_hw_number_t hwirq_max,
++                                            int direct_max,
++                                            const struct irq_domain_ops *ops,
++                                            void *host_data)
+ {
+       struct irqchip_fwid *fwid;
+       struct irq_domain *domain;
+@@ -230,12 +219,44 @@ struct irq_domain *__irq_domain_add(stru
+       irq_domain_check_hierarchy(domain);
++      return domain;
++}
++
++static void __irq_domain_publish(struct irq_domain *domain)
++{
+       mutex_lock(&irq_domain_mutex);
+       debugfs_add_domain_dir(domain);
+       list_add(&domain->link, &irq_domain_list);
+       mutex_unlock(&irq_domain_mutex);
+       pr_debug("Added domain %s\n", domain->name);
++}
++
++/**
++ * __irq_domain_add() - Allocate a new irq_domain data structure
++ * @fwnode: firmware node for the interrupt controller
++ * @size: Size of linear map; 0 for radix mapping only
++ * @hwirq_max: Maximum number of interrupts supported by controller
++ * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
++ *              direct mapping
++ * @ops: domain callbacks
++ * @host_data: Controller private data pointer
++ *
++ * Allocates and initializes an irq_domain structure.
++ * Returns pointer to IRQ domain, or NULL on failure.
++ */
++struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
++                                  irq_hw_number_t hwirq_max, int direct_max,
++                                  const struct irq_domain_ops *ops,
++                                  void *host_data)
++{
++      struct irq_domain *domain;
++
++      domain = __irq_domain_create(fwnode, size, hwirq_max, direct_max,
++                                   ops, host_data);
++      if (domain)
++              __irq_domain_publish(domain);
++
+       return domain;
+ }
+ EXPORT_SYMBOL_GPL(__irq_domain_add);
+@@ -1138,12 +1159,15 @@ struct irq_domain *irq_domain_create_hie
+       struct irq_domain *domain;
+       if (size)
+-              domain = irq_domain_create_linear(fwnode, size, ops, host_data);
++              domain = __irq_domain_create(fwnode, size, size, 0, ops, host_data);
+       else
+-              domain = irq_domain_create_tree(fwnode, ops, host_data);
++              domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data);
++
+       if (domain) {
+               domain->parent = parent;
+               domain->flags |= flags;
++
++              __irq_domain_publish(domain);
+       }
+       return domain;
diff --git a/queue-6.2/irqdomain-fix-mapping-creation-race.patch b/queue-6.2/irqdomain-fix-mapping-creation-race.patch
new file mode 100644 (file)
index 0000000..de47ab2
--- /dev/null
@@ -0,0 +1,179 @@
+From 601363cc08da25747feb87c55573dd54de91d66a Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 13 Feb 2023 11:42:48 +0100
+Subject: irqdomain: Fix mapping-creation race
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit 601363cc08da25747feb87c55573dd54de91d66a upstream.
+
+Parallel probing of devices that share interrupts (e.g. when a driver
+uses asynchronous probing) can currently result in two mappings for the
+same hardware interrupt to be created due to missing serialisation.
+
+Make sure to hold the irq_domain_mutex when creating mappings so that
+looking for an existing mapping before creating a new one is done
+atomically.
+
+Fixes: 765230b5f084 ("driver-core: add asynchronous probing support for drivers")
+Fixes: b62b2cf5759b ("irqdomain: Fix handling of type settings for existing mappings")
+Link: https://lore.kernel.org/r/YuJXMHoT4ijUxnRb@hovoldconsulting.com
+Cc: stable@vger.kernel.org      # 4.8
+Cc: Dmitry Torokhov <dtor@chromium.org>
+Cc: Jon Hunter <jonathanh@nvidia.com>
+Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Tested-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230213104302.17307-7-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/irq/irqdomain.c |   64 +++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 46 insertions(+), 18 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -25,6 +25,9 @@ static DEFINE_MUTEX(irq_domain_mutex);
+ static struct irq_domain *irq_default_domain;
++static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base,
++                                      unsigned int nr_irqs, int node, void *arg,
++                                      bool realloc, const struct irq_affinity_desc *affinity);
+ static void irq_domain_check_hierarchy(struct irq_domain *domain);
+ struct irqchip_fwid {
+@@ -682,9 +685,9 @@ unsigned int irq_create_direct_mapping(s
+ EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
+ #endif
+-static unsigned int __irq_create_mapping_affinity(struct irq_domain *domain,
+-                                                irq_hw_number_t hwirq,
+-                                                const struct irq_affinity_desc *affinity)
++static unsigned int irq_create_mapping_affinity_locked(struct irq_domain *domain,
++                                                     irq_hw_number_t hwirq,
++                                                     const struct irq_affinity_desc *affinity)
+ {
+       struct device_node *of_node = irq_domain_get_of_node(domain);
+       int virq;
+@@ -699,7 +702,7 @@ static unsigned int __irq_create_mapping
+               return 0;
+       }
+-      if (irq_domain_associate(domain, virq, hwirq)) {
++      if (irq_domain_associate_locked(domain, virq, hwirq)) {
+               irq_free_desc(virq);
+               return 0;
+       }
+@@ -735,14 +738,20 @@ unsigned int irq_create_mapping_affinity
+               return 0;
+       }
++      mutex_lock(&irq_domain_mutex);
++
+       /* Check if mapping already exists */
+       virq = irq_find_mapping(domain, hwirq);
+       if (virq) {
+               pr_debug("existing mapping on virq %d\n", virq);
+-              return virq;
++              goto out;
+       }
+-      return __irq_create_mapping_affinity(domain, hwirq, affinity);
++      virq = irq_create_mapping_affinity_locked(domain, hwirq, affinity);
++out:
++      mutex_unlock(&irq_domain_mutex);
++
++      return virq;
+ }
+ EXPORT_SYMBOL_GPL(irq_create_mapping_affinity);
+@@ -809,6 +818,8 @@ unsigned int irq_create_fwspec_mapping(s
+       if (WARN_ON(type & ~IRQ_TYPE_SENSE_MASK))
+               type &= IRQ_TYPE_SENSE_MASK;
++      mutex_lock(&irq_domain_mutex);
++
+       /*
+        * If we've already configured this interrupt,
+        * don't do it again, or hell will break loose.
+@@ -821,7 +832,7 @@ unsigned int irq_create_fwspec_mapping(s
+                * interrupt number.
+                */
+               if (type == IRQ_TYPE_NONE || type == irq_get_trigger_type(virq))
+-                      return virq;
++                      goto out;
+               /*
+                * If the trigger type has not been set yet, then set
+@@ -829,35 +840,45 @@ unsigned int irq_create_fwspec_mapping(s
+                */
+               if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) {
+                       irq_data = irq_get_irq_data(virq);
+-                      if (!irq_data)
+-                              return 0;
++                      if (!irq_data) {
++                              virq = 0;
++                              goto out;
++                      }
+                       irqd_set_trigger_type(irq_data, type);
+-                      return virq;
++                      goto out;
+               }
+               pr_warn("type mismatch, failed to map hwirq-%lu for %s!\n",
+                       hwirq, of_node_full_name(to_of_node(fwspec->fwnode)));
+-              return 0;
++              virq = 0;
++              goto out;
+       }
+       if (irq_domain_is_hierarchy(domain)) {
+-              virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
+-              if (virq <= 0)
+-                      return 0;
++              virq = irq_domain_alloc_irqs_locked(domain, -1, 1, NUMA_NO_NODE,
++                                                  fwspec, false, NULL);
++              if (virq <= 0) {
++                      virq = 0;
++                      goto out;
++              }
+       } else {
+               /* Create mapping */
+-              virq = __irq_create_mapping_affinity(domain, hwirq, NULL);
++              virq = irq_create_mapping_affinity_locked(domain, hwirq, NULL);
+               if (!virq)
+-                      return virq;
++                      goto out;
+       }
+       irq_data = irq_get_irq_data(virq);
+-      if (WARN_ON(!irq_data))
+-              return 0;
++      if (WARN_ON(!irq_data)) {
++              virq = 0;
++              goto out;
++      }
+       /* Store trigger type */
+       irqd_set_trigger_type(irq_data, type);
++out:
++      mutex_unlock(&irq_domain_mutex);
+       return virq;
+ }
+@@ -1888,6 +1909,13 @@ void irq_domain_set_info(struct irq_doma
+       irq_set_handler_data(virq, handler_data);
+ }
++static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base,
++                                      unsigned int nr_irqs, int node, void *arg,
++                                      bool realloc, const struct irq_affinity_desc *affinity)
++{
++      return -EINVAL;
++}
++
+ static void irq_domain_check_hierarchy(struct irq_domain *domain)
+ {
+ }
diff --git a/queue-6.2/irqdomain-look-for-existing-mapping-only-once.patch b/queue-6.2/irqdomain-look-for-existing-mapping-only-once.patch
new file mode 100644 (file)
index 0000000..74cf8ba
--- /dev/null
@@ -0,0 +1,128 @@
+From 6e6f75c9c98d2d246d90411ff2b6f0cd271f4cba Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 13 Feb 2023 11:42:46 +0100
+Subject: irqdomain: Look for existing mapping only once
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit 6e6f75c9c98d2d246d90411ff2b6f0cd271f4cba upstream.
+
+Avoid looking for an existing mapping twice when creating a new mapping
+using irq_create_fwspec_mapping() by factoring out the actual allocation
+which is shared with irq_create_mapping_affinity().
+
+The new helper function will also be used to fix a shared-interrupt
+mapping race, hence the Fixes tag.
+
+Fixes: b62b2cf5759b ("irqdomain: Fix handling of type settings for existing mappings")
+Cc: stable@vger.kernel.org      # 4.8
+Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Tested-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230213104302.17307-5-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/irq/irqdomain.c |   60 ++++++++++++++++++++++++++-----------------------
+ 1 file changed, 33 insertions(+), 27 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -682,6 +682,34 @@ unsigned int irq_create_direct_mapping(s
+ EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
+ #endif
++static unsigned int __irq_create_mapping_affinity(struct irq_domain *domain,
++                                                irq_hw_number_t hwirq,
++                                                const struct irq_affinity_desc *affinity)
++{
++      struct device_node *of_node = irq_domain_get_of_node(domain);
++      int virq;
++
++      pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
++
++      /* Allocate a virtual interrupt number */
++      virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
++                                    affinity);
++      if (virq <= 0) {
++              pr_debug("-> virq allocation failed\n");
++              return 0;
++      }
++
++      if (irq_domain_associate(domain, virq, hwirq)) {
++              irq_free_desc(virq);
++              return 0;
++      }
++
++      pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
++              hwirq, of_node_full_name(of_node), virq);
++
++      return virq;
++}
++
+ /**
+  * irq_create_mapping_affinity() - Map a hardware interrupt into linux irq space
+  * @domain: domain owning this hardware interrupt or NULL for default domain
+@@ -694,14 +722,11 @@ EXPORT_SYMBOL_GPL(irq_create_direct_mapp
+  * on the number returned from that call.
+  */
+ unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
+-                                     irq_hw_number_t hwirq,
+-                                     const struct irq_affinity_desc *affinity)
++                                       irq_hw_number_t hwirq,
++                                       const struct irq_affinity_desc *affinity)
+ {
+-      struct device_node *of_node;
+       int virq;
+-      pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+-
+       /* Look for default domain if necessary */
+       if (domain == NULL)
+               domain = irq_default_domain;
+@@ -709,34 +734,15 @@ unsigned int irq_create_mapping_affinity
+               WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
+               return 0;
+       }
+-      pr_debug("-> using domain @%p\n", domain);
+-
+-      of_node = irq_domain_get_of_node(domain);
+       /* Check if mapping already exists */
+       virq = irq_find_mapping(domain, hwirq);
+       if (virq) {
+-              pr_debug("-> existing mapping on virq %d\n", virq);
++              pr_debug("existing mapping on virq %d\n", virq);
+               return virq;
+       }
+-      /* Allocate a virtual interrupt number */
+-      virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
+-                                    affinity);
+-      if (virq <= 0) {
+-              pr_debug("-> virq allocation failed\n");
+-              return 0;
+-      }
+-
+-      if (irq_domain_associate(domain, virq, hwirq)) {
+-              irq_free_desc(virq);
+-              return 0;
+-      }
+-
+-      pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
+-              hwirq, of_node_full_name(of_node), virq);
+-
+-      return virq;
++      return __irq_create_mapping_affinity(domain, hwirq, affinity);
+ }
+ EXPORT_SYMBOL_GPL(irq_create_mapping_affinity);
+@@ -841,7 +847,7 @@ unsigned int irq_create_fwspec_mapping(s
+                       return 0;
+       } else {
+               /* Create mapping */
+-              virq = irq_create_mapping(domain, hwirq);
++              virq = __irq_create_mapping_affinity(domain, hwirq, NULL);
+               if (!virq)
+                       return virq;
+       }
diff --git a/queue-6.2/irqdomain-refactor-__irq_domain_alloc_irqs.patch b/queue-6.2/irqdomain-refactor-__irq_domain_alloc_irqs.patch
new file mode 100644 (file)
index 0000000..dfea335
--- /dev/null
@@ -0,0 +1,150 @@
+From d55f7f4c58c07beb5050a834bf57ae2ede599c7e Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 13 Feb 2023 11:42:47 +0100
+Subject: irqdomain: Refactor __irq_domain_alloc_irqs()
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit d55f7f4c58c07beb5050a834bf57ae2ede599c7e upstream.
+
+Refactor __irq_domain_alloc_irqs() so that it can be called internally
+while holding the irq_domain_mutex.
+
+This will be used to fix a shared-interrupt mapping race, hence the
+Fixes tag.
+
+Fixes: b62b2cf5759b ("irqdomain: Fix handling of type settings for existing mappings")
+Cc: stable@vger.kernel.org      # 4.8
+Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Tested-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230213104302.17307-6-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/irq/irqdomain.c |   88 ++++++++++++++++++++++++++-----------------------
+ 1 file changed, 48 insertions(+), 40 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -1441,40 +1441,12 @@ int irq_domain_alloc_irqs_hierarchy(stru
+       return domain->ops->alloc(domain, irq_base, nr_irqs, arg);
+ }
+-/**
+- * __irq_domain_alloc_irqs - Allocate IRQs from domain
+- * @domain:   domain to allocate from
+- * @irq_base: allocate specified IRQ number if irq_base >= 0
+- * @nr_irqs:  number of IRQs to allocate
+- * @node:     NUMA node id for memory allocation
+- * @arg:      domain specific argument
+- * @realloc:  IRQ descriptors have already been allocated if true
+- * @affinity: Optional irq affinity mask for multiqueue devices
+- *
+- * Allocate IRQ numbers and initialized all data structures to support
+- * hierarchy IRQ domains.
+- * Parameter @realloc is mainly to support legacy IRQs.
+- * Returns error code or allocated IRQ number
+- *
+- * The whole process to setup an IRQ has been split into two steps.
+- * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ
+- * descriptor and required hardware resources. The second step,
+- * irq_domain_activate_irq(), is to program the hardware with preallocated
+- * resources. In this way, it's easier to rollback when failing to
+- * allocate resources.
+- */
+-int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
+-                          unsigned int nr_irqs, int node, void *arg,
+-                          bool realloc, const struct irq_affinity_desc *affinity)
++static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base,
++                                      unsigned int nr_irqs, int node, void *arg,
++                                      bool realloc, const struct irq_affinity_desc *affinity)
+ {
+       int i, ret, virq;
+-      if (domain == NULL) {
+-              domain = irq_default_domain;
+-              if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n"))
+-                      return -EINVAL;
+-      }
+-
+       if (realloc && irq_base >= 0) {
+               virq = irq_base;
+       } else {
+@@ -1493,24 +1465,18 @@ int __irq_domain_alloc_irqs(struct irq_d
+               goto out_free_desc;
+       }
+-      mutex_lock(&irq_domain_mutex);
+       ret = irq_domain_alloc_irqs_hierarchy(domain, virq, nr_irqs, arg);
+-      if (ret < 0) {
+-              mutex_unlock(&irq_domain_mutex);
++      if (ret < 0)
+               goto out_free_irq_data;
+-      }
+       for (i = 0; i < nr_irqs; i++) {
+               ret = irq_domain_trim_hierarchy(virq + i);
+-              if (ret) {
+-                      mutex_unlock(&irq_domain_mutex);
++              if (ret)
+                       goto out_free_irq_data;
+-              }
+       }
+-      
++
+       for (i = 0; i < nr_irqs; i++)
+               irq_domain_insert_irq(virq + i);
+-      mutex_unlock(&irq_domain_mutex);
+       return virq;
+@@ -1520,6 +1486,48 @@ out_free_desc:
+       irq_free_descs(virq, nr_irqs);
+       return ret;
+ }
++
++/**
++ * __irq_domain_alloc_irqs - Allocate IRQs from domain
++ * @domain:   domain to allocate from
++ * @irq_base: allocate specified IRQ number if irq_base >= 0
++ * @nr_irqs:  number of IRQs to allocate
++ * @node:     NUMA node id for memory allocation
++ * @arg:      domain specific argument
++ * @realloc:  IRQ descriptors have already been allocated if true
++ * @affinity: Optional irq affinity mask for multiqueue devices
++ *
++ * Allocate IRQ numbers and initialized all data structures to support
++ * hierarchy IRQ domains.
++ * Parameter @realloc is mainly to support legacy IRQs.
++ * Returns error code or allocated IRQ number
++ *
++ * The whole process to setup an IRQ has been split into two steps.
++ * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ
++ * descriptor and required hardware resources. The second step,
++ * irq_domain_activate_irq(), is to program the hardware with preallocated
++ * resources. In this way, it's easier to rollback when failing to
++ * allocate resources.
++ */
++int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
++                          unsigned int nr_irqs, int node, void *arg,
++                          bool realloc, const struct irq_affinity_desc *affinity)
++{
++      int ret;
++
++      if (domain == NULL) {
++              domain = irq_default_domain;
++              if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n"))
++                      return -EINVAL;
++      }
++
++      mutex_lock(&irq_domain_mutex);
++      ret = irq_domain_alloc_irqs_locked(domain, irq_base, nr_irqs, node, arg,
++                                         realloc, affinity);
++      mutex_unlock(&irq_domain_mutex);
++
++      return ret;
++}
+ EXPORT_SYMBOL_GPL(__irq_domain_alloc_irqs);
+ /* The irq_data was moved, fix the revmap to refer to the new location */
index 8ccdea9e10e88a3973f246e36da65100e64eac7b..629c7f212c51c378594872c8f1c414e37b582049 100644 (file)
@@ -878,3 +878,11 @@ selftests-drivers-fix-incorrect-kernel-headers-search-path.patch
 selftests-dmabuf-heaps-fix-incorrect-kernel-headers-search-path.patch
 selftests-vm-fix-incorrect-kernel-headers-search-path.patch
 selftests-seccomp-fix-incorrect-kernel-headers-search-path.patch
+irqdomain-fix-association-race.patch
+irqdomain-fix-disassociation-race.patch
+irqdomain-look-for-existing-mapping-only-once.patch
+irqdomain-drop-bogus-fwspec-mapping-error-handling.patch
+irqdomain-refactor-__irq_domain_alloc_irqs.patch
+irqdomain-fix-mapping-creation-race.patch
+irqdomain-fix-domain-registration-race.patch
+crypto-qat-fix-out-of-bounds-read.patch