From: Greg Kroah-Hartman Date: Mon, 14 Oct 2024 08:50:34 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v5.10.227~49 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4153fc3b8995ff5398d75e52395865acc8f19ff7;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: resource-fix-region_intersects-vs-add_memory_driver_managed.patch --- diff --git a/queue-5.15/resource-fix-region_intersects-vs-add_memory_driver_managed.patch b/queue-5.15/resource-fix-region_intersects-vs-add_memory_driver_managed.patch new file mode 100644 index 00000000000..02f0061ce2e --- /dev/null +++ b/queue-5.15/resource-fix-region_intersects-vs-add_memory_driver_managed.patch @@ -0,0 +1,174 @@ +From b4afe4183ec77f230851ea139d91e5cf2644c68b Mon Sep 17 00:00:00 2001 +From: Huang Ying +Date: Fri, 6 Sep 2024 11:07:11 +0800 +Subject: resource: fix region_intersects() vs add_memory_driver_managed() + +From: Huang Ying + +commit b4afe4183ec77f230851ea139d91e5cf2644c68b upstream. + +On a system with CXL memory, the resource tree (/proc/iomem) related to +CXL memory may look like something as follows. + +490000000-50fffffff : CXL Window 0 + 490000000-50fffffff : region0 + 490000000-50fffffff : dax0.0 + 490000000-50fffffff : System RAM (kmem) + +Because drivers/dax/kmem.c calls add_memory_driver_managed() during +onlining CXL memory, which makes "System RAM (kmem)" a descendant of "CXL +Window X". This confuses region_intersects(), which expects all "System +RAM" resources to be at the top level of iomem_resource. This can lead to +bugs. + +For example, when the following command line is executed to write some +memory in CXL memory range via /dev/mem, + + $ dd if=data of=/dev/mem bs=$((1 << 10)) seek=$((0x490000000 >> 10)) count=1 + dd: error writing '/dev/mem': Bad address + 1+0 records in + 0+0 records out + 0 bytes copied, 0.0283507 s, 0.0 kB/s + +the command fails as expected. However, the error code is wrong. It +should be "Operation not permitted" instead of "Bad address". More +seriously, the /dev/mem permission checking in devmem_is_allowed() passes +incorrectly. Although the accessing is prevented later because ioremap() +isn't allowed to map system RAM, it is a potential security issue. During +command executing, the following warning is reported in the kernel log for +calling ioremap() on system RAM. + + ioremap on RAM at 0x0000000490000000 - 0x0000000490000fff + WARNING: CPU: 2 PID: 416 at arch/x86/mm/ioremap.c:216 __ioremap_caller.constprop.0+0x131/0x35d + Call Trace: + memremap+0xcb/0x184 + xlate_dev_mem_ptr+0x25/0x2f + write_mem+0x94/0xfb + vfs_write+0x128/0x26d + ksys_write+0xac/0xfe + do_syscall_64+0x9a/0xfd + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + +The details of command execution process are as follows. In the above +resource tree, "System RAM" is a descendant of "CXL Window 0" instead of a +top level resource. So, region_intersects() will report no System RAM +resources in the CXL memory region incorrectly, because it only checks the +top level resources. Consequently, devmem_is_allowed() will return 1 +(allow access via /dev/mem) for CXL memory region incorrectly. +Fortunately, ioremap() doesn't allow to map System RAM and reject the +access. + +So, region_intersects() needs to be fixed to work correctly with the +resource tree with "System RAM" not at top level as above. To fix it, if +we found a unmatched resource in the top level, we will continue to search +matched resources in its descendant resources. So, we will not miss any +matched resources in resource tree anymore. + +In the new implementation, an example resource tree + +|------------- "CXL Window 0" ------------| +|-- "System RAM" --| + +will behave similar as the following fake resource tree for +region_intersects(, IORESOURCE_SYSTEM_RAM, ), + +|-- "System RAM" --||-- "CXL Window 0a" --| + +Where "CXL Window 0a" is part of the original "CXL Window 0" that +isn't covered by "System RAM". + +Link: https://lkml.kernel.org/r/20240906030713.204292-2-ying.huang@intel.com +Fixes: c221c0b0308f ("device-dax: "Hotplug" persistent memory for use like normal RAM") +Signed-off-by: "Huang, Ying" +Cc: Dan Williams +Cc: David Hildenbrand +Cc: Davidlohr Bueso +Cc: Jonathan Cameron +Cc: Dave Jiang +Cc: Alison Schofield +Cc: Vishal Verma +Cc: Ira Weiny +Cc: Alistair Popple +Cc: Andy Shevchenko +Cc: Bjorn Helgaas +Cc: Baoquan He +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + kernel/resource.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 50 insertions(+), 8 deletions(-) + +--- a/kernel/resource.c ++++ b/kernel/resource.c +@@ -480,20 +480,62 @@ EXPORT_SYMBOL_GPL(page_is_ram); + static int __region_intersects(resource_size_t start, size_t size, + unsigned long flags, unsigned long desc) + { +- struct resource res; ++ resource_size_t ostart, oend; + int type = 0; int other = 0; +- struct resource *p; ++ struct resource *p, *dp; ++ bool is_type, covered; ++ struct resource res; + + res.start = start; + res.end = start + size - 1; + + for (p = iomem_resource.child; p ; p = p->sibling) { +- bool is_type = (((p->flags & flags) == flags) && +- ((desc == IORES_DESC_NONE) || +- (desc == p->desc))); +- +- if (resource_overlaps(p, &res)) +- is_type ? type++ : other++; ++ if (!resource_overlaps(p, &res)) ++ continue; ++ is_type = (p->flags & flags) == flags && ++ (desc == IORES_DESC_NONE || desc == p->desc); ++ if (is_type) { ++ type++; ++ continue; ++ } ++ /* ++ * Continue to search in descendant resources as if the ++ * matched descendant resources cover some ranges of 'p'. ++ * ++ * |------------- "CXL Window 0" ------------| ++ * |-- "System RAM" --| ++ * ++ * will behave similar as the following fake resource ++ * tree when searching "System RAM". ++ * ++ * |-- "System RAM" --||-- "CXL Window 0a" --| ++ */ ++ covered = false; ++ ostart = max(res.start, p->start); ++ oend = min(res.end, p->end); ++ for (dp = p->child; dp; dp = next_resource(dp)) { ++ if (!resource_overlaps(dp, &res)) ++ continue; ++ is_type = (dp->flags & flags) == flags && ++ (desc == IORES_DESC_NONE || desc == dp->desc); ++ if (is_type) { ++ type++; ++ /* ++ * Range from 'ostart' to 'dp->start' ++ * isn't covered by matched resource. ++ */ ++ if (dp->start > ostart) ++ break; ++ if (dp->end >= oend) { ++ covered = true; ++ break; ++ } ++ /* Remove covered range */ ++ ostart = max(ostart, dp->end + 1); ++ } ++ } ++ if (!covered) ++ other++; + } + + if (type == 0) diff --git a/queue-5.15/series b/queue-5.15/series index 60552033768..bda34831619 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -669,3 +669,4 @@ hwmon-tmp513-add-missing-dependency-on-regmap_i2c.patch hwmon-adm9240-add-missing-dependency-on-regmap_i2c.patch hwmon-adt7470-add-missing-dependency-on-regmap_i2c.patch hid-amd_sfh-switch-to-device-managed-dmam_alloc_coherent.patch +resource-fix-region_intersects-vs-add_memory_driver_managed.patch