Browse Source

checks: Fix crash in graph_child_address if 'reg' cell size != 1

If an endpoint node has a 'reg' property which consists of more than
one cell (4 bytes) and given that matching '#address-cells' and '#size-cells'
properties are specified on the port node an assertion is triggered in
check_graph_child_address() before the relevant diagnostic checks in
check_graph_reg() (called by check_graph_port() and check_graph_endpoint()) are executed.

The issue is fixed by making graph_child_address depend on the
graph_port and graph_endpoint checks.

Additionally the assertion can also be triggered if the length of the
'reg' property is less than 4 bytes e.g. by specifying
'reg = "a";'. In that case however other warnings are produced
highlighting the malformed property before dtc crashes.

Example dts file triggering the issue:

/dts-v1/;
 / {
	bar: bar {
		port {
			bar_con: endpoint {
				remote-endpoint = <&foo_con>;
			};
		};
	};
	foo {
		port {
			#address-cells = <1>;
			#size-cells = <1>; // should always be 0
			foo_con: endpoint@1 {
				reg = <1 2>; // causes assertion failure instead of diagnostic
				remote-endpoint = <&bar_con>;
			};
		};
	};
};

Signed-off-by: Johannes Beisswenger <johannes.beisswenger@cetitec.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
main
Johannes Beisswenger 1 year ago committed by David Gibson
parent
commit
ea3b9a1d2c
  1. 50
      checks.c

50
checks.c

@ -1785,31 +1785,6 @@ static void check_graph_nodes(struct check *c, struct dt_info *dti, @@ -1785,31 +1785,6 @@ static void check_graph_nodes(struct check *c, struct dt_info *dti,
}
WARNING(graph_nodes, check_graph_nodes, NULL);

static void check_graph_child_address(struct check *c, struct dt_info *dti,
struct node *node)
{
int cnt = 0;
struct node *child;

if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
return;

for_each_child(node, child) {
struct property *prop = get_property(child, "reg");

/* No error if we have any non-zero unit address */
if (prop && propval_cell(prop) != 0)
return;

cnt++;
}

if (cnt == 1 && node->addr_cells != -1)
FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
node->children->name);
}
WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes);

static void check_graph_reg(struct check *c, struct dt_info *dti,
struct node *node)
{
@ -1900,6 +1875,31 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti, @@ -1900,6 +1875,31 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
}
WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);

static void check_graph_child_address(struct check *c, struct dt_info *dti,
struct node *node)
{
int cnt = 0;
struct node *child;

if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
return;

for_each_child(node, child) {
struct property *prop = get_property(child, "reg");

/* No error if we have any non-zero unit address */
if (prop && propval_cell(prop) != 0 )
return;

cnt++;
}

if (cnt == 1 && node->addr_cells != -1)
FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
node->children->name);
}
WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes, &graph_port, &graph_endpoint);

static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
&node_name_chars, &node_name_format, &property_name_chars,

Loading…
Cancel
Save