mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH master 3/3] of: fdt: fix possibles overflows during parsing of invalid DTs
Date: Fri, 20 Oct 2023 09:23:16 +0200	[thread overview]
Message-ID: <20231020072316.2830850-3-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20231020072316.2830850-1-a.fatoum@pengutronix.de>

barebox may end up doing out of bound accesses if certain offsets in
parsed device trees exceed the total size of the flattened device tree
being parsed. Add some checks to early abort the parsing of such
invalid device trees.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/of/fdt.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 40 insertions(+), 8 deletions(-)

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 9d72fafd3669..a4b42eec1c46 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -14,8 +14,23 @@
 #include <memory.h>
 #include <linux/sizes.h>
 #include <linux/ctype.h>
+#include <linux/overflow.h>
+#include <linux/string_helpers.h>
 #include <linux/err.h>
 
+static inline bool __dt_ptr_ok(const struct fdt_header *fdt, const void *p,
+				  unsigned elem_size, unsigned elem_align)
+{
+	if (!p || (const void *)fdt > p || !PTR_IS_ALIGNED(p, elem_align) ||
+	     p + elem_size > (const void *)fdt + be32_to_cpu(fdt->totalsize)) {
+		pr_err("unflatten: offset overflows or misaligns FDT\n");
+		return false;
+	}
+
+	return true;
+}
+#define dt_ptr_ok(fdt, p) __dt_ptr_ok(fdt, p, sizeof(*(p)), __alignof__(*(p)))
+
 static inline uint32_t dt_struct_advance(struct fdt_header *f, uint32_t dt, int size)
 {
 	dt += size;
@@ -29,27 +44,38 @@ static inline uint32_t dt_struct_advance(struct fdt_header *f, uint32_t dt, int
 
 static inline char *dt_string(struct fdt_header *f, char *strstart, uint32_t ofs)
 {
+	char *str;
+
 	if (ofs > f->size_dt_strings)
 		return NULL;
-	else
-		return strstart + ofs;
+
+	str = strstart + ofs;
+
+	return string_is_terminated(str, f->size_dt_strings - ofs) ? str : NULL;
 }
 
 static int of_reservemap_num_entries(const struct fdt_header *fdt)
 {
-	const struct fdt_reserve_entry *r;
+	/*
+	 * FDT may violate spec mandated 8-byte alignment if unflattening it out of
+	 * a FIT image property, so play it safe here.
+	 */
+	const struct fdt_reserve_entry_unaligned {
+		fdt64_t address;
+		fdt64_t size;
+	} __packed *r;
 	int n = 0;
 
 	r = (void *)fdt + be32_to_cpu(fdt->off_mem_rsvmap);
 
-	while (r->size) {
+	while (dt_ptr_ok(fdt, r) && r->size) {
 		n++;
 		r++;
 		if (n == OF_MAX_RESERVE_MAP)
 			return -EINVAL;
 	}
 
-	return n;
+	return r->size == 0 ? n : -ESPIPE;
 }
 
 /**
@@ -135,12 +161,12 @@ static struct device_node *__of_unflatten_dtb(const void *infdt, int size,
 	if (f.totalsize > size)
 		return ERR_PTR(-EINVAL);
 
-	if (f.off_dt_struct + f.size_dt_struct > f.totalsize) {
+	if (size_add(f.off_dt_struct, f.size_dt_struct) > f.totalsize) {
 		pr_err("unflatten: dt size exceeds total size\n");
 		return ERR_PTR(-ESPIPE);
 	}
 
-	if (f.off_dt_strings + f.size_dt_strings > f.totalsize) {
+	if (size_add(f.off_dt_strings, f.size_dt_strings) > f.totalsize) {
 		pr_err("unflatten: string size exceeds total size\n");
 		return ERR_PTR(-ESPIPE);
 	}
@@ -157,7 +183,13 @@ static struct device_node *__of_unflatten_dtb(const void *infdt, int size,
 		goto err;
 
 	while (1) {
-		tag = be32_to_cpu(*(uint32_t *)(infdt + dt_struct));
+		__be32 *tagp = (uint32_t *)(infdt + dt_struct);
+		if (!dt_ptr_ok(infdt, tagp)) {
+			ret = -ESPIPE;
+			goto err;
+		}
+
+		tag = be32_to_cpu(*tagp);
 
 		switch (tag) {
 		case FDT_BEGIN_NODE:
-- 
2.39.2




  parent reply	other threads:[~2023-10-20  7:24 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-20  7:23 [PATCH master 1/3] include: linux/overflow.h: sync with upstream Ahmad Fatoum
2023-10-20  7:23 ` [PATCH master 2/3] include: import Linux string_is_terminated helper Ahmad Fatoum
2023-10-20  7:23 ` Ahmad Fatoum [this message]
2023-10-23 11:41 ` [PATCH master 1/3] include: linux/overflow.h: sync with upstream Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231020072316.2830850-3-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox