[PATCH v2 3/3] iommu/vt-d: Sanity check uapi argsz filled by users

From: Jacob Pan
Date: Thu Jun 11 2020 - 00:06:02 EST


IOMMU UAPI data has an argsz field which is filled by user. As the data
structures expands, argsz may change. As the UAPI data are shared among
different architectures, extensions of UAPI data could be a result of
one architecture which has no impact on another. Therefore, these argsz
santity checks are performed in the model specific IOMMU drivers. This
patch adds sanity checks in the VT-d to ensure argsz passed by userspace
matches feature flags and other contents.

Signed-off-by: Jacob Pan <jacob.jun.pan@xxxxxxxxxxxxxxx>
---
drivers/iommu/intel-iommu.c | 16 ++++++++++++++++
drivers/iommu/intel-svm.c | 12 ++++++++++++
2 files changed, 28 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 27ebf4b9faef..c98b5109684b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -5365,6 +5365,7 @@ intel_iommu_sva_invalidate(struct iommu_domain *domain, struct device *dev,
struct device_domain_info *info;
struct intel_iommu *iommu;
unsigned long flags;
+ unsigned long minsz;
int cache_type;
u8 bus, devfn;
u16 did, sid;
@@ -5385,6 +5386,21 @@ intel_iommu_sva_invalidate(struct iommu_domain *domain, struct device *dev,
if (!(dmar_domain->flags & DOMAIN_FLAG_NESTING_MODE))
return -EINVAL;

+ minsz = offsetofend(struct iommu_cache_invalidate_info, padding);
+ if (inv_info->argsz < minsz)
+ return -EINVAL;
+
+ /* Sanity check user filled invalidation dat sizes */
+ if (inv_info->granularity == IOMMU_INV_GRANU_ADDR &&
+ inv_info->argsz != offsetofend(struct iommu_cache_invalidate_info,
+ addr_info))
+ return -EINVAL;
+
+ if (inv_info->granularity == IOMMU_INV_GRANU_PASID &&
+ inv_info->argsz != offsetofend(struct iommu_cache_invalidate_info,
+ pasid_info))
+ return -EINVAL;
+
spin_lock_irqsave(&device_domain_lock, flags);
spin_lock(&iommu->lock);
info = get_domain_info(dev);
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index 35b43fe819ed..64dc2c66dfff 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -235,15 +235,27 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
struct dmar_domain *dmar_domain;
struct intel_svm_dev *sdev;
struct intel_svm *svm;
+ unsigned long minsz;
int ret = 0;

if (WARN_ON(!iommu) || !data)
return -EINVAL;

+ /*
+ * We mandate that no size change in IOMMU UAPI data before the
+ * variable size union at the end.
+ */
+ minsz = offsetofend(struct iommu_gpasid_bind_data, padding);
+ if (data->argsz < minsz)
+ return -EINVAL;
+
if (data->version != IOMMU_GPASID_BIND_VERSION_1 ||
data->format != IOMMU_PASID_FORMAT_INTEL_VTD)
return -EINVAL;

+ if (data->argsz != offsetofend(struct iommu_gpasid_bind_data, vtd))
+ return -EINVAL;
+
if (!dev_is_pci(dev))
return -ENOTSUPP;

--
2.7.4