Skip to content

Commit 2926a2a

Browse files
committed
iommu: Fix wrong freeing of iommu_device->dev
The struct iommu_device has a 'struct device' embedded into it, not as a pointer, but the whole struct. In the conversion of the iommu drivers to use struct iommu_device it was forgotten that the relase function for that struct device simply calls kfree() on the pointer. This frees memory that was never allocated and causes memory corruption. To fix this issue, use a pointer to struct device instead of embedding the whole struct. This needs some updates in the iommu sysfs code as well as the Intel VT-d and AMD IOMMU driver. Reported-by: Sebastian Ott <[email protected]> Fixes: 39ab955 ('iommu: Add sysfs bindings for struct iommu_device') Cc: [email protected] # >= v4.11 Signed-off-by: Joerg Roedel <[email protected]>
1 parent a7990c6 commit 2926a2a

File tree

4 files changed

+37
-15
lines changed

4 files changed

+37
-15
lines changed

drivers/iommu/amd_iommu_types.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,9 @@ struct amd_iommu {
574574

575575
static inline struct amd_iommu *dev_to_amd_iommu(struct device *dev)
576576
{
577-
return container_of(dev, struct amd_iommu, iommu.dev);
577+
struct iommu_device *iommu = dev_to_iommu_device(dev);
578+
579+
return container_of(iommu, struct amd_iommu, iommu);
578580
}
579581

580582
#define ACPIHID_UID_LEN 256

drivers/iommu/intel-iommu.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4736,7 +4736,9 @@ static void intel_disable_iommus(void)
47364736

47374737
static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
47384738
{
4739-
return container_of(dev, struct intel_iommu, iommu.dev);
4739+
struct iommu_device *iommu_dev = dev_to_iommu_device(dev);
4740+
4741+
return container_of(iommu_dev, struct intel_iommu, iommu);
47404742
}
47414743

47424744
static ssize_t intel_iommu_show_version(struct device *dev,

drivers/iommu/iommu-sysfs.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,32 +62,40 @@ int iommu_device_sysfs_add(struct iommu_device *iommu,
6262
va_list vargs;
6363
int ret;
6464

65-
device_initialize(&iommu->dev);
65+
iommu->dev = kzalloc(sizeof(*iommu->dev), GFP_KERNEL);
66+
if (!iommu->dev)
67+
return -ENOMEM;
6668

67-
iommu->dev.class = &iommu_class;
68-
iommu->dev.parent = parent;
69-
iommu->dev.groups = groups;
69+
device_initialize(iommu->dev);
70+
71+
iommu->dev->class = &iommu_class;
72+
iommu->dev->parent = parent;
73+
iommu->dev->groups = groups;
7074

7175
va_start(vargs, fmt);
72-
ret = kobject_set_name_vargs(&iommu->dev.kobj, fmt, vargs);
76+
ret = kobject_set_name_vargs(&iommu->dev->kobj, fmt, vargs);
7377
va_end(vargs);
7478
if (ret)
7579
goto error;
7680

77-
ret = device_add(&iommu->dev);
81+
ret = device_add(iommu->dev);
7882
if (ret)
7983
goto error;
8084

85+
dev_set_drvdata(iommu->dev, iommu);
86+
8187
return 0;
8288

8389
error:
84-
put_device(&iommu->dev);
90+
put_device(iommu->dev);
8591
return ret;
8692
}
8793

8894
void iommu_device_sysfs_remove(struct iommu_device *iommu)
8995
{
90-
device_unregister(&iommu->dev);
96+
dev_set_drvdata(iommu->dev, NULL);
97+
device_unregister(iommu->dev);
98+
iommu->dev = NULL;
9199
}
92100
/*
93101
* IOMMU drivers can indicate a device is managed by a given IOMMU using
@@ -102,14 +110,14 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link)
102110
if (!iommu || IS_ERR(iommu))
103111
return -ENODEV;
104112

105-
ret = sysfs_add_link_to_group(&iommu->dev.kobj, "devices",
113+
ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices",
106114
&link->kobj, dev_name(link));
107115
if (ret)
108116
return ret;
109117

110-
ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev.kobj, "iommu");
118+
ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu");
111119
if (ret)
112-
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices",
120+
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices",
113121
dev_name(link));
114122

115123
return ret;
@@ -121,5 +129,5 @@ void iommu_device_unlink(struct iommu_device *iommu, struct device *link)
121129
return;
122130

123131
sysfs_remove_link(&link->kobj, "iommu");
124-
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices", dev_name(link));
132+
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link));
125133
}

include/linux/iommu.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ struct iommu_device {
240240
struct list_head list;
241241
const struct iommu_ops *ops;
242242
struct fwnode_handle *fwnode;
243-
struct device dev;
243+
struct device *dev;
244244
};
245245

246246
int iommu_device_register(struct iommu_device *iommu);
@@ -265,6 +265,11 @@ static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
265265
iommu->fwnode = fwnode;
266266
}
267267

268+
static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
269+
{
270+
return (struct iommu_device *)dev_get_drvdata(dev);
271+
}
272+
268273
#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */
269274
#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */
270275
#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */
@@ -589,6 +594,11 @@ static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
589594
{
590595
}
591596

597+
static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
598+
{
599+
return NULL;
600+
}
601+
592602
static inline void iommu_device_unregister(struct iommu_device *iommu)
593603
{
594604
}

0 commit comments

Comments
 (0)