Commit d047cd8a authored by Rob Herring's avatar Rob Herring

scripts/dtc: Update to upstream version v1.6.0-2-g87a656ae5ff9

This adds the following commits from upstream:

87a656ae5ff9 check: Inform about missing ranges
73d6e9ecb417 libfdt: fix undefined behaviour in fdt_splice_()
2525da3dba9b Bump version to v1.6.0
62cb4ad286ff Execute tests on FreeBSD with Cirrus CI
1f9a41750883 tests: Allow running the testsuite on already installed binary / libraries
c5995ddf4c20 tests: Honour NO_YAML make variable
e4ce227e89d7 tests: Properly clean up .bak file from tests
9b75292c335c tests: Honour $(NO_PYTHON) flag from Makefile in run_tests.sh
6c253afd07d4 Encode $(NO_PYTHON) consistently with other variables
95ec8ef706bd tests: No need to explicitly pass $PYTHON from Make to run_tests.sh
2b5f62d109a2 tests: Let run_tests.sh run Python tests without Makefile assistance
76b43dcbd18a checks: Add 'dma-ranges' check
e5c92a4780c6 libfdt: Use VALID_INPUT for FDT_ERR_BADSTATE checks
e5cc26b68bc0 libfdt: Add support for disabling internal checks
28fd7590aad2 libfdt: Improve comments in some of the assumptions
fc207c32341b libfdt: Fix a few typos
0f61c72dedc4 libfdt: Allow exclusion of fdt_check_full()
f270f45fd5d2 libfdt: Add support for disabling ordering check/fixup
c18bae9a4c96 libfdt: Add support for disabling version checks
fc03c4a2e04e libfdt: Add support for disabling rollback handling
77563ae72b7c libfdt: Add support for disabling sanity checks
57bc6327b80b libfdt: Add support for disabling dtb checks
464962489dcc Add a way to control the level of checks in the code
0c5326cb2845 libfdt: De-inline fdt_header_size()
cc6a5a071504 Revert "yamltree: Ensure consistent bracketing of properties with phandles"
0e9225eb0dfe Remove redundant YYLOC global declaration
cab09eedd644 Move -DNO_VALGRIND into CPPFLAGS
0eb1cb0b531e Makefile: pass $(CFLAGS) also during dependency generation
Signed-off-by: default avatarRob Herring <robh@kernel.org>
parent 78154212
...@@ -352,7 +352,7 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, ...@@ -352,7 +352,7 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
FAIL(c, dti, node, "node has a reg or ranges property, but no unit name"); FAIL(c, dti, node, "node has a reg or ranges property, but no unit name");
} else { } else {
if (unitname[0]) if (unitname[0])
FAIL(c, dti, node, "node has a unit name, but no reg property"); FAIL(c, dti, node, "node has a unit name, but no reg or ranges property");
} }
} }
WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
...@@ -765,13 +765,15 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, ...@@ -765,13 +765,15 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
{ {
struct property *prop; struct property *prop;
int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
const char *ranges = c->data;
prop = get_property(node, "ranges"); prop = get_property(node, ranges);
if (!prop) if (!prop)
return; return;
if (!node->parent) { if (!node->parent) {
FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property"); FAIL_PROP(c, dti, node, prop, "Root node has a \"%s\" property",
ranges);
return; return;
} }
...@@ -783,23 +785,24 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, ...@@ -783,23 +785,24 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
if (prop->val.len == 0) { if (prop->val.len == 0) {
if (p_addr_cells != c_addr_cells) if (p_addr_cells != c_addr_cells)
FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
"#address-cells (%d) differs from %s (%d)", "#address-cells (%d) differs from %s (%d)",
c_addr_cells, node->parent->fullpath, ranges, c_addr_cells, node->parent->fullpath,
p_addr_cells); p_addr_cells);
if (p_size_cells != c_size_cells) if (p_size_cells != c_size_cells)
FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
"#size-cells (%d) differs from %s (%d)", "#size-cells (%d) differs from %s (%d)",
c_size_cells, node->parent->fullpath, ranges, c_size_cells, node->parent->fullpath,
p_size_cells); p_size_cells);
} else if ((prop->val.len % entrylen) != 0) { } else if ((prop->val.len % entrylen) != 0) {
FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) " FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
"(parent #address-cells == %d, child #address-cells == %d, " "(parent #address-cells == %d, child #address-cells == %d, "
"#size-cells == %d)", prop->val.len, "#size-cells == %d)", ranges, prop->val.len,
p_addr_cells, c_addr_cells, c_size_cells); p_addr_cells, c_addr_cells, c_size_cells);
} }
} }
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); WARNING(ranges_format, check_ranges_format, "ranges", &addr_size_cells);
WARNING(dma_ranges_format, check_ranges_format, "dma-ranges", &addr_size_cells);
static const struct bus_type pci_bus = { static const struct bus_type pci_bus = {
.name = "PCI", .name = "PCI",
...@@ -1780,7 +1783,7 @@ static struct check *check_table[] = { ...@@ -1780,7 +1783,7 @@ static struct check *check_table[] = {
&property_name_chars_strict, &property_name_chars_strict,
&node_name_chars_strict, &node_name_chars_strict,
&addr_size_cells, &reg_format, &ranges_format, &addr_size_cells, &reg_format, &ranges_format, &dma_ranges_format,
&unit_address_vs_reg, &unit_address_vs_reg,
&unit_address_format, &unit_address_format,
......
...@@ -23,7 +23,6 @@ LINECOMMENT "//".*\n ...@@ -23,7 +23,6 @@ LINECOMMENT "//".*\n
#include "srcpos.h" #include "srcpos.h"
#include "dtc-parser.tab.h" #include "dtc-parser.tab.h"
YYLTYPE yylloc;
extern bool treesource_error; extern bool treesource_error;
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */ /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
......
...@@ -19,15 +19,21 @@ int32_t fdt_ro_probe_(const void *fdt) ...@@ -19,15 +19,21 @@ int32_t fdt_ro_probe_(const void *fdt)
{ {
uint32_t totalsize = fdt_totalsize(fdt); uint32_t totalsize = fdt_totalsize(fdt);
if (can_assume(VALID_DTB))
return totalsize;
if (fdt_magic(fdt) == FDT_MAGIC) { if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */ /* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) if (!can_assume(LATEST)) {
return -FDT_ERR_BADVERSION; if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION;
return -FDT_ERR_BADVERSION; if (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) { } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */ /* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0) if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE; return -FDT_ERR_BADSTATE;
} else { } else {
return -FDT_ERR_BADMAGIC; return -FDT_ERR_BADMAGIC;
...@@ -70,44 +76,59 @@ size_t fdt_header_size_(uint32_t version) ...@@ -70,44 +76,59 @@ size_t fdt_header_size_(uint32_t version)
return FDT_V17_SIZE; return FDT_V17_SIZE;
} }
size_t fdt_header_size(const void *fdt)
{
return can_assume(LATEST) ? FDT_V17_SIZE :
fdt_header_size_(fdt_version(fdt));
}
int fdt_check_header(const void *fdt) int fdt_check_header(const void *fdt)
{ {
size_t hdrsize; size_t hdrsize;
if (fdt_magic(fdt) != FDT_MAGIC) if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC; return -FDT_ERR_BADMAGIC;
if (!can_assume(LATEST)) {
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|| (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION))
return -FDT_ERR_BADVERSION;
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
return -FDT_ERR_BADVERSION;
}
hdrsize = fdt_header_size(fdt); hdrsize = fdt_header_size(fdt);
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) if (!can_assume(VALID_DTB)) {
|| (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
return -FDT_ERR_BADVERSION;
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
return -FDT_ERR_BADVERSION;
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
/* Bounds check memrsv block */ if ((fdt_totalsize(fdt) < hdrsize)
if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt))) || (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED; return -FDT_ERR_TRUNCATED;
/* Bounds check structure block */ /* Bounds check memrsv block */
if (fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt), if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt))) fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED; return -FDT_ERR_TRUNCATED;
} else { }
if (!can_assume(VALID_DTB)) {
/* Bounds check structure block */
if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
} else {
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
}
/* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt), if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt), fdt_off_dt_strings(fdt),
fdt_size_dt_struct(fdt))) fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED; return -FDT_ERR_TRUNCATED;
} }
/* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED;
return 0; return 0;
} }
...@@ -115,12 +136,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) ...@@ -115,12 +136,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{ {
unsigned absoffset = offset + fdt_off_dt_struct(fdt); unsigned absoffset = offset + fdt_off_dt_struct(fdt);
if ((absoffset < offset) if (!can_assume(VALID_INPUT))
|| ((absoffset + len) < absoffset) if ((absoffset < offset)
|| (absoffset + len) > fdt_totalsize(fdt)) || ((absoffset + len) < absoffset)
return NULL; || (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (fdt_version(fdt) >= 0x11) if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
if (((offset + len) < offset) if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt))) || ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL; return NULL;
...@@ -137,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) ...@@ -137,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*nextoffset = -FDT_ERR_TRUNCATED; *nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (!tagp) if (!can_assume(VALID_DTB) && !tagp)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp); tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE; offset += FDT_TAGSIZE;
...@@ -149,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) ...@@ -149,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do { do {
p = fdt_offset_ptr(fdt, offset++, 1); p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0')); } while (p && (*p != '\0'));
if (!p) if (!can_assume(VALID_DTB) && !p)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
break; break;
case FDT_PROP: case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!lenp) if (!can_assume(VALID_DTB) && !lenp)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
/* skip-name offset, length and value */ /* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp); + fdt32_to_cpu(*lenp);
if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && if (!can_assume(LATEST) &&
fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
((offset - fdt32_to_cpu(*lenp)) % 8) != 0) ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4; offset += 4;
break; break;
...@@ -183,6 +206,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) ...@@ -183,6 +206,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
int fdt_check_node_offset_(const void *fdt, int offset) int fdt_check_node_offset_(const void *fdt, int offset)
{ {
if (can_assume(VALID_INPUT))
return offset;
if ((offset < 0) || (offset % FDT_TAGSIZE) if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
return -FDT_ERR_BADOFFSET; return -FDT_ERR_BADOFFSET;
......
...@@ -33,17 +33,26 @@ static int fdt_nodename_eq_(const void *fdt, int offset, ...@@ -33,17 +33,26 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{ {
int32_t totalsize = fdt_ro_probe_(fdt); int32_t totalsize;
uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt); uint32_t absoffset;
size_t len; size_t len;
int err; int err;
const char *s, *n; const char *s, *n;
if (can_assume(VALID_INPUT)) {
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
if (lenp)
*lenp = strlen(s);
return s;
}
totalsize = fdt_ro_probe_(fdt);
err = totalsize; err = totalsize;
if (totalsize < 0) if (totalsize < 0)
goto fail; goto fail;
err = -FDT_ERR_BADOFFSET; err = -FDT_ERR_BADOFFSET;
absoffset = stroffset + fdt_off_dt_strings(fdt);
if (absoffset >= totalsize) if (absoffset >= totalsize)
goto fail; goto fail;
len = totalsize - absoffset; len = totalsize - absoffset;
...@@ -51,7 +60,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) ...@@ -51,7 +60,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
if (fdt_magic(fdt) == FDT_MAGIC) { if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0) if (stroffset < 0)
goto fail; goto fail;
if (fdt_version(fdt) >= 17) { if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
if (stroffset >= fdt_size_dt_strings(fdt)) if (stroffset >= fdt_size_dt_strings(fdt))
goto fail; goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len) if ((fdt_size_dt_strings(fdt) - stroffset) < len)
...@@ -151,10 +160,13 @@ static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) ...@@ -151,10 +160,13 @@ static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
int offset = n * sizeof(struct fdt_reserve_entry); int offset = n * sizeof(struct fdt_reserve_entry);
int absoffset = fdt_off_mem_rsvmap(fdt) + offset; int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
if (absoffset < fdt_off_mem_rsvmap(fdt)) if (!can_assume(VALID_INPUT)) {
return NULL; if (absoffset < fdt_off_mem_rsvmap(fdt))
if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry)) return NULL;
return NULL; if (absoffset > fdt_totalsize(fdt) -
sizeof(struct fdt_reserve_entry))
return NULL;
}
return fdt_mem_rsv_(fdt, n); return fdt_mem_rsv_(fdt, n);
} }
...@@ -164,7 +176,7 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) ...@@ -164,7 +176,7 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
FDT_RO_PROBE(fdt); FDT_RO_PROBE(fdt);
re = fdt_mem_rsv(fdt, n); re = fdt_mem_rsv(fdt, n);
if (!re) if (!can_assume(VALID_INPUT) && !re)
return -FDT_ERR_BADOFFSET; return -FDT_ERR_BADOFFSET;
*address = fdt64_ld(&re->address); *address = fdt64_ld(&re->address);
...@@ -295,7 +307,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) ...@@ -295,7 +307,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
nameptr = nh->name; nameptr = nh->name;
if (fdt_version(fdt) < 0x10) { if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
/* /*
* For old FDT versions, match the naming conventions of V16: * For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree * give only the leaf name (after all /). The actual tree
...@@ -346,7 +358,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, ...@@ -346,7 +358,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int err; int err;
const struct fdt_property *prop; const struct fdt_property *prop;
if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) { if (!can_assume(VALID_INPUT) &&
(err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp) if (lenp)
*lenp = err; *lenp = err;
return NULL; return NULL;
...@@ -367,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, ...@@ -367,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
/* Prior to version 16, properties may need realignment /* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */ * and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) { if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp) if (lenp)
*lenp = -FDT_ERR_BADVERSION; *lenp = -FDT_ERR_BADVERSION;
return NULL; return NULL;
...@@ -388,7 +401,8 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, ...@@ -388,7 +401,8 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
(offset = fdt_next_property_offset(fdt, offset))) { (offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop; const struct fdt_property *prop;
if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) { prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
offset = -FDT_ERR_INTERNAL; offset = -FDT_ERR_INTERNAL;
break; break;
} }
...@@ -413,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, ...@@ -413,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
{ {
/* Prior to version 16, properties may need realignment /* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */ * and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) { if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp) if (lenp)
*lenp = -FDT_ERR_BADVERSION; *lenp = -FDT_ERR_BADVERSION;
return NULL; return NULL;
...@@ -444,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, ...@@ -444,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
return NULL; return NULL;
/* Handle realignment */ /* Handle realignment */
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
fdt32_ld(&prop->len) >= 8) (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4; return prop->data + 4;
return prop->data; return prop->data;
} }
...@@ -461,19 +475,24 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, ...@@ -461,19 +475,24 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
if (namep) { if (namep) {
const char *name; const char *name;
int namelen; int namelen;
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
&namelen); if (!can_assume(VALID_INPUT)) {
if (!name) { name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
if (lenp) &namelen);
*lenp = namelen; if (!name) {
return NULL; if (lenp)
*lenp = namelen;
return NULL;
}
*namep = name;
} else {
*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
} }
*namep = name;
} }
/* Handle realignment */ /* Handle realignment */
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
fdt32_ld(&prop->len) >= 8) (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4; return prop->data + 4;
return prop->data; return prop->data;
} }
...@@ -598,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, ...@@ -598,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
} }
} }
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) if (!can_assume(VALID_INPUT)) {
return -FDT_ERR_BADOFFSET; if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADOFFSET;
return -FDT_ERR_BADSTRUCTURE; else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
}
return offset; /* error from fdt_next_node() */ return offset; /* error from fdt_next_node() */
} }
...@@ -613,7 +634,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset) ...@@ -613,7 +634,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err) if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL; return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
-FDT_ERR_INTERNAL;
return nodedepth; return nodedepth;
} }
...@@ -833,66 +855,3 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, ...@@ -833,66 +855,3 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
return offset; /* error from fdt_next_node() */ return offset; /* error from fdt_next_node() */
} }
int fdt_check_full(const void *fdt, size_t bufsize)
{
int err;
int num_memrsv;
int offset, nextoffset = 0;
uint32_t tag;
unsigned depth = 0;
const void *prop;
const char *propname;
if (bufsize < FDT_V1_SIZE)
return -FDT_ERR_TRUNCATED;
err = fdt_check_header(fdt);
if (err != 0)
return err;
if (bufsize < fdt_totalsize(fdt))
return -FDT_ERR_TRUNCATED;
num_memrsv = fdt_num_mem_rsv(fdt);
if (num_memrsv < 0)
return num_memrsv;
while (1) {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
if (nextoffset < 0)
return nextoffset;
switch (tag) {
case FDT_NOP:
break;
case FDT_END:
if (depth != 0)
return -FDT_ERR_BADSTRUCTURE;
return 0;
case FDT_BEGIN_NODE:
depth++;
if (depth > INT_MAX)
return -FDT_ERR_BADSTRUCTURE;
break;
case FDT_END_NODE:
if (depth == 0)
return -FDT_ERR_BADSTRUCTURE;
depth--;
break;
case FDT_PROP:
prop = fdt_getprop_by_offset(fdt, offset, &propname,
&err);
if (!prop)
return err;
break;
default:
return -FDT_ERR_INTERNAL;
}
}
}
...@@ -24,14 +24,16 @@ static int fdt_blocks_misordered_(const void *fdt, ...@@ -24,14 +24,16 @@ static int fdt_blocks_misordered_(const void *fdt,
static int fdt_rw_probe_(void *fdt) static int fdt_rw_probe_(void *fdt)
{ {
if (can_assume(VALID_DTB))
return 0;
FDT_RO_PROBE(fdt); FDT_RO_PROBE(fdt);
if (fdt_version(fdt) < 17) if (!can_assume(LATEST) && fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION; return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt))) fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT; return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17) if (!can_assume(LATEST) && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17); fdt_set_version(fdt, 17);
return 0; return 0;
...@@ -44,7 +46,7 @@ static int fdt_rw_probe_(void *fdt) ...@@ -44,7 +46,7 @@ static int fdt_rw_probe_(void *fdt)
return err_; \ return err_; \
} }
static inline int fdt_data_size_(void *fdt) static inline unsigned int fdt_data_size_(void *fdt)
{ {
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
} }
...@@ -52,15 +54,16 @@ static inline int fdt_data_size_(void *fdt) ...@@ -52,15 +54,16 @@ static inline int fdt_data_size_(void *fdt)
static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{ {
char *p = splicepoint; char *p = splicepoint;
char *end = (char *)fdt + fdt_data_size_(fdt); unsigned int dsize = fdt_data_size_(fdt);
size_t soff = p - (char *)fdt;
if (((p + oldlen) < p) || ((p + oldlen) > end)) if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
return -FDT_ERR_BADOFFSET; return -FDT_ERR_BADOFFSET;
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) if ((p < (char *)fdt) || (dsize + newlen < oldlen))
return -FDT_ERR_BADOFFSET; return -FDT_ERR_BADOFFSET;
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) if (dsize - oldlen + newlen > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen); memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
return 0; return 0;
} }
...@@ -112,6 +115,15 @@ static int fdt_splice_string_(void *fdt, int newlen) ...@@ -112,6 +115,15 @@ static int fdt_splice_string_(void *fdt, int newlen)
return 0; return 0;
} }
/**
* fdt_find_add_string_() - Find or allocate a string
*
* @fdt: pointer to the device tree to check/adjust
* @s: string to find/add
* @allocated: Set to 0 if the string was found, 1 if not found and so
* allocated. Ignored if can_assume(NO_ROLLBACK)
* @return offset of string in the string table (whether found or added)
*/
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{ {
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
...@@ -120,7 +132,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) ...@@ -120,7 +132,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
int len = strlen(s) + 1; int len = strlen(s) + 1;
int err; int err;
*allocated = 0; if (!can_assume(NO_ROLLBACK))
*allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p) if (p)
...@@ -132,7 +145,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) ...@@ -132,7 +145,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
if (err) if (err)
return err; return err;
*allocated = 1; if (!can_assume(NO_ROLLBACK))
*allocated = 1;
memcpy(new, s, len); memcpy(new, s, len);
return (new - strtab); return (new - strtab);
...@@ -206,7 +220,8 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, ...@@ -206,7 +220,8 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
err = fdt_splice_struct_(fdt, *prop, 0, proplen); err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err) { if (err) {
if (allocated) /* Delete the string if we failed to add it */
if (!can_assume(NO_ROLLBACK) && allocated)
fdt_del_last_string_(fdt, name); fdt_del_last_string_(fdt, name);
return err; return err;
} }
...@@ -411,7 +426,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) ...@@ -411,7 +426,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry); * sizeof(struct fdt_reserve_entry);
if (fdt_version(fdt) >= 17) { if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt); struct_size = fdt_size_dt_struct(fdt);
} else { } else {
struct_size = 0; struct_size = 0;
...@@ -421,7 +436,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) ...@@ -421,7 +436,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return struct_size; return struct_size;
} }
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { if (can_assume(LIBFDT_ORDER) |
!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */ /* no further work necessary */
err = fdt_move(fdt, buf, bufsize); err = fdt_move(fdt, buf, bufsize);
if (err) if (err)
......
...@@ -12,10 +12,13 @@ ...@@ -12,10 +12,13 @@
static int fdt_sw_probe_(void *fdt) static int fdt_sw_probe_(void *fdt)
{ {
if (fdt_magic(fdt) == FDT_MAGIC) if (!can_assume(VALID_INPUT)) {
return -FDT_ERR_BADSTATE; if (fdt_magic(fdt) == FDT_MAGIC)
else if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADSTATE;
return -FDT_ERR_BADMAGIC; else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
}
return 0; return 0;
} }
...@@ -38,7 +41,7 @@ static int fdt_sw_probe_memrsv_(void *fdt) ...@@ -38,7 +41,7 @@ static int fdt_sw_probe_memrsv_(void *fdt)
if (err) if (err)
return err; return err;
if (fdt_off_dt_strings(fdt) != 0) if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE; return -FDT_ERR_BADSTATE;
return 0; return 0;
} }
...@@ -64,7 +67,8 @@ static int fdt_sw_probe_struct_(void *fdt) ...@@ -64,7 +67,8 @@ static int fdt_sw_probe_struct_(void *fdt)
if (err) if (err)
return err; return err;
if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) if (!can_assume(VALID_INPUT) &&
fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
return -FDT_ERR_BADSTATE; return -FDT_ERR_BADSTATE;
return 0; return 0;
} }
...@@ -151,7 +155,8 @@ int fdt_resize(void *fdt, void *buf, int bufsize) ...@@ -151,7 +155,8 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt); tailsize = fdt_size_dt_strings(fdt);
if ((headsize + tailsize) > fdt_totalsize(fdt)) if (!can_assume(VALID_DTB) &&
headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL; return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > bufsize) if ((headsize + tailsize) > bufsize)
......
...@@ -266,11 +266,12 @@ fdt_set_hdr_(size_dt_struct); ...@@ -266,11 +266,12 @@ fdt_set_hdr_(size_dt_struct);
* fdt_header_size - return the size of the tree's header * fdt_header_size - return the size of the tree's header
* @fdt: pointer to a flattened device tree * @fdt: pointer to a flattened device tree
*/ */
size_t fdt_header_size(const void *fdt);
/**
* fdt_header_size_ - internal function which takes a version number
*/
size_t fdt_header_size_(uint32_t version); size_t fdt_header_size_(uint32_t version);
static inline size_t fdt_header_size(const void *fdt)
{
return fdt_header_size_(fdt_version(fdt));
}
/** /**
* fdt_check_header - sanity check a device tree header * fdt_check_header - sanity check a device tree header
......
...@@ -48,4 +48,126 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) ...@@ -48,4 +48,126 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
#define FDT_SW_MAGIC (~FDT_MAGIC) #define FDT_SW_MAGIC (~FDT_MAGIC)
/**********************************************************************/
/* Checking controls */
/**********************************************************************/
#ifndef FDT_ASSUME_MASK
#define FDT_ASSUME_MASK 0
#endif
/*
* Defines assumptions which can be enabled. Each of these can be enabled
* individually. For maximum safety, don't enable any assumptions!
*
* For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
* You should have another method of validating the device tree, such as a
* signature or hash check before using libfdt.
*
* For situations where security is not a concern it may be safe to enable
* ASSUME_SANE.
*/
enum {
/*
* This does essentially no checks. Only the latest device-tree
* version is correctly handled. Inconsistencies or errors in the device
* tree may cause undefined behaviour or crashes. Invalid parameters
* passed to libfdt may do the same.
*
* If an error occurs when modifying the tree it may leave the tree in
* an intermediate (but valid) state. As an example, adding a property
* where there is insufficient space may result in the property name
* being added to the string table even though the property itself is
* not added to the struct section.
*
* Only use this if you have a fully validated device tree with
* the latest supported version and wish to minimise code size.
*/
ASSUME_PERFECT = 0xff,
/*
* This assumes that the device tree is sane. i.e. header metadata
* and basic hierarchy are correct.
*
* With this assumption enabled, normal device trees produced by libfdt
* and the compiler should be handled safely. Malicious device trees and
* complete garbage may cause libfdt to behave badly or crash. Truncated
* device trees (e.g. those only partially loaded) can also cause
* problems.
*
* Note: Only checks that relate exclusively to the device tree itself
* (not the parameters passed to libfdt) are disabled by this
* assumption. This includes checking headers, tags and the like.
*/
ASSUME_VALID_DTB = 1 << 0,
/*
* This builds on ASSUME_VALID_DTB and further assumes that libfdt
* functions are called with valid parameters, i.e. not trigger
* FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
* extensive checking of parameters and the device tree, making various
* assumptions about correctness.
*
* It doesn't make sense to enable this assumption unless
* ASSUME_VALID_DTB is also enabled.
*/
ASSUME_VALID_INPUT = 1 << 1,
/*
* This disables checks for device-tree version and removes all code
* which handles older versions.
*
* Only enable this if you know you have a device tree with the latest
* version.
*/
ASSUME_LATEST = 1 << 2,
/*
* This assumes that it is OK for a failed addition to the device tree,
* due to lack of space or some other problem, to skip any rollback
* steps (such as dropping the property name from the string table).
* This is safe to enable in most circumstances, even though it may
* leave the tree in a sub-optimal state.
*/
ASSUME_NO_ROLLBACK = 1 << 3,
/*
* This assumes that the device tree components appear in a 'convenient'
* order, i.e. the memory reservation block first, then the structure
* block and finally the string block.
*
* This order is not specified by the device-tree specification,
* but is expected by libfdt. The device-tree compiler always created
* device trees with this order.
*
* This assumption disables a check in fdt_open_into() and removes the
* ability to fix the problem there. This is safe if you know that the
* device tree is correctly ordered. See fdt_blocks_misordered_().
*/
ASSUME_LIBFDT_ORDER = 1 << 4,
/*
* This assumes that libfdt itself does not have any internal bugs. It
* drops certain checks that should never be needed unless libfdt has an
* undiscovered bug.
*
* This can generally be considered safe to enable.
*/
ASSUME_LIBFDT_FLAWLESS = 1 << 5,
};
/**
* can_assume_() - check if a particular assumption is enabled
*
* @mask: Mask to check (ASSUME_...)
* @return true if that assumption is enabled, else false
*/
static inline bool can_assume_(int mask)
{
return FDT_ASSUME_MASK & mask;
}
/** helper macros for checking assumptions */
#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)
#endif /* LIBFDT_INTERNAL_H */ #endif /* LIBFDT_INTERNAL_H */
#define DTC_VERSION "DTC 1.5.0-gc40aeb60" #define DTC_VERSION "DTC 1.6.0-g87a656ae"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment