[PATCH] tlv: check incoming TLV headers for size
Sascha Hauer
s.hauer at pengutronix.de
Wed Mar 4 23:44:48 PST 2026
tlv_register_device() gets untrusted data in the incoming TLV header.
Add a size argument and check if the TLV is within the size boundaries
before processing it.
While at it check that the reserved field in the TLV header is set to
zero which is necessary should we later want to use it.
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
common/tlv/bus.c | 20 +++++++++++++++++++-
common/tlv/parser.c | 2 +-
common/tlv/register.c | 2 +-
include/tlv/tlv.h | 3 ++-
test/self/tlv.c | 4 ++--
5 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/common/tlv/bus.c b/common/tlv/bus.c
index 29b6ce87bf..9c06baf360 100644
--- a/common/tlv/bus.c
+++ b/common/tlv/bus.c
@@ -14,9 +14,23 @@ static void tlv_devinfo(struct device *dev)
printf("Magic: %08x\n", tlvdev->magic);
}
+static int tlv_header_check(struct tlv_header *header, size_t size)
+{
+ if (size < sizeof(*header))
+ return -ENODATA;
+
+ if (header->reserved != 0)
+ return -EINVAL;
+
+ if (size < tlv_total_len(header))
+ return -ENODATA;
+
+ return 0;
+}
+
static struct device_node *tlv_parent_node;
-struct tlv_device *tlv_register_device(struct tlv_header *header,
+struct tlv_device *tlv_register_device(struct tlv_header *header, size_t size,
struct device *parent)
{
struct tlv_device *tlvdev;
@@ -25,6 +39,10 @@ struct tlv_device *tlv_register_device(struct tlv_header *header,
static int id = 0;
int ret;
+ ret = tlv_header_check(header, size);
+ if (ret)
+ return ERR_PTR(ret);
+
tlvdev = xzalloc(sizeof(*tlvdev));
dev = &tlvdev->dev;
diff --git a/common/tlv/parser.c b/common/tlv/parser.c
index 010e4cce38..4c0b6b5c6f 100644
--- a/common/tlv/parser.c
+++ b/common/tlv/parser.c
@@ -165,7 +165,7 @@ struct tlv_device *tlv_register_device_by_path(const char *path, struct device *
if (IS_ERR(header))
return ERR_CAST(header);
- tlvdev = tlv_register_device(header, parent);
+ tlvdev = tlv_register_device(header, size, parent);
if (IS_ERR(tlvdev))
free(header);
diff --git a/common/tlv/register.c b/common/tlv/register.c
index a6d95fb8e0..66dd38f5d4 100644
--- a/common/tlv/register.c
+++ b/common/tlv/register.c
@@ -56,7 +56,7 @@ static int tlv_probe_from_compatible(struct device *dev)
goto err;
}
- tlvdev = tlv_register_device(header, dev);
+ tlvdev = tlv_register_device(header, size, dev);
if (IS_ERR(tlvdev)) {
ret = PTR_ERR(tlvdev);
goto err;
diff --git a/include/tlv/tlv.h b/include/tlv/tlv.h
index 8b4ee1b399..c2812398dc 100644
--- a/include/tlv/tlv.h
+++ b/include/tlv/tlv.h
@@ -61,7 +61,8 @@ static inline struct device_node *tlv_of_node(struct tlv_device *tlvdev)
return tlvdev->dev.device_node;
}
-struct tlv_device *tlv_register_device(struct tlv_header *header, struct device *parent);
+struct tlv_device *tlv_register_device(struct tlv_header *header, size_t size,
+ struct device *parent);
static inline struct tlv_header *tlv_device_header(struct tlv_device *tlvdev)
{
return tlvdev->dev.platform_data;
diff --git a/test/self/tlv.c b/test/self/tlv.c
index 8f1b810b5a..cefa8b4a7a 100644
--- a/test/self/tlv.c
+++ b/test/self/tlv.c
@@ -60,14 +60,14 @@ static void test_lxa_tlv(void)
return;
}
- cpu_tlvdev = tlv_register_device(cpu_blob, NULL);
+ cpu_tlvdev = tlv_register_device(cpu_blob, cpu_bloblen, NULL);
if (IS_ERR(cpu_tlvdev)) {
free(cpu_blob);
failed_tests++;
skipped_tests++;
}
- io_tlvdev = tlv_register_device(io_blob, NULL);
+ io_tlvdev = tlv_register_device(io_blob, io_bloblen, NULL);
if (IS_ERR(io_tlvdev)) {
free(io_blob);
failed_tests++;
--
2.47.3
More information about the barebox
mailing list