diff options
author | Anton Blanchard <anton@samba.org> | 2016-01-03 08:43:35 +1100 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2016-02-19 01:08:46 +1100 |
commit | 2e53f9d2f0a8faab6cec0d78958d52c155f6c6eb (patch) | |
tree | 1c498c162608ead00ad8e841967b426df45293b4 | |
parent | b06e55c88b9b922ff7e25cd62a4709b65524f0fc (diff) | |
download | dtc-2e53f9d2f0a8faab6cec0d78958d52c155f6c6eb.zip dtc-2e53f9d2f0a8faab6cec0d78958d52c155f6c6eb.tar.gz dtc-2e53f9d2f0a8faab6cec0d78958d52c155f6c6eb.tar.bz2 |
Catch unsigned 32bit overflow when parsing flattened device tree offsets
We have a couple of checks of the form:
if (offset+size > totalsize)
die();
We need to check that offset+size doesn't overflow, otherwise the check
will pass, and we may access past totalsize.
Found with AFL.
Signed-off-by: Anton Blanchard <anton@samba.org>
[Added a testcase]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
-rw-r--r-- | flattree.c | 4 | ||||
-rw-r--r-- | tests/dumptrees.c | 1 | ||||
-rwxr-xr-x | tests/run_tests.sh | 2 | ||||
-rw-r--r-- | tests/testdata.h | 1 | ||||
-rw-r--r-- | tests/trees.S | 31 |
5 files changed, 37 insertions, 2 deletions
@@ -889,7 +889,7 @@ struct boot_info *dt_from_blob(const char *fname) if (version >= 3) { uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings); - if (off_str+size_str > totalsize) + if ((off_str+size_str < off_str) || (off_str+size_str > totalsize)) die("String table extends past total size\n"); inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str); } else { @@ -898,7 +898,7 @@ struct boot_info *dt_from_blob(const char *fname) if (version >= 17) { size_dt = fdt32_to_cpu(fdt->size_dt_struct); - if (off_dt+size_dt > totalsize) + if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize)) die("Structure block extends past total size\n"); } diff --git a/tests/dumptrees.c b/tests/dumptrees.c index bebf553..a49dbfa 100644 --- a/tests/dumptrees.c +++ b/tests/dumptrees.c @@ -36,6 +36,7 @@ struct { #define TREE(name) { &_##name, #name ".dtb" } TREE(test_tree1), TREE(bad_node_char), TREE(bad_node_format), TREE(bad_prop_char), + TREE(ovf_size_strings), }; #define NUM_TREES (sizeof(trees) / sizeof(trees[0])) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 8863c9a..710f2ac 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -295,6 +295,8 @@ libfdt_tests () { run_dtc_test -I dts -O dtb nul-in-escape.dts run_wrap_error_test $DTC nul-in-line-info1.dts run_wrap_error_test $DTC nul-in-line-info2.dts + + run_wrap_error_test $DTC -I dtb -O dts -o /dev/null ovf_size_strings.dtb } dtc_tests () { diff --git a/tests/testdata.h b/tests/testdata.h index ce715e4..576974d 100644 --- a/tests/testdata.h +++ b/tests/testdata.h @@ -33,4 +33,5 @@ extern struct fdt_header _truncated_property; extern struct fdt_header _bad_node_char; extern struct fdt_header _bad_node_format; extern struct fdt_header _bad_prop_char; +extern struct fdt_header _ovf_size_strings; #endif /* ! __ASSEMBLY */ diff --git a/tests/trees.S b/tests/trees.S index 2389cd3..3d24aa2 100644 --- a/tests/trees.S +++ b/tests/trees.S @@ -209,3 +209,34 @@ bad_prop_char_strings: STRING(bad_prop_char, prop, "prop$erty") bad_prop_char_strings_end: bad_prop_char_end: + + + /* overflow_size_strings */ + .balign 8 + .globl _ovf_size_strings +_ovf_size_strings: +ovf_size_strings: + FDTLONG(FDT_MAGIC) + FDTLONG(ovf_size_strings_end - ovf_size_strings) + FDTLONG(ovf_size_strings_struct - ovf_size_strings) + FDTLONG(ovf_size_strings_strings - ovf_size_strings) + FDTLONG(ovf_size_strings_rsvmap - ovf_size_strings) + FDTLONG(0x11) + FDTLONG(0x10) + FDTLONG(0) + FDTLONG(0xffffffff) + FDTLONG(ovf_size_strings_struct_end - ovf_size_strings_struct) + EMPTY_RSVMAP(ovf_size_strings) + +ovf_size_strings_struct: + BEGIN_NODE("") + PROP_INT(ovf_size_strings, bad_string, 0) + END_NODE + FDTLONG(FDT_END) +ovf_size_strings_struct_end: + +ovf_size_strings_strings: + STRING(ovf_size_strings, x, "x") + ovf_size_strings_bad_string = ovf_size_strings_strings + 0x10000000 +ovf_size_strings_strings_end: +ovf_size_strings_end: |