| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Will Deacon <will@kernel.org> |
| Date: Fri, 8 Nov 2019 12:56:09 +0000 |
| Subject: FROMLIST: drivers/iommu: Take a ref to the IOMMU driver prior to |
| ->add_device() |
| |
| To avoid accidental removal of an active IOMMU driver module, take a |
| reference to the driver module in 'iommu_probe_device()' immediately |
| prior to invoking the '->add_device()' callback and hold it until the |
| after the device has been removed by '->remove_device()'. |
| |
| Suggested-by: Joerg Roedel <joro@8bytes.org> |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Bug: 140290589 |
| Link: https://lore.kernel.org/lkml/20191121114918.2293-5-will@kernel.org/ |
| Signed-off-by: Will Deacon <willdeacon@google.com> |
| Change-Id: I8f6a8aad8c41faa51df9c3a440c8b80c74e3ce8a |
| --- |
| drivers/iommu/iommu.c | 19 +++++++++++++++++-- |
| include/linux/iommu.h | 2 ++ |
| 2 files changed, 19 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c |
| index bbf3dc2eb5c9..9f463179083a 100644 |
| --- a/drivers/iommu/iommu.c |
| +++ b/drivers/iommu/iommu.c |
| @@ -22,6 +22,7 @@ |
| #include <linux/bitops.h> |
| #include <linux/property.h> |
| #include <linux/fsl/mc.h> |
| +#include <linux/module.h> |
| #include <trace/events/iommu.h> |
| |
| static struct kset *iommu_group_kset; |
| @@ -185,10 +186,21 @@ int iommu_probe_device(struct device *dev) |
| if (!iommu_get_dev_param(dev)) |
| return -ENOMEM; |
| |
| + if (!try_module_get(ops->owner)) { |
| + ret = -EINVAL; |
| + goto err_free_dev_param; |
| + } |
| + |
| ret = ops->add_device(dev); |
| if (ret) |
| - iommu_free_dev_param(dev); |
| + goto err_module_put; |
| + |
| + return 0; |
| |
| +err_module_put: |
| + module_put(ops->owner); |
| +err_free_dev_param: |
| + iommu_free_dev_param(dev); |
| return ret; |
| } |
| |
| @@ -199,7 +211,10 @@ void iommu_release_device(struct device *dev) |
| if (dev->iommu_group) |
| ops->remove_device(dev); |
| |
| - iommu_free_dev_param(dev); |
| + if (dev->iommu_param) { |
| + module_put(ops->owner); |
| + iommu_free_dev_param(dev); |
| + } |
| } |
| |
| static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, |
| diff --git a/include/linux/iommu.h b/include/linux/iommu.h |
| index 29bac5345563..d9dab5a3e912 100644 |
| --- a/include/linux/iommu.h |
| +++ b/include/linux/iommu.h |
| @@ -245,6 +245,7 @@ struct iommu_iotlb_gather { |
| * @sva_get_pasid: Get PASID associated to a SVA handle |
| * @page_response: handle page request response |
| * @pgsize_bitmap: bitmap of all possible supported page sizes |
| + * @owner: Driver module providing these ops |
| */ |
| struct iommu_ops { |
| bool (*capable)(enum iommu_cap); |
| @@ -308,6 +309,7 @@ struct iommu_ops { |
| struct iommu_page_response *msg); |
| |
| unsigned long pgsize_bitmap; |
| + struct module *owner; |
| }; |
| |
| /** |