From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
To: Bjorn Andersson <quic_bjorande@quicinc.com>
Cc: Sebastian Reichel <sre@kernel.org>,
Bjorn Andersson <andersson@kernel.org>,
Konrad Dybcio <konrad.dybcio@linaro.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Neil Armstrong <neil.armstrong@linaro.org>,
Johan Hovold <johan+linaro@kernel.org>,
Chris Lew <quic_clew@quicinc.com>,
Dmitry Baryshkov <dmitry.baryshkov@linaro.org>,
Stephen Boyd <swboyd@chromium.org>,
Amit Pundir <amit.pundir@linaro.org>,
linux-arm-msm@vger.kernel.org, linux-pm@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
Johan Hovold <johan@kernel.org>,
stable@vger.kernel.org
Subject: Re: [PATCH 1/3] soc: qcom: pmic_glink: Fix race during initialization
Date: Mon, 19 Aug 2024 16:20:02 +0300 [thread overview]
Message-ID: <ZsNGgmnZfZs+Z50R@kuha.fi.intel.com> (raw)
In-Reply-To: <20240818-pmic-glink-v6-11-races-v1-1-f87c577e0bc9@quicinc.com>
On Sun, Aug 18, 2024 at 04:17:37PM -0700, Bjorn Andersson wrote:
> As pointed out by Stephen Boyd it is possible that during initialization
> of the pmic_glink child drivers, the protection-domain notifiers fires,
> and the associated work is scheduled, before the client registration
> returns and as a result the local "client" pointer has been initialized.
>
> The outcome of this is a NULL pointer dereference as the "client"
> pointer is blindly dereferenced.
>
> Timeline provided by Stephen:
> CPU0 CPU1
> ---- ----
> ucsi->client = NULL;
> devm_pmic_glink_register_client()
> client->pdr_notify(client->priv, pg->client_state)
> pmic_glink_ucsi_pdr_notify()
> schedule_work(&ucsi->register_work)
> <schedule away>
> pmic_glink_ucsi_register()
> ucsi_register()
> pmic_glink_ucsi_read_version()
> pmic_glink_ucsi_read()
> pmic_glink_ucsi_read()
> pmic_glink_send(ucsi->client)
> <client is NULL BAD>
> ucsi->client = client // Too late!
>
> This code is identical across the altmode, battery manager and usci
> child drivers.
>
> Resolve this by splitting the allocation of the "client" object and the
> registration thereof into two operations.
>
> This only happens if the protection domain registry is populated at the
> time of registration, which by the introduction of commit '1ebcde047c54
> ("soc: qcom: add pd-mapper implementation")' became much more likely.
>
> Reported-by: Amit Pundir <amit.pundir@linaro.org>
> Closes: https://lore.kernel.org/all/CAMi1Hd2_a7TjA7J9ShrAbNOd_CoZ3D87twmO5t+nZxC9sX18tA@mail.gmail.com/
> Reported-by: Johan Hovold <johan@kernel.org>
> Closes: https://lore.kernel.org/all/ZqiyLvP0gkBnuekL@hovoldconsulting.com/
> Reported-by: Stephen Boyd <swboyd@chromium.org>
> Closes: https://lore.kernel.org/all/CAE-0n52JgfCBWiFQyQWPji8cq_rCsviBpW-m72YitgNfdaEhQg@mail.gmail.com/
> Fixes: 58ef4ece1e41 ("soc: qcom: pmic_glink: Introduce base PMIC GLINK driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> ---
> drivers/power/supply/qcom_battmgr.c | 16 ++++++++++------
> drivers/soc/qcom/pmic_glink.c | 28 ++++++++++++++++++----------
> drivers/soc/qcom/pmic_glink_altmode.c | 17 +++++++++++------
> drivers/usb/typec/ucsi/ucsi_glink.c | 16 ++++++++++------
> include/linux/soc/qcom/pmic_glink.h | 11 ++++++-----
> 5 files changed, 55 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c
> index 49bef4a5ac3f..df90a470c51a 100644
> --- a/drivers/power/supply/qcom_battmgr.c
> +++ b/drivers/power/supply/qcom_battmgr.c
> @@ -1387,12 +1387,16 @@ static int qcom_battmgr_probe(struct auxiliary_device *adev,
> "failed to register wireless charing power supply\n");
> }
>
> - battmgr->client = devm_pmic_glink_register_client(dev,
> - PMIC_GLINK_OWNER_BATTMGR,
> - qcom_battmgr_callback,
> - qcom_battmgr_pdr_notify,
> - battmgr);
> - return PTR_ERR_OR_ZERO(battmgr->client);
> + battmgr->client = devm_pmic_glink_new_client(dev, PMIC_GLINK_OWNER_BATTMGR,
> + qcom_battmgr_callback,
> + qcom_battmgr_pdr_notify,
> + battmgr);
> + if (IS_ERR(battmgr->client))
> + return PTR_ERR(battmgr->client);
> +
> + pmic_glink_register_client(battmgr->client);
> +
> + return 0;
> }
>
> static const struct auxiliary_device_id qcom_battmgr_id_table[] = {
> diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
> index 9ebc0ba35947..58ec91767d79 100644
> --- a/drivers/soc/qcom/pmic_glink.c
> +++ b/drivers/soc/qcom/pmic_glink.c
> @@ -66,15 +66,14 @@ static void _devm_pmic_glink_release_client(struct device *dev, void *res)
> spin_unlock_irqrestore(&pg->client_lock, flags);
> }
>
> -struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
> - unsigned int id,
> - void (*cb)(const void *, size_t, void *),
> - void (*pdr)(void *, int),
> - void *priv)
> +struct pmic_glink_client *devm_pmic_glink_new_client(struct device *dev,
> + unsigned int id,
> + void (*cb)(const void *, size_t, void *),
> + void (*pdr)(void *, int),
> + void *priv)
> {
> struct pmic_glink_client *client;
> struct pmic_glink *pg = dev_get_drvdata(dev->parent);
> - unsigned long flags;
>
> client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
> if (!client)
> @@ -85,6 +84,18 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
> client->cb = cb;
> client->pdr_notify = pdr;
> client->priv = priv;
> + INIT_LIST_HEAD(&client->node);
> +
> + devres_add(dev, client);
> +
> + return client;
> +}
> +EXPORT_SYMBOL_GPL(devm_pmic_glink_new_client);
> +
> +void pmic_glink_register_client(struct pmic_glink_client *client)
> +{
> + struct pmic_glink *pg = client->pg;
> + unsigned long flags;
>
> mutex_lock(&pg->state_lock);
> spin_lock_irqsave(&pg->client_lock, flags);
> @@ -95,11 +106,8 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
> spin_unlock_irqrestore(&pg->client_lock, flags);
> mutex_unlock(&pg->state_lock);
>
> - devres_add(dev, client);
> -
> - return client;
> }
> -EXPORT_SYMBOL_GPL(devm_pmic_glink_register_client);
> +EXPORT_SYMBOL_GPL(pmic_glink_register_client);
>
> int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
> {
> diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
> index 1e0808b3cb93..e4f5059256e5 100644
> --- a/drivers/soc/qcom/pmic_glink_altmode.c
> +++ b/drivers/soc/qcom/pmic_glink_altmode.c
> @@ -520,12 +520,17 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
> return ret;
> }
>
> - altmode->client = devm_pmic_glink_register_client(dev,
> - altmode->owner_id,
> - pmic_glink_altmode_callback,
> - pmic_glink_altmode_pdr_notify,
> - altmode);
> - return PTR_ERR_OR_ZERO(altmode->client);
> + altmode->client = devm_pmic_glink_new_client(dev,
> + altmode->owner_id,
> + pmic_glink_altmode_callback,
> + pmic_glink_altmode_pdr_notify,
> + altmode);
> + if (IS_ERR(altmode->client))
> + return PTR_ERR(altmode->client);
> +
> + pmic_glink_register_client(altmode->client);
> +
> + return 0;
> }
>
> static const struct auxiliary_device_id pmic_glink_altmode_id_table[] = {
> diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c
> index 16c328497e0b..ac53a81c2a81 100644
> --- a/drivers/usb/typec/ucsi/ucsi_glink.c
> +++ b/drivers/usb/typec/ucsi/ucsi_glink.c
> @@ -367,12 +367,16 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
> ucsi->port_orientation[port] = desc;
> }
>
> - ucsi->client = devm_pmic_glink_register_client(dev,
> - PMIC_GLINK_OWNER_USBC,
> - pmic_glink_ucsi_callback,
> - pmic_glink_ucsi_pdr_notify,
> - ucsi);
> - return PTR_ERR_OR_ZERO(ucsi->client);
> + ucsi->client = devm_pmic_glink_new_client(dev, PMIC_GLINK_OWNER_USBC,
> + pmic_glink_ucsi_callback,
> + pmic_glink_ucsi_pdr_notify,
> + ucsi);
> + if (IS_ERR(ucsi->client))
> + return PTR_ERR(ucsi->client);
> +
> + pmic_glink_register_client(ucsi->client);
> +
> + return 0;
> }
>
> static void pmic_glink_ucsi_remove(struct auxiliary_device *adev)
> diff --git a/include/linux/soc/qcom/pmic_glink.h b/include/linux/soc/qcom/pmic_glink.h
> index fd124aa18c81..aedde76d7e13 100644
> --- a/include/linux/soc/qcom/pmic_glink.h
> +++ b/include/linux/soc/qcom/pmic_glink.h
> @@ -23,10 +23,11 @@ struct pmic_glink_hdr {
>
> int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len);
>
> -struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
> - unsigned int id,
> - void (*cb)(const void *, size_t, void *),
> - void (*pdr)(void *, int),
> - void *priv);
> +struct pmic_glink_client *devm_pmic_glink_new_client(struct device *dev,
> + unsigned int id,
> + void (*cb)(const void *, size_t, void *),
> + void (*pdr)(void *, int),
> + void *priv);
> +void pmic_glink_register_client(struct pmic_glink_client *client);
>
> #endif
--
heikki
next prev parent reply other threads:[~2024-08-19 13:20 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-18 23:17 [PATCH 0/3] soc: qcom: pmic_glink: v6.11-rc bug fixes Bjorn Andersson
2024-08-18 23:17 ` [PATCH 1/3] soc: qcom: pmic_glink: Fix race during initialization Bjorn Andersson
2024-08-19 9:15 ` Neil Armstrong
2024-08-19 13:20 ` Heikki Krogerus [this message]
2024-08-18 23:17 ` [PATCH 2/3] usb: typec: ucsi: Move unregister out of atomic section Bjorn Andersson
2024-08-19 1:16 ` Dmitry Baryshkov
2024-08-19 3:05 ` Bjorn Andersson
2024-08-19 7:32 ` Dmitry Baryshkov
2024-08-19 9:16 ` Neil Armstrong
2024-08-19 13:27 ` Heikki Krogerus
2024-08-19 15:06 ` Johan Hovold
2024-08-19 16:45 ` Bjorn Andersson
2024-08-20 6:34 ` Johan Hovold
2024-08-19 15:33 ` Johan Hovold
2024-08-18 23:17 ` [PATCH 3/3] soc: qcom: pmic_glink: Actually communicate with remote goes down Bjorn Andersson
2024-08-19 1:09 ` Dmitry Baryshkov
2024-08-19 9:16 ` Neil Armstrong
2024-08-19 13:33 ` Heikki Krogerus
2024-08-19 10:12 ` [PATCH 0/3] soc: qcom: pmic_glink: v6.11-rc bug fixes Amit Pundir
2024-08-19 14:07 ` Greg Kroah-Hartman
2024-08-19 14:56 ` Bjorn Andersson
2024-08-19 15:48 ` Johan Hovold
2024-08-19 16:53 ` Bjorn Andersson
2024-08-20 7:31 ` Johan Hovold
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZsNGgmnZfZs+Z50R@kuha.fi.intel.com \
--to=heikki.krogerus@linux.intel.com \
--cc=amit.pundir@linaro.org \
--cc=andersson@kernel.org \
--cc=dmitry.baryshkov@linaro.org \
--cc=gregkh@linuxfoundation.org \
--cc=johan+linaro@kernel.org \
--cc=johan@kernel.org \
--cc=konrad.dybcio@linaro.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=quic_bjorande@quicinc.com \
--cc=quic_clew@quicinc.com \
--cc=sre@kernel.org \
--cc=stable@vger.kernel.org \
--cc=swboyd@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox