On 07/16/2016 03:32 AM, Dan Williams wrote:
acpi_evaluate_object() allocates memory. Free the buffer allocated
during acpi_nfit_add().  Also, make it clear that ->nfit is not used
outside of acpi_nfit_init() context.

Cc: <[email protected]>
Cc: Vishal Verma <[email protected]>
Reported-by: Xiao Guangrong <[email protected]>
Reported-by: Haozhong Zhang <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
---
Change since v1:

* Fix unitialized use of 'rc' (Haozhong)
* Clarify that their is no use-after-free problem in acpi_nfit_notify()
   (Xiao)


No... This is a real problem, please seem below.

  drivers/acpi/nfit.c |   21 +++++++++------------
  1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index d89a02d9ed10..cbdbe13bdbe8 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -2390,7 +2390,7 @@ static int acpi_nfit_add(struct acpi_device *adev)
        struct acpi_table_header *tbl;
        acpi_status status = AE_OK;
        acpi_size sz;
-       int rc;
+       int rc = 0;

        status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
        if (ACPI_FAILURE(status)) {
@@ -2427,12 +2427,15 @@ static int acpi_nfit_add(struct acpi_device *adev)
                        acpi_desc->nfit =
                                (struct acpi_nfit_header *)obj->buffer.pointer;
                        sz = obj->buffer.length;
+                       rc = acpi_nfit_init(acpi_desc, sz);
                } else
                        dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
                                 __func__, (int) obj->type);
-       }
+               acpi_desc->nfit = NULL;
+               kfree(buf.pointer);
+       } else
+               rc = acpi_nfit_init(acpi_desc, sz);

-       rc = acpi_nfit_init(acpi_desc, sz);
        if (rc) {
                nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
                return rc;
@@ -2454,7 +2457,6 @@ static void acpi_nfit_notify(struct acpi_device *adev, 
u32 event)
  {
        struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
        struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_nfit_header *nfit_saved;
        union acpi_object *obj;
        struct device *dev = &adev->dev;
        acpi_status status;
@@ -2492,21 +2494,16 @@ static void acpi_nfit_notify(struct acpi_device *adev, 
u32 event)
                goto out_unlock;
        }

-       nfit_saved = acpi_desc->nfit;
        obj = buf.pointer;
        if (obj->type == ACPI_TYPE_BUFFER) {
                acpi_desc->nfit =
                        (struct acpi_nfit_header *)obj->buffer.pointer;
                ret = acpi_nfit_init(acpi_desc, obj->buffer.length);

The issue is in acpi_nfit_init(), there are some info constructing nfit_spa
is directly from acpi_desc->nfit, for example:
acpi_nfit_init() -> add_table() -> add_spa():

static bool add_spa(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev,
                struct acpi_nfit_system_address *spa)
{
   ...
        list_for_each_entry(nfit_spa, &prev->spas, list) {
                if (memcmp(nfit_spa->spa, spa, length) == 0) {      // A
                        list_move_tail(&nfit_spa->list, &acpi_desc->spas);
                        return true;
                }
        }
   ...
                return false;
        INIT_LIST_HEAD(&nfit_spa->list);
        nfit_spa->spa = spa;                // B
        list_add_tail(&nfit_spa->list, &acpi_desc->spas);
  ...
}

Note at point B, @spa is from acpi_desc->nfit. At point A, this @spa will be 
used
to check if it has already existed if hotplug event happens later.

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to