Skip to contentSkip to conversation

libfdt: Fix bugs in fdt_get_path()

PATCH Applied David Gibson 3 participants 4 messages Aug 29, 2008 – Sep 25, 2008 1 message not in the archive

lore
Share & tools
lore
#0 lore raw

The current implementation of fdt_get_path() has a couple of bugs, fixed by this patch.

First, contrary to its documentation, on success it returns the length of the node's path, rather than 0. The testcase is correspondingly wrong, and the patch fixes this as well.

Second, in some circumstances, it will return -FDT_ERR_BADOFFSET instead of -FDT_ERR_NOSPACE when given insufficient buffer space. Specifically this happens when there is insufficient space even to hold the path's second last component. This behaviour is corrected, and the testcase updated to check it.

tests/get_path.c +7 -3
Index: dtc/tests/get_path.c
===================================================================
@@ -43,6 +43,8 @@ static void check_path_buf(void *fdt, co
 	memset(buf, POISON, sizeof(buf)); /* poison the buffer */
 
 	len = fdt_get_path(fdt, offset, buf, buflen);
+	verbose_printf("get_path() %s -> %d -> %s\n", path, offset, buf);
+
 	if (buflen <= pathlen) {
 		if (len != -FDT_ERR_NOSPACE)
 			FAIL("fdt_get_path([%d bytes]) returns %d with "
@@ -51,9 +53,9 @@ static void check_path_buf(void *fdt, co
 		if (len < 0)
 			FAIL("fdt_get_path([%d bytes]): %s", buflen,
 			     fdt_strerror(len));
-		if (len != pathlen)
-			FAIL("fdt_get_path([%d bytes]) reports length %d "
-			     "instead of %d", buflen, len, pathlen);
+		if (len != 0)
+			FAIL("fdt_get_path([%d bytes]) returns %d "
+			     "instead of 0", buflen, len);
 		if (strcmp(buf, path) != 0)
 			FAIL("fdt_get_path([%d bytes]) returns \"%s\" "
 			     "instead of \"%s\"", buflen, buf, path);
@@ -70,6 +72,8 @@ static void check_path(void *fdt, const 
 	check_path_buf(fdt, path, pathlen, 1024);
 	check_path_buf(fdt, path, pathlen, pathlen+1);
 	check_path_buf(fdt, path, pathlen, pathlen);
+	check_path_buf(fdt, path, pathlen, 0);
+	check_path_buf(fdt, path, pathlen, 2);
 }
 
 int main(int argc, char *argv[])
libfdt/fdt_ro.c +11 -12
Index: dtc/libfdt/fdt_ro.c
===================================================================
@@ -328,9 +328,6 @@ int fdt_get_path(const void *fdt, int no
 	for (offset = 0, depth = 0;
 	     (offset >= 0) && (offset <= nodeoffset);
 	     offset = fdt_next_node(fdt, offset, &depth)) {
-		if (pdepth < depth)
-			continue; /* overflowed buffer */
-
 		while (pdepth > depth) {
 			do {
 				p--;
@@ -338,14 +335,16 @@ int fdt_get_path(const void *fdt, int no
 			pdepth--;
 		}
 
-		name = fdt_get_name(fdt, offset, &namelen);
-		if (!name)
-			return namelen;
-		if ((p + namelen + 1) <= buflen) {
-			memcpy(buf + p, name, namelen);
-			p += namelen;
-			buf[p++] = '/';
-			pdepth++;
+		if (pdepth >= depth) {
+			name = fdt_get_name(fdt, offset, &namelen);
+			if (!name)
+				return namelen;
+			if ((p + namelen + 1) <= buflen) {
+				memcpy(buf + p, name, namelen);
+				p += namelen;
+				buf[p++] = '/';
+				pdepth++;
+			}
 		}
 
 		if (offset == nodeoffset) {
@@ -355,7 +354,7 @@ int fdt_get_path(const void *fdt, int no
 			if (p > 1) /* special case so that root path is "/", not "" */
 				p--;
 			buf[p] = '\0';
-			return p;
+			return 0;
 		}
 	}
 
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#1 lore raw

FYI, I propose to pick this up for the *NEXT* release of u-boot ("Yellow Submarine" ;-). My reasoning is that (1) the current window closes today, which makes me uncomfortable WRT putting in changes today and (2) this appears to be a latent bug (at worst, a misleading error message); I have not seen evidence that it is causing problems at the moment.

Best regards,
gvb

Quoted 99 lines · David Gibson

The current implementation of fdt_get_path() has a couple of bugs, fixed by this patch.

First, contrary to its documentation, on success it returns the length of the node's path, rather than 0. The testcase is correspondingly wrong, and the patch fixes this as well.

Second, in some circumstances, it will return -FDT_ERR_BADOFFSET instead of -FDT_ERR_NOSPACE when given insufficient buffer space. Specifically this happens when there is insufficient space even to hold the path's second last component. This behaviour is corrected, and the testcase updated to check it.

Index: dtc/tests/get_path.c
===================================================================

tests/get_path.c +7 -3
@@ -43,6 +43,8 @@ static void check_path_buf(void *fdt, co
 	memset(buf, POISON, sizeof(buf)); /* poison the buffer */
 
 	len = fdt_get_path(fdt, offset, buf, buflen);
+	verbose_printf("get_path() %s -> %d -> %s\n", path, offset, buf);
+
 	if (buflen <= pathlen) {
 		if (len != -FDT_ERR_NOSPACE)
 			FAIL("fdt_get_path([%d bytes]) returns %d with "
@@ -51,9 +53,9 @@ static void check_path_buf(void *fdt, co
 		if (len < 0)
 			FAIL("fdt_get_path([%d bytes]): %s", buflen,
 			     fdt_strerror(len));
-		if (len != pathlen)
-			FAIL("fdt_get_path([%d bytes]) reports length %d "
-			     "instead of %d", buflen, len, pathlen);
+		if (len != 0)
+			FAIL("fdt_get_path([%d bytes]) returns %d "
+			     "instead of 0", buflen, len);
 		if (strcmp(buf, path) != 0)
 			FAIL("fdt_get_path([%d bytes]) returns \"%s\" "
 			     "instead of \"%s\"", buflen, buf, path);
@@ -70,6 +72,8 @@ static void check_path(void *fdt, const 
 	check_path_buf(fdt, path, pathlen, 1024);
 	check_path_buf(fdt, path, pathlen, pathlen+1);
 	check_path_buf(fdt, path, pathlen, pathlen);
+	check_path_buf(fdt, path, pathlen, 0);
+	check_path_buf(fdt, path, pathlen, 2);
 }
 
 int main(int argc, char *argv[])

Index: dtc/libfdt/fdt_ro.c
===================================================================

libfdt/fdt_ro.c +11 -12
@@ -328,9 +328,6 @@ int fdt_get_path(const void *fdt, int no
 	for (offset = 0, depth = 0;
 	     (offset >= 0) && (offset <= nodeoffset);
 	     offset = fdt_next_node(fdt, offset, &depth)) {
-		if (pdepth < depth)
-			continue; /* overflowed buffer */
-
 		while (pdepth > depth) {
 			do {
 				p--;
@@ -338,14 +335,16 @@ int fdt_get_path(const void *fdt, int no
 			pdepth--;
 		}
 
-		name = fdt_get_name(fdt, offset, &namelen);
-		if (!name)
-			return namelen;
-		if ((p + namelen + 1) <= buflen) {
-			memcpy(buf + p, name, namelen);
-			p += namelen;
-			buf[p++] = '/';
-			pdepth++;
+		if (pdepth >= depth) {
+			name = fdt_get_name(fdt, offset, &namelen);
+			if (!name)
+				return namelen;
+			if ((p + namelen + 1) <= buflen) {
+				memcpy(buf + p, name, namelen);
+				p += namelen;
+				buf[p++] = '/';
+				pdepth++;
+			}
 		}
 
 		if (offset == nodeoffset) {
@@ -355,7 +354,7 @@ int fdt_get_path(const void *fdt, int no
 			if (p > 1) /* special case so that root path is "/", not "" */
 				p--;
 			buf[p] = '\0';
-			return p;
+			return 0;
 		}
 	}
 
#2 lore raw
Quoted 5 lines · Jerry Van Baren

FYI, I propose to pick this up for the *NEXT* release of u-boot ("Yellow Submarine" ;-). My reasoning is that (1) the current window closes today, which makes me uncomfortable WRT putting in changes today and (2) this appears to be a latent bug (at worst, a misleading error message); I have not seen evidence that it is causing problems at the moment.

Yeah, that seems reasonable. It's only an incorrect-error-code bug, although I'd class it a relatively important one within that class, since the distinction between NOSPACE and other errors typically does matter.

Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

A message that is not in the archive (sent off-list or not yet received): [email protected]

Applied
#4 lore raw
Quoted 7 lines

The current implementation of fdt_get_path() has a couple of bugs, fixed by this patch.

First, contrary to its documentation, on success it returns the length of the node's path, rather than 0. The testcase is correspondingly wrong, and the patch fixes this as well.

Quoted 7 lines

Second, in some circumstances, it will return -FDT_ERR_BADOFFSET instead of -FDT_ERR_NOSPACE when given insufficient buffer space. Specifically this happens when there is insufficient space even to hold the path's second last component. This behaviour is corrected, and the testcase updated to check it.

Applied.

Thanks,
jdl