Skip to content

Commit e686c32

Browse files
committed
dax/kmem: Fix leak of memory-hotplug resources
While experimenting with CXL region removal the following corruption of /proc/iomem appeared. Before: f010000000-f04fffffff : CXL Window 0 f010000000-f02fffffff : region4 f010000000-f02fffffff : dax4.0 f010000000-f02fffffff : System RAM (kmem) After (modprobe -r cxl_test): f010000000-f02fffffff : **redacted binary garbage** f010000000-f02fffffff : System RAM (kmem) ...and testing further the same is visible with persistent memory assigned to kmem: Before: 480000000-243fffffff : Persistent Memory 480000000-57e1fffff : namespace3.0 580000000-243fffffff : dax3.0 580000000-243fffffff : System RAM (kmem) After (ndctl disable-region all): 480000000-243fffffff : Persistent Memory 580000000-243fffffff : ***redacted binary garbage*** 580000000-243fffffff : System RAM (kmem) The corrupted data is from a use-after-free of the "dax4.0" and "dax3.0" resources, and it also shows that the "System RAM (kmem)" resource is not being removed. The bug does not appear after "modprobe -r kmem", it requires the parent of "dax4.0" and "dax3.0" to be removed which re-parents the leaked "System RAM (kmem)" instances. Those in turn reference the freed resource as a parent. First up for the fix is release_mem_region_adjustable() needs to reliably delete the resource inserted by add_memory_driver_managed(). That is thwarted by a check for IORESOURCE_SYSRAM that predates the dax/kmem driver, from commit: 65c7878 ("kernel, resource: check for IORESOURCE_SYSRAM in release_mem_region_adjustable") That appears to be working around the behavior of HMM's "MEMORY_DEVICE_PUBLIC" facility that has since been deleted. With that check removed the "System RAM (kmem)" resource gets removed, but corruption still occurs occasionally because the "dax" resource is not reliably removed. The dax range information is freed before the device is unregistered, so the driver can not reliably recall (another use after free) what it is meant to release. Lastly if that use after free got lucky, the driver was covering up the leak of "System RAM (kmem)" due to its use of release_resource() which detaches, but does not free, child resources. The switch to remove_resource() forces remove_memory() to be responsible for the deletion of the resource added by add_memory_driver_managed(). Fixes: c2f3011 ("device-dax: add an allocation interface for device-dax instances") Cc: <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Pavel Tatashin <[email protected]> Reviewed-by: Vishal Verma <[email protected]> Reviewed-by: Pasha Tatashin <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Link: https://lore.kernel.org/r/167653656244.3147810.5705900882794040229.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <[email protected]>
1 parent 23c198e commit e686c32

File tree

3 files changed

+3
-17
lines changed

3 files changed

+3
-17
lines changed

drivers/dax/bus.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,8 @@ static void unregister_dev_dax(void *dev)
441441
dev_dbg(dev, "%s\n", __func__);
442442

443443
kill_dev_dax(dev_dax);
444-
free_dev_dax_ranges(dev_dax);
445444
device_del(dev);
445+
free_dev_dax_ranges(dev_dax);
446446
put_device(dev);
447447
}
448448

drivers/dax/kmem.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
146146
if (rc) {
147147
dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n",
148148
i, range.start, range.end);
149-
release_resource(res);
149+
remove_resource(res);
150150
kfree(res);
151151
data->res[i] = NULL;
152152
if (mapped)
@@ -195,7 +195,7 @@ static void dev_dax_kmem_remove(struct dev_dax *dev_dax)
195195

196196
rc = remove_memory(range.start, range_len(&range));
197197
if (rc == 0) {
198-
release_resource(data->res[i]);
198+
remove_resource(data->res[i]);
199199
kfree(data->res[i]);
200200
data->res[i] = NULL;
201201
success++;

kernel/resource.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,20 +1343,6 @@ void release_mem_region_adjustable(resource_size_t start, resource_size_t size)
13431343
continue;
13441344
}
13451345

1346-
/*
1347-
* All memory regions added from memory-hotplug path have the
1348-
* flag IORESOURCE_SYSTEM_RAM. If the resource does not have
1349-
* this flag, we know that we are dealing with a resource coming
1350-
* from HMM/devm. HMM/devm use another mechanism to add/release
1351-
* a resource. This goes via devm_request_mem_region and
1352-
* devm_release_mem_region.
1353-
* HMM/devm take care to release their resources when they want,
1354-
* so if we are dealing with them, let us just back off here.
1355-
*/
1356-
if (!(res->flags & IORESOURCE_SYSRAM)) {
1357-
break;
1358-
}
1359-
13601346
if (!(res->flags & IORESOURCE_MEM))
13611347
break;
13621348

0 commit comments

Comments
 (0)