Skip to content

Commit

Permalink
ACPI: bus: Avoid non-ACPI device objects in walks over children
Browse files Browse the repository at this point in the history
When walking the children of an ACPI device, take extra care to avoid
using to_acpi_device() on the ones that are not ACPI devices, because
that may lead to out-of-bounds access and memory corruption.

While at it, make the function passed to acpi_dev_for_each_child()
take a struct acpi_device pointer argument (instead of a struct device
one), so it is more straightforward to use.

Fixes: b7dd629 ("ACPI: PM: Introduce acpi_dev_power_up_children_with_adr()")
Reported-by: kernel test robot <[email protected]>
BugLink: https://lore.kernel.org/lkml/20220420064725.GB16310@xsang-OptiPlex-9020/
Signed-off-by: Rafael J. Wysocki <[email protected]>
Reviewed-by: Mika Westerberg <[email protected]>
  • Loading branch information
rafaeljw committed Apr 22, 2022
1 parent 62d5287 commit 10fa1b2
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 7 deletions.
24 changes: 22 additions & 2 deletions drivers/acpi/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -1070,10 +1070,30 @@ int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data)
}
EXPORT_SYMBOL_GPL(acpi_bus_for_each_dev);

struct acpi_dev_walk_context {
int (*fn)(struct acpi_device *, void *);
void *data;
};

static int acpi_dev_for_one_check(struct device *dev, void *context)
{
struct acpi_dev_walk_context *adwc = context;

if (dev->bus != &acpi_bus_type)
return 0;

return adwc->fn(to_acpi_device(dev), adwc->data);
}

int acpi_dev_for_each_child(struct acpi_device *adev,
int (*fn)(struct device *, void *), void *data)
int (*fn)(struct acpi_device *, void *), void *data)
{
return device_for_each_child(&adev->dev, data, fn);
struct acpi_dev_walk_context adwc = {
.fn = fn,
.data = data,
};

return device_for_each_child(&adev->dev, &adwc, acpi_dev_for_one_check);
}

/* --------------------------------------------------------------------------
Expand Down
5 changes: 1 addition & 4 deletions drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,8 @@ bool acpi_bus_power_manageable(acpi_handle handle)
}
EXPORT_SYMBOL(acpi_bus_power_manageable);

static int acpi_power_up_if_adr_present(struct device *dev, void *not_used)
static int acpi_power_up_if_adr_present(struct acpi_device *adev, void *not_used)
{
struct acpi_device *adev;

adev = to_acpi_device(dev);
if (!(adev->flags.power_manageable && adev->pnp.type.bus_address))
return 0;

Expand Down
2 changes: 1 addition & 1 deletion include/acpi/acpi_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ extern struct bus_type acpi_bus_type;

int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data);
int acpi_dev_for_each_child(struct acpi_device *adev,
int (*fn)(struct device *, void *), void *data);
int (*fn)(struct acpi_device *, void *), void *data);

/*
* Events
Expand Down

0 comments on commit 10fa1b2

Please sign in to comment.