From 673478bc29cf72010faaf293c1c8c667393335a0 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Thu, 2 Apr 2026 13:40:15 +0800 Subject: [PATCH] iio: chemical: mhz19b: reject oversized serial replies mhz19b_receive_buf() appends each serdev chunk into the fixed MHZ19B_CMD_SIZE receive buffer and advances buf_idx by len without checking that the chunk fits in the remaining space. A large callback can therefore overflow st->buf before the command path validates the reply. Reset the reply state before each command and reject oversized serial replies before copying them into the fixed buffer. When an oversized reply is detected, wake the waiter and report -EMSGSIZE instead of overwriting st->buf. Fixes: 4572a70b3681 ("iio: chemical: Add support for Winsen MHZ19B CO2 sensor") Cc: stable@vger.kernel.org Signed-off-by: Pengpeng Hou Acked-by: Gyeyoung Baek Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/mhz19b.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/iio/chemical/mhz19b.c b/drivers/iio/chemical/mhz19b.c index 3c64154918b1..9d4cf432919e 100644 --- a/drivers/iio/chemical/mhz19b.c +++ b/drivers/iio/chemical/mhz19b.c @@ -52,6 +52,8 @@ struct mhz19b_state { struct completion buf_ready; u8 buf_idx; + bool buf_overflow; + /* * Serdev receive buffer. * When data is received from the MH-Z19B, @@ -106,6 +108,10 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg) cmd_buf[8] = mhz19b_get_checksum(cmd_buf); /* Write buf to uart ctrl synchronously */ + st->buf_idx = 0; + st->buf_overflow = false; + reinit_completion(&st->buf_ready); + ret = serdev_device_write(serdev, cmd_buf, MHZ19B_CMD_SIZE, 0); if (ret < 0) return ret; @@ -121,6 +127,9 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg) if (!ret) return -ETIMEDOUT; + if (st->buf_overflow) + return -EMSGSIZE; + if (st->buf[8] != mhz19b_get_checksum(st->buf)) { dev_err(dev, "checksum err"); return -EINVAL; @@ -240,6 +249,14 @@ static size_t mhz19b_receive_buf(struct serdev_device *serdev, { struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); struct mhz19b_state *st = iio_priv(indio_dev); + size_t remaining = MHZ19B_CMD_SIZE - st->buf_idx; + + if (len > remaining) { + st->buf_idx = 0; + st->buf_overflow = true; + complete(&st->buf_ready); + return len; + } memcpy(st->buf + st->buf_idx, data, len); st->buf_idx += len;