[PATCH] firmware: tegra: bpmp: reject truncated debugfs entries

Pengpeng Hou posted 1 patch 1 week, 3 days ago
drivers/firmware/tegra/bpmp-debugfs.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
[PATCH] firmware: tegra: bpmp: reject truncated debugfs entries
Posted by Pengpeng Hou 1 week, 3 days ago
The BPMP debugfs response parser reads u32 fields and NUL-terminated
names from a size-delimited reply. seqbuf_read() currently clamps a
request to the remaining input bytes and can return success after a
short read. Consequently, a truncated u32 can be partially copied and
the directory parser can continue with an incomplete field.

seqbuf_read_str() also moves the cursor one byte beyond the current
range when no NUL terminator exists, and reports the failure only after
changing the parser state.

Make fixed-width reads fail when the full request is unavailable and
require a terminator within the current range before advancing the
cursor. Use a signed return type for the status helper so its error
contract matches its callers.

Fixes: f2381f652266 ("firmware: tegra: Add BPMP debugfs support")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 drivers/firmware/tegra/bpmp-debugfs.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c
index 33c6300af964..bb2ce5be2e78 100644
--- a/drivers/firmware/tegra/bpmp-debugfs.c
+++ b/drivers/firmware/tegra/bpmp-debugfs.c
@@ -32,7 +32,7 @@ static size_t seqbuf_avail(struct seqbuf *seqbuf)
 	return seqbuf->pos < seqbuf->size ? seqbuf->size - seqbuf->pos : 0;
 }
 
-static size_t seqbuf_status(struct seqbuf *seqbuf)
+static int seqbuf_status(struct seqbuf *seqbuf)
 {
 	return seqbuf->pos <= seqbuf->size ? 0 : -EOVERFLOW;
 }
@@ -44,7 +44,9 @@ static int seqbuf_eof(struct seqbuf *seqbuf)
 
 static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte)
 {
-	nbyte = min(nbyte, seqbuf_avail(seqbuf));
+	if (nbyte > seqbuf_avail(seqbuf))
+		return -EOVERFLOW;
+
 	memcpy(buf, seqbuf->buf + seqbuf->pos, nbyte);
 	seqbuf->pos += nbyte;
 	return seqbuf_status(seqbuf);
@@ -57,9 +59,16 @@ static int seqbuf_read_u32(struct seqbuf *seqbuf, u32 *v)
 
 static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str)
 {
+	size_t avail;
+	size_t len;
+
+	avail = seqbuf_avail(seqbuf);
 	*str = seqbuf->buf + seqbuf->pos;
-	seqbuf->pos += strnlen(*str, seqbuf_avail(seqbuf));
-	seqbuf->pos++;
+	len = strnlen(*str, avail);
+	if (len == avail)
+		return -EOVERFLOW;
+
+	seqbuf->pos += len + 1;
 	return seqbuf_status(seqbuf);
 }
 
-- 
2.43.0