From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754071AbbESHNU (ORCPT ); Tue, 19 May 2015 03:13:20 -0400 Received: from mailout3.w1.samsung.com ([210.118.77.13]:12740 "EHLO mailout3.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753888AbbESHNP (ORCPT ); Tue, 19 May 2015 03:13:15 -0400 X-AuditID: cbfec7f5-f794b6d000001495-84-555ae288293e From: Krzysztof Kozlowski To: Sebastian Reichel , Dmitry Eremin-Solenikov , David Woodhouse , linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "H. Nikolaus Schaller" , Krzysztof Kozlowski Subject: [RFC/RFT v2 1/2] power_supply: Fix NULL pointer dereference during bq27x00_battery probe Date: Tue, 19 May 2015 16:13:01 +0900 Message-id: <1432019582-27612-2-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1432019582-27612-1-git-send-email-k.kozlowski@samsung.com> References: <1432019582-27612-1-git-send-email-k.kozlowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprGLMWRmVeSWpSXmKPExsVy+t/xy7odj6JCDVb9UbaY9OQ9s8XElZOZ LX5s+8pk8fqFocXlXXPYLD73HmG0OL27xIHdY+esu+wea96fYvbYvELLY9OqTjaPvi2rGD0+ b5ILYIvisklJzcksSy3St0vgymg+2M5Y8EW0YsLGdWwNjG8Euxg5OSQETCS2HNjIAmGLSVy4 t56ti5GLQ0hgKaPEtqYJbCAJIYH/jBLtmyxAbDYBY4nNy5eAFYkI7GaUmDB1OVg3s0C8xMMp O1hBbGGBZIlTzzczg9gsAqoSl1qng9XwCrhL9Gz8yQSxTU7i5LHJYPWcAh4S/R0L2CGWuUtc frKBcQIj7wJGhlWMoqmlyQXFSem5RnrFibnFpXnpesn5uZsYIaH1dQfj0mNWhxgFOBiVeHhX +EWGCrEmlhVX5h5ilOBgVhLhZbsUFSrEm5JYWZValB9fVJqTWnyIUZqDRUmcd+au9yFCAumJ JanZqakFqUUwWSYOTqkGRpddfIlzI8KlDt+6+P1vc8Wf3zolv3aIRYtd/lYWPtlJ/q7Gh0cn Xpx0azB4Xe5/MXp24+cZHcaThOZJZ2X0xIb0PZmj5Sfz9FNNtvAT5akLNl38Z5yym81LtvFE BKOf/tNjFSqNi/8sW1XwzIpfbdVuzhePAlU69MJKr690SVqk9dTv3J2ob0osxRmJhlrMRcWJ AGuhDTkpAgAA Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Power supply is often registered during probe of a driver. The power_supply_register() returns pointer to newly allocated structure as return value. However before returning the power_supply_register() calls back the get_property() method provided by the driver through uevent. In that time the driver probe is still in progress and driver did not assigned pointer to power supply to its local variables. This leads to NULL pointer dereference from get_property() function. Starting from bq27x00_battery_probe(): di->bat = power_supply_register() device_add() kobject_uevent() power_supply_uevent() power_supply_show_property() power_supply_get_property() bq27x00_battery_get_property() dereference of (di->bat) which is NULL here The first uevent of power supply (the one coming from device creation) should not call back to the driver. To prevent that from happening, increment the atomic use counter at the end of power_supply_register(). This means that power_supply_get_property() will return -ENODEV. IMPORTANT: The patch has impact on this first uevent sent from power supply because it will not contain properties from power supply. The uevent with properties will be sent later after indicating that power supply has changed. This also has a race now, but will be fixed in other patches. Reported-by: H. Nikolaus Schaller Signed-off-by: Krzysztof Kozlowski Fixes: 297d716f6260 ("power_supply: Change ownership from driver to core") --- drivers/power/power_supply_core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 2ed4a4a6b3c5..15da277e0e8d 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -659,7 +659,6 @@ __power_supply_register(struct device *parent, dev->release = power_supply_dev_release; dev_set_drvdata(dev, psy); psy->desc = desc; - atomic_inc(&psy->use_cnt); if (cfg) { psy->drv_data = cfg->drv_data; psy->of_node = cfg->of_node; @@ -700,6 +699,16 @@ __power_supply_register(struct device *parent, if (rc) goto create_triggers_failed; + /* + * Update use_cnt after any uevents (most notably from device_add()). + * We are here still during driver's probe but + * the power_supply_uevent() calls back driver's get_property + * method so: + * 1. Driver did not assigned the returned struct power_supply, + * 2. Driver could not finish initialization (anything in its probe + * after calling power_supply_register()). + */ + atomic_inc(&psy->use_cnt); power_supply_changed(psy); return psy; -- 1.9.1