Message ID | ddd1f5cd5341db0ca347259953135eaf9e782873.1567583496.git.leonard.crestez@nxp.com (mailing list archive) |
---|---|
State | Accepted |
Headers | show |
Series | firmware: imx: warn on unexpected RX | expand |
> Subject: [PATCH] firmware: imx: warn on unexpected RX > > The imx_scu_call_rpc function function returns the result inside the same > "msg" struct containing the transmitted message. This is implemented by > holding a pointer to msg (which is usually on the stack) in sc_imx_rpc and > writing to it from imx_scu_rx_callback. > > This means that if the have_resp parameter is incorrect or SCU sends an > unexpected for any reason the most likely result is kernel stack corruption. > > Fix this by only setting sc_imx_rpc.msg for the duration of the > imx_scu_call_rpc call and warning in imx_scu_rx_callback if unset. > > Print the unexpected response data to help debugging. > > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> Acked-by: Anson Huang <Anson.Huang@nxp.com> > --- > drivers/firmware/imx/imx-scu.c | 10 +++++++++- > 1 file changed, 9 insertions(+), 1 deletion(-) > > diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx- > scu.c index 04a24a863d6e..869be7a5172c 100644 > --- a/drivers/firmware/imx/imx-scu.c > +++ b/drivers/firmware/imx/imx-scu.c > @@ -105,10 +105,16 @@ static void imx_scu_rx_callback(struct mbox_client > *c, void *msg) > struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, > cl); > struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc; > struct imx_sc_rpc_msg *hdr; > u32 *data = msg; > > + if (!sc_ipc->msg) { > + dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, > ignore!\n", > + sc_chan->idx, *data); > + return; > + } > + > if (sc_chan->idx == 0) { > hdr = msg; > sc_ipc->rx_size = hdr->size; > dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size); > if (sc_ipc->rx_size > 4) > @@ -163,11 +169,12 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, > void *msg, bool have_resp) > return -EINVAL; > > mutex_lock(&sc_ipc->lock); > reinit_completion(&sc_ipc->done); > > - sc_ipc->msg = msg; > + if (have_resp) > + sc_ipc->msg = msg; > sc_ipc->count = 0; > ret = imx_scu_ipc_write(sc_ipc, msg); > if (ret < 0) { > dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret); > goto out; > @@ -185,10 +192,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, > void *msg, bool have_resp) > hdr = msg; > ret = hdr->func; > } > > out: > + sc_ipc->msg = NULL; > mutex_unlock(&sc_ipc->lock); > > dev_dbg(sc_ipc->dev, "RPC SVC done\n"); > > return imx_sc_to_linux_errno(ret); > -- > 2.17.1
On Wed, Sep 04, 2019 at 10:54:58AM +0300, Leonard Crestez wrote: > The imx_scu_call_rpc function function returns the result inside the s/function function/function > same "msg" struct containing the transmitted message. This is > implemented by holding a pointer to msg (which is usually on the stack) > in sc_imx_rpc and writing to it from imx_scu_rx_callback. > > This means that if the have_resp parameter is incorrect or SCU sends an > unexpected for any reason the most likely result is kernel stack unexpected response I fixed them up and applied the patch. Shawn > corruption. > > Fix this by only setting sc_imx_rpc.msg for the duration of the > imx_scu_call_rpc call and warning in imx_scu_rx_callback if unset. > > Print the unexpected response data to help debugging. > > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> > --- > drivers/firmware/imx/imx-scu.c | 10 +++++++++- > 1 file changed, 9 insertions(+), 1 deletion(-) > > diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c > index 04a24a863d6e..869be7a5172c 100644 > --- a/drivers/firmware/imx/imx-scu.c > +++ b/drivers/firmware/imx/imx-scu.c > @@ -105,10 +105,16 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg) > struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl); > struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc; > struct imx_sc_rpc_msg *hdr; > u32 *data = msg; > > + if (!sc_ipc->msg) { > + dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n", > + sc_chan->idx, *data); > + return; > + } > + > if (sc_chan->idx == 0) { > hdr = msg; > sc_ipc->rx_size = hdr->size; > dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size); > if (sc_ipc->rx_size > 4) > @@ -163,11 +169,12 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) > return -EINVAL; > > mutex_lock(&sc_ipc->lock); > reinit_completion(&sc_ipc->done); > > - sc_ipc->msg = msg; > + if (have_resp) > + sc_ipc->msg = msg; > sc_ipc->count = 0; > ret = imx_scu_ipc_write(sc_ipc, msg); > if (ret < 0) { > dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret); > goto out; > @@ -185,10 +192,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) > hdr = msg; > ret = hdr->func; > } > > out: > + sc_ipc->msg = NULL; > mutex_unlock(&sc_ipc->lock); > > dev_dbg(sc_ipc->dev, "RPC SVC done\n"); > > return imx_sc_to_linux_errno(ret); > -- > 2.17.1 >
diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 04a24a863d6e..869be7a5172c 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -105,10 +105,16 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg) struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl); struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc; struct imx_sc_rpc_msg *hdr; u32 *data = msg; + if (!sc_ipc->msg) { + dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n", + sc_chan->idx, *data); + return; + } + if (sc_chan->idx == 0) { hdr = msg; sc_ipc->rx_size = hdr->size; dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size); if (sc_ipc->rx_size > 4) @@ -163,11 +169,12 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) return -EINVAL; mutex_lock(&sc_ipc->lock); reinit_completion(&sc_ipc->done); - sc_ipc->msg = msg; + if (have_resp) + sc_ipc->msg = msg; sc_ipc->count = 0; ret = imx_scu_ipc_write(sc_ipc, msg); if (ret < 0) { dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret); goto out; @@ -185,10 +192,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) hdr = msg; ret = hdr->func; } out: + sc_ipc->msg = NULL; mutex_unlock(&sc_ipc->lock); dev_dbg(sc_ipc->dev, "RPC SVC done\n"); return imx_sc_to_linux_errno(ret);
The imx_scu_call_rpc function function returns the result inside the same "msg" struct containing the transmitted message. This is implemented by holding a pointer to msg (which is usually on the stack) in sc_imx_rpc and writing to it from imx_scu_rx_callback. This means that if the have_resp parameter is incorrect or SCU sends an unexpected for any reason the most likely result is kernel stack corruption. Fix this by only setting sc_imx_rpc.msg for the duration of the imx_scu_call_rpc call and warning in imx_scu_rx_callback if unset. Print the unexpected response data to help debugging. Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> --- drivers/firmware/imx/imx-scu.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)