[PATCH 15/27] libfdt: Tweak data handling to satisfy Coverity

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Feb 28 06:51:32 UTC 2020


From: David Gibson <david at gibson.dropbear.id.au>

In libfdt we often sanity test fdt_totalsize(fdt) fairly early, then
trust it (but *only* that header field) for the remainder of our work.
However, Coverity gets confused by this - it sees the byteswap in
fdt32_ld() and assumes that means it is coming from an untrusted source
everytime, resulting in many tainted data warnings.

Most of these end up with logic in fdt_get_string() as the unsafe
destination for this tainted data, so let's tweak the logic there to make
it clearer to Coverity that this is ok.

We add a sanity test on fdt_totalsize() to fdt_probe_ro_().  Because the
interface allows bare ints to be used for offsets, we already have the
assumption that totalsize must be 31-bits or less (2GiB would be a
ludicrously large fdt).  This makes this more explicit.

We also make fdt_probe_ro() return the size for convenience, and change the
logic in fdt_get_string() to keep it in a local so that Coverity can see
that it has already been bounds-checked.

Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
---
 cpukit/dtc/libfdt/fdt.c             |  9 +++++++--
 cpukit/dtc/libfdt/fdt_ro.c          | 11 ++++++-----
 cpukit/dtc/libfdt/libfdt_internal.h | 10 +++++-----
 3 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/cpukit/dtc/libfdt/fdt.c b/cpukit/dtc/libfdt/fdt.c
index 179168ec63..d6ce7c052d 100644
--- a/cpukit/dtc/libfdt/fdt.c
+++ b/cpukit/dtc/libfdt/fdt.c
@@ -15,8 +15,10 @@
  * that the given buffer contains what appears to be a flattened
  * device tree with sane information in its header.
  */
-int fdt_ro_probe_(const void *fdt)
+int32_t fdt_ro_probe_(const void *fdt)
 {
+	uint32_t totalsize = fdt_totalsize(fdt);
+
 	if (fdt_magic(fdt) == FDT_MAGIC) {
 		/* Complete tree */
 		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
@@ -31,7 +33,10 @@ int fdt_ro_probe_(const void *fdt)
 		return -FDT_ERR_BADMAGIC;
 	}
 
-	return 0;
+	if (totalsize < INT32_MAX)
+		return totalsize;
+	else
+		return -FDT_ERR_TRUNCATED;
 }
 
 static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
diff --git a/cpukit/dtc/libfdt/fdt_ro.c b/cpukit/dtc/libfdt/fdt_ro.c
index 6fd9ec170d..a5c2797cde 100644
--- a/cpukit/dtc/libfdt/fdt_ro.c
+++ b/cpukit/dtc/libfdt/fdt_ro.c
@@ -33,19 +33,20 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
 
 const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
 {
+	int32_t totalsize = fdt_ro_probe_(fdt);
 	uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
 	size_t len;
 	int err;
 	const char *s, *n;
 
-	err = fdt_ro_probe_(fdt);
-	if (err != 0)
+	err = totalsize;
+	if (totalsize < 0)
 		goto fail;
 
 	err = -FDT_ERR_BADOFFSET;
-	if (absoffset >= fdt_totalsize(fdt))
+	if (absoffset >= totalsize)
 		goto fail;
-	len = fdt_totalsize(fdt) - absoffset;
+	len = totalsize - absoffset;
 
 	if (fdt_magic(fdt) == FDT_MAGIC) {
 		if (stroffset < 0)
@@ -288,7 +289,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
 	const char *nameptr;
 	int err;
 
-	if (((err = fdt_ro_probe_(fdt)) != 0)
+	if (((err = fdt_ro_probe_(fdt)) < 0)
 	    || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
 			goto fail;
 
diff --git a/cpukit/dtc/libfdt/libfdt_internal.h b/cpukit/dtc/libfdt/libfdt_internal.h
index 7830e550c3..741eeb3150 100644
--- a/cpukit/dtc/libfdt/libfdt_internal.h
+++ b/cpukit/dtc/libfdt/libfdt_internal.h
@@ -11,11 +11,11 @@
 #define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE))
 
 int fdt_ro_probe_(const void *fdt);
-#define FDT_RO_PROBE(fdt)			\
-	{ \
-		int err_; \
-		if ((err_ = fdt_ro_probe_(fdt)) != 0)	\
-			return err_; \
+#define FDT_RO_PROBE(fdt)					\
+	{							\
+		int totalsize_;					\
+		if ((totalsize_ = fdt_ro_probe_(fdt)) < 0)	\
+			return totalsize_;			\
 	}
 
 int fdt_check_node_offset_(const void *fdt, int offset);
-- 
2.16.4



More information about the devel mailing list