| From 2cb8bee0b25501de991e79d1a235a9d0ef4c8534 Mon Sep 17 00:00:00 2001 |
| From: Joseph CT Chan <josephctchan@google.com> |
| Date: Wed, 19 Aug 2026 19:07:46 +0000 |
| Subject: [PATCH] soc: nuvoton: npcm-espi-mmbi: validate buffer offsets |
| |
| Validate host read-only (hrop) and host read-write (hrwp) pointer |
| offsets against circular buffer boundary sizes (b2h_cb_size and |
| h2b_cb_size) in npcm-espi-mmbi. |
| |
| Untrusted inputs from the host could provide out-of-bounds offsets, |
| causing negative size calculations that wrap into huge positive values |
| when passed to memcpy/copy_from_user, leading to kernel stack overflow |
| and arbitrary out-of-bounds writes. |
| |
| Upstream-Status: Inappropriate [vendor specific] |
| Signed-off-by: Joseph CT Chan <josephctchan@google.com> |
| --- |
| drivers/soc/nuvoton/npcm-espi-mmbi.c | 24 ++++++++++++++++++++++++ |
| 1 file changed, 24 insertions(+) |
| |
| diff --git a/drivers/soc/nuvoton/npcm-espi-mmbi.c b/drivers/soc/nuvoton/npcm-espi-mmbi.c |
| index 56f8e3a41376..71d9cac1ed2d 100644 |
| --- a/drivers/soc/nuvoton/npcm-espi-mmbi.c |
| +++ b/drivers/soc/nuvoton/npcm-espi-mmbi.c |
| @@ -255,6 +255,13 @@ static int get_b2h_avail_buf_len(struct npcm_mmbi_channel *channel, |
| dev_dbg(channel->priv->dev, "HROP - b2h_wp: 0x%0x, h2b_rp: 0x%0x", |
| hrop.b2h_wp, hrop.h2b_rp); |
| |
| + if (b2h_rp >= channel->b2h_cb_size || |
| + hrop.b2h_wp >= channel->b2h_cb_size) { |
| + dev_err(channel->priv->dev, "Invalid B2H queue offset: b2h_rp=0x%x, b2h_wp=0x%x (max=0x%x)\n", |
| + b2h_rp, hrop.b2h_wp, channel->b2h_cb_size); |
| + return -EINVAL; |
| + } |
| + |
| if (hrop.b2h_wp >= b2h_rp) |
| *avail_buf_len = channel->b2h_cb_size - hrop.b2h_wp + b2h_rp - 1; |
| else |
| @@ -291,6 +298,13 @@ static int get_mmbi_header(struct npcm_mmbi_channel *channel, |
| b2h_rp = GET_B2H_READ_POINTER(h_rwp1); |
| dev_dbg(channel->priv->dev, "MMBI HRWP - h2b_wp: 0x%0x, b2h_rp: 0x%0x\n", h2b_wp, b2h_rp); |
| |
| + if (h2b_wp >= channel->h2b_cb_size || |
| + hrop.h2b_rp >= channel->h2b_cb_size) { |
| + dev_err(channel->priv->dev, "Invalid H2B queue offset: h2b_wp=0x%x, h2b_rp=0x%x (max=0x%x)\n", |
| + h2b_wp, hrop.h2b_rp, channel->h2b_cb_size); |
| + return -EINVAL; |
| + } |
| + |
| if (h2b_wp >= hrop.h2b_rp) |
| *unread_data_len = h2b_wp - hrop.h2b_rp; |
| else |
| @@ -602,6 +616,11 @@ static ssize_t mmbi_read(struct file *filp, char *buff, size_t count, |
| } |
| |
| memcpy(&hrop, channel->hrop_vmem, sizeof(struct host_rop)); |
| + if (hrop.h2b_rp >= channel->h2b_cb_size) { |
| + dev_err(priv->dev, "Invalid H2B read pointer: 0x%x\n", hrop.h2b_rp); |
| + ret = -EINVAL; |
| + goto err_out; |
| + } |
| if ((hrop.h2b_rp + sizeof(struct mmbi_header)) <= |
| channel->h2b_cb_size) { |
| rd_offset = hrop.h2b_rp + sizeof(struct mmbi_header); |
| @@ -732,6 +751,11 @@ static ssize_t mmbi_write(struct file *filp, const char *buffer, size_t len, |
| header.data = ((protocol->type << 24) + len); |
| |
| memcpy(&hrop, channel->hrop_vmem, sizeof(struct host_rop)); |
| + if (hrop.b2h_wp >= channel->b2h_cb_size) { |
| + dev_err(priv->dev, "Invalid B2H write pointer: 0x%x\n", hrop.b2h_wp); |
| + mutex_unlock(&priv->lock); |
| + return -EINVAL; |
| + } |
| wt_offset = hrop.b2h_wp; |
| end_offset = channel->b2h_cb_size; |
| |
| -- |
| 2.55.0.737.g08866a6d13-goog |
| |