Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Apr 04, 2021 at 10:37:35PM -0500, Frank Rowand wrote:
> Hi Guenter,
> 
> Can you please test this patch to see if it prevents the crash on
> openrisc that you reported in
> https://lore.kernel.org/lkml/20210327224116.69309-1-linux@xxxxxxxxxxxx/
> 
> Just after start of unittest you should see a warning about
> testcases.
> 

Trying again:

With this patch applied, the kernel no longer crashes, and the log message
is as expected:

### dt-test ### start of unittest - you will see error messages
### dt-test ### unittest_data_add: unflatten testcases tree failed

Tested-by: Guenter Roeck <linux@xxxxxxxxxxxx>

> Thanks,
> 
> Frank
> 
> 
> On 4/4/21 10:28 PM, frowand.list@xxxxxxxxx wrote:
> > From: Frank Rowand <frank.rowand@xxxxxxxx>
> > 
> > fdt_get_name() returns error values via a parameter pointer
> > instead of in function return.  Fix check for this error value
> > in populate_node() and callers of populate_node().
> > 
> > Chasing up the caller tree showed callers of various functions
> > failing to initialize the value of pointer parameters that
> > can return error values.  Initialize those values to NULL.
> > 
> > The bug was introduced by
> > commit e6a6928c3ea1 ("of/fdt: Convert FDT functions to use libfdt")
> > but this patch can not be backported directly to that commit
> > because the relevant code has further been restructured by
> > commit dfbd4c6eff35 ("drivers/of: Split unflatten_dt_node()")
> > 
> > The bug became visible by triggering a crash on openrisc with:
> > commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
> > as reported in:
> > https://lore.kernel.org/lkml/20210327224116.69309-1-linux@xxxxxxxxxxxx/
> > 
> > Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
> > Reported-by: Guenter Roeck <linux@xxxxxxxxxxxx>
> > Signed-off-by: Frank Rowand <frank.rowand@xxxxxxxx>
> > 
> > ---
> > 
> > This patch papers over the unaligned pointer passed to
> > of_fdt_unflatten_tree() bug that Guenter reported in
> > https://lore.kernel.org/lkml/20210327224116.69309-1-linux@xxxxxxxxxxxx/
> > 
> > I will create a separate patch to fix that problem.
> > 
> >  drivers/of/fdt.c      | 36 +++++++++++++++++++++++-------------
> >  drivers/of/overlay.c  |  2 +-
> >  drivers/of/unittest.c | 15 ++++++++++-----
> >  3 files changed, 34 insertions(+), 19 deletions(-)
> > 
> > diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> > index dcc1dd96911a..adb26aff481d 100644
> > --- a/drivers/of/fdt.c
> > +++ b/drivers/of/fdt.c
> > @@ -205,7 +205,7 @@ static void populate_properties(const void *blob,
> >  		*pprev = NULL;
> >  }
> >  
> > -static bool populate_node(const void *blob,
> > +static int populate_node(const void *blob,
> >  			  int offset,
> >  			  void **mem,
> >  			  struct device_node *dad,
> > @@ -214,24 +214,24 @@ static bool populate_node(const void *blob,
> >  {
> >  	struct device_node *np;
> >  	const char *pathp;
> > -	unsigned int l, allocl;
> > +	int len;
> >  
> > -	pathp = fdt_get_name(blob, offset, &l);
> > +	pathp = fdt_get_name(blob, offset, &len);
> >  	if (!pathp) {
> >  		*pnp = NULL;
> > -		return false;
> > +		return len;
> >  	}
> >  
> > -	allocl = ++l;
> > +	len++;
> >  
> > -	np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
> > +	np = unflatten_dt_alloc(mem, sizeof(struct device_node) + len,
> >  				__alignof__(struct device_node));
> >  	if (!dryrun) {
> >  		char *fn;
> >  		of_node_init(np);
> >  		np->full_name = fn = ((char *)np) + sizeof(*np);
> >  
> > -		memcpy(fn, pathp, l);
> > +		memcpy(fn, pathp, len);
> >  
> >  		if (dad != NULL) {
> >  			np->parent = dad;
> > @@ -295,6 +295,7 @@ static int unflatten_dt_nodes(const void *blob,
> >  	struct device_node *nps[FDT_MAX_DEPTH];
> >  	void *base = mem;
> >  	bool dryrun = !base;
> > +	int ret;
> >  
> >  	if (nodepp)
> >  		*nodepp = NULL;
> > @@ -322,9 +323,10 @@ static int unflatten_dt_nodes(const void *blob,
> >  		    !of_fdt_device_is_available(blob, offset))
> >  			continue;
> >  
> > -		if (!populate_node(blob, offset, &mem, nps[depth],
> > -				   &nps[depth+1], dryrun))
> > -			return mem - base;
> > +		ret = populate_node(blob, offset, &mem, nps[depth],
> > +				   &nps[depth+1], dryrun);
> > +		if (ret < 0)
> > +			return ret;
> >  
> >  		if (!dryrun && nodepp && !*nodepp)
> >  			*nodepp = nps[depth+1];
> > @@ -372,6 +374,10 @@ void *__unflatten_device_tree(const void *blob,
> >  {
> >  	int size;
> >  	void *mem;
> > +	int ret;
> > +
> > +	if (mynodes)
> > +		*mynodes = NULL;
> >  
> >  	pr_debug(" -> unflatten_device_tree()\n");
> >  
> > @@ -392,7 +398,7 @@ void *__unflatten_device_tree(const void *blob,
> >  
> >  	/* First pass, scan for size */
> >  	size = unflatten_dt_nodes(blob, NULL, dad, NULL);
> > -	if (size < 0)
> > +	if (size <= 0)
> >  		return NULL;
> >  
> >  	size = ALIGN(size, 4);
> > @@ -410,12 +416,16 @@ void *__unflatten_device_tree(const void *blob,
> >  	pr_debug("  unflattening %p...\n", mem);
> >  
> >  	/* Second pass, do actual unflattening */
> > -	unflatten_dt_nodes(blob, mem, dad, mynodes);
> > +	ret = unflatten_dt_nodes(blob, mem, dad, mynodes);
> > +
> >  	if (be32_to_cpup(mem + size) != 0xdeadbeef)
> >  		pr_warn("End of tree marker overwritten: %08x\n",
> >  			be32_to_cpup(mem + size));
> >  
> > -	if (detached && mynodes) {
> > +	if (ret <= 0)
> > +		return NULL;
> > +
> > +	if (detached && mynodes && *mynodes) {
> >  		of_node_set_flag(*mynodes, OF_DETACHED);
> >  		pr_debug("unflattened tree is detached\n");
> >  	}
> > diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
> > index 50bbe0edf538..e12c643b6ba8 100644
> > --- a/drivers/of/overlay.c
> > +++ b/drivers/of/overlay.c
> > @@ -1017,7 +1017,7 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
> >  	const void *new_fdt;
> >  	int ret;
> >  	u32 size;
> > -	struct device_node *overlay_root;
> > +	struct device_node *overlay_root = NULL;
> >  
> >  	*ovcs_id = 0;
> >  	ret = 0;
> > diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
> > index eb100627c186..f9b5b698249f 100644
> > --- a/drivers/of/unittest.c
> > +++ b/drivers/of/unittest.c
> > @@ -1408,7 +1408,7 @@ static void attach_node_and_children(struct device_node *np)
> >  static int __init unittest_data_add(void)
> >  {
> >  	void *unittest_data;
> > -	struct device_node *unittest_data_node, *np;
> > +	struct device_node *unittest_data_node = NULL, *np;
> >  	/*
> >  	 * __dtb_testcases_begin[] and __dtb_testcases_end[] are magically
> >  	 * created by cmd_dt_S_dtb in scripts/Makefile.lib
> > @@ -1417,10 +1417,10 @@ static int __init unittest_data_add(void)
> >  	extern uint8_t __dtb_testcases_end[];
> >  	const int size = __dtb_testcases_end - __dtb_testcases_begin;
> >  	int rc;
> > +	void *ret;
> >  
> >  	if (!size) {
> > -		pr_warn("%s: No testcase data to attach; not running tests\n",
> > -			__func__);
> > +		pr_warn("%s: testcases is empty\n", __func__);
> >  		return -ENODATA;
> >  	}
> >  
> > @@ -1429,9 +1429,14 @@ static int __init unittest_data_add(void)
> >  	if (!unittest_data)
> >  		return -ENOMEM;
> >  
> > -	of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node);
> > +	ret = of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node);
> > +	if (!ret) {
> > +		pr_warn("%s: unflatten testcases tree failed\n", __func__);
> > +		kfree(unittest_data);
> > +		return -ENODATA;
> > +	}
> >  	if (!unittest_data_node) {
> > -		pr_warn("%s: No tree to attach; not running tests\n", __func__);
> > +		pr_warn("%s: testcases tree is empty\n", __func__);
> >  		kfree(unittest_data);
> >  		return -ENODATA;
> >  	}
> > 
> 



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux