From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-by2nam03on0100.outbound.protection.outlook.com ([104.47.42.100]:51511 "EHLO NAM03-BY2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S965100AbeCHE6R (ORCPT ); Wed, 7 Mar 2018 23:58:17 -0500 From: Sasha Levin To: "linux-kernel@vger.kernel.org" , "stable@vger.kernel.org" CC: Guenter Roeck , Wim Van Sebroeck , Sasha Levin Subject: [PATCH AUTOSEL for 4.14 23/67] watchdog: Fix potential kref imbalance when opening watchdog Date: Thu, 8 Mar 2018 04:57:41 +0000 Message-ID: <20180308045641.7814-23-alexander.levin@microsoft.com> References: <20180308045641.7814-1-alexander.levin@microsoft.com> In-Reply-To: <20180308045641.7814-1-alexander.levin@microsoft.com> Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org List-ID: From: Guenter Roeck [ Upstream commit 4bcd615fad6adddc68b058d498b30a9e0e0db77a ] If a watchdog driver's open function sets WDOG_HW_RUNNING with the expectation that the watchdog can not be stopped, but then stops the watchdog anyway in its stop function, kref_get() wil not be called in watchdog_open(). If the watchdog then stops on close, WDOG_HW_RUNNING will be cleared and kref_put() will be called, causing a kref imbalance. As result the character device data structure will be released, which in turn will cause the system to crash on the next call to watchdog_open(). Fixes: ee142889e32f5 ("watchdog: Introduce WDOG_HW_RUNNING flag") Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/watchdog_dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_de= v.c index 0826e663bd5a..e6edf3737ea7 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -768,6 +768,7 @@ static int watchdog_open(struct inode *inode, struct fi= le *file) { struct watchdog_core_data *wd_data; struct watchdog_device *wdd; + bool hw_running; int err; =20 /* Get the corresponding watchdog device */ @@ -787,7 +788,8 @@ static int watchdog_open(struct inode *inode, struct fi= le *file) * If the /dev/watchdog device is open, we don't want the module * to be unloaded. */ - if (!watchdog_hw_running(wdd) && !try_module_get(wdd->ops->owner)) { + hw_running =3D watchdog_hw_running(wdd); + if (!hw_running && !try_module_get(wdd->ops->owner)) { err =3D -EBUSY; goto out_clear; } @@ -798,7 +800,7 @@ static int watchdog_open(struct inode *inode, struct fi= le *file) =20 file->private_data =3D wd_data; =20 - if (!watchdog_hw_running(wdd)) + if (!hw_running) kref_get(&wd_data->kref); =20 /* dev/watchdog is a virtual (and thus non-seekable) filesystem */ --=20 2.14.1