blob: 72ad8fa6d8a07c8c9257484bed3b3023ef6c5175 [file]
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