ACPI 6.4 extended the System Physical Address Range Structure from 56
to 64 bytes by appending an eight-byte location cookie. The cookie-valid
flag describes whether that field contains usable data; it does not
select the structure length.

sizeof_spa() instead derives the expected length from the flag. It
therefore rejects a valid 64-byte ACPI 6.4 structure when the cookie is
present but not valid. It can also compare 64 bytes against a previously
saved 56-byte structure without first checking that the saved allocation
has the same length.

Accept either the legacy 56-byte layout or the ACPI 6.4 64-byte layout.
Require the cookie-valid flag to be clear for the legacy layout, and
compare saved entries only when their validated lengths match.

Fixes: e9cfd259c6d3 ("ACPI: NFIT: Fix support for variable 'SPA' structure 
size")
Assisted-by: Codex:gpt-5
Signed-off-by: Pengpeng Hou <[email protected]>
---
 drivers/acpi/nfit/core.c | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 4428adb6a1ab..f68edfe64952 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -705,9 +705,20 @@ int nfit_spa_type(struct acpi_nfit_system_address *spa)
 
 static size_t sizeof_spa(struct acpi_nfit_system_address *spa)
 {
+       size_t legacy_size = offsetof(struct acpi_nfit_system_address,
+                                     location_cookie);
+       size_t size = spa->header.length;
+
+       if (size == sizeof(*spa))
+               return size;
+
+       if (size != legacy_size)
+               return 0;
+
        if (spa->flags & ACPI_NFIT_LOCATION_COOKIE_VALID)
-               return sizeof(*spa);
-       return sizeof(*spa) - 8;
+               return 0;
+
+       return size;
 }
 
 static bool add_spa(struct acpi_nfit_desc *acpi_desc,
@@ -716,23 +727,26 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc,
 {
        struct device *dev = acpi_desc->dev;
        struct nfit_spa *nfit_spa;
+       size_t size = sizeof_spa(spa);
 
-       if (spa->header.length != sizeof_spa(spa))
+       if (!size)
                return false;
 
        list_for_each_entry(nfit_spa, &prev->spas, list) {
-               if (memcmp(nfit_spa->spa, spa, sizeof_spa(spa)) == 0) {
+               if (sizeof_spa(nfit_spa->spa) != size)
+                       continue;
+
+               if (memcmp(nfit_spa->spa, spa, size) == 0) {
                        list_move_tail(&nfit_spa->list, &acpi_desc->spas);
                        return true;
                }
        }
 
-       nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa) + sizeof_spa(spa),
-                       GFP_KERNEL);
+       nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa) + size, GFP_KERNEL);
        if (!nfit_spa)
                return false;
        INIT_LIST_HEAD(&nfit_spa->list);
-       memcpy(nfit_spa->spa, spa, sizeof_spa(spa));
+       memcpy(nfit_spa->spa, spa, size);
        list_add_tail(&nfit_spa->list, &acpi_desc->spas);
        dev_dbg(dev, "spa index: %d type: %s\n",
                        spa->range_index,
-- 
2.50.1 (Apple Git-155)


Reply via email to