linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()
@ 2021-04-05 17:02 Guenter Roeck
  0 siblings, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2021-04-05 17:02 UTC (permalink / raw)
  To: frowand.list
  Cc: Rob Herring, Pantelis Antoniou, devicetree, Geert Uytterhoeven,
	linux-kernel

On Sun, Apr 04, 2021 at 10:28:45PM -0500, frowand.list@gmail.com wrote:
> From: Frank Rowand <frank.rowand@sony.com>
> 
> 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@roeck-us.net/
> 
> Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
> Reported-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
> 

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@roeck-us.net>

Thanks,
Guenter

> ---
> 
> 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@roeck-us.net/
> 
> 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;
>  	}
> -- 
> Frank Rowand <frank.rowand@sony.com>
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()
  2021-04-06 20:30   ` Frank Rowand
@ 2021-04-07 21:04     ` Frank Rowand
  0 siblings, 0 replies; 8+ messages in thread
From: Frank Rowand @ 2021-04-07 21:04 UTC (permalink / raw)
  To: Rob Herring
  Cc: Guenter Roeck, Pantelis Antoniou, devicetree, Geert Uytterhoeven,
	linux-kernel

On 4/6/21 3:30 PM, Frank Rowand wrote:
> On 4/6/21 2:21 PM, Rob Herring wrote:
>> On Sun, Apr 04, 2021 at 10:28:45PM -0500, frowand.list@gmail.com wrote:
>>> From: Frank Rowand <frank.rowand@sony.com>
>>>
>>> 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@roeck-us.net/
>>>
>>> Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
>>> Reported-by: Guenter Roeck <linux@roeck-us.net>
>>> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
>>>
>>> ---
>>>
>>> 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@roeck-us.net/
>>>
>>> I will create a separate patch to fix that problem.
> 
> Likely to be tomorrow (Wed 4/7).
> 
> -Frank
> 
>>
>> Got an ETA for that?
>>
>> Rob
>> .
>>
> 

The patch to fix the alignment issue is:

  https://lore.kernel.org/linux-devicetree/20210407205110.2173976-1-frowand.list@gmail.com/

Hopefully it will pass testing by Guenter.
  
Sorry about the previous vertical dyslexia response... :-)

-Frank

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()
  2021-04-06 19:21 ` Rob Herring
@ 2021-04-06 20:30   ` Frank Rowand
  2021-04-07 21:04     ` Frank Rowand
  0 siblings, 1 reply; 8+ messages in thread
From: Frank Rowand @ 2021-04-06 20:30 UTC (permalink / raw)
  To: Rob Herring
  Cc: Guenter Roeck, Pantelis Antoniou, devicetree, Geert Uytterhoeven,
	linux-kernel

On 4/6/21 2:21 PM, Rob Herring wrote:
> On Sun, Apr 04, 2021 at 10:28:45PM -0500, frowand.list@gmail.com wrote:
>> From: Frank Rowand <frank.rowand@sony.com>
>>
>> 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@roeck-us.net/
>>
>> Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
>> Reported-by: Guenter Roeck <linux@roeck-us.net>
>> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
>>
>> ---
>>
>> 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@roeck-us.net/
>>
>> I will create a separate patch to fix that problem.

Likely to be tomorrow (Wed 4/7).

-Frank

> 
> Got an ETA for that?
> 
> Rob
> .
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()
  2021-04-05  3:28 frowand.list
  2021-04-05  3:37 ` Frank Rowand
  2021-04-06 19:21 ` Rob Herring
@ 2021-04-06 19:21 ` Rob Herring
  2 siblings, 0 replies; 8+ messages in thread
From: Rob Herring @ 2021-04-06 19:21 UTC (permalink / raw)
  To: frowand.list
  Cc: Geert Uytterhoeven, Rob Herring, Guenter Roeck, devicetree,
	linux-kernel, Pantelis Antoniou

On Sun, 04 Apr 2021 22:28:45 -0500, frowand.list@gmail.com wrote:
> From: Frank Rowand <frank.rowand@sony.com>
> 
> 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@roeck-us.net/
> 
> Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
> Reported-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
> 
> ---
> 
> 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@roeck-us.net/
> 
> 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(-)
> 

Applied, thanks!

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()
  2021-04-05  3:28 frowand.list
  2021-04-05  3:37 ` Frank Rowand
@ 2021-04-06 19:21 ` Rob Herring
  2021-04-06 20:30   ` Frank Rowand
  2021-04-06 19:21 ` Rob Herring
  2 siblings, 1 reply; 8+ messages in thread
From: Rob Herring @ 2021-04-06 19:21 UTC (permalink / raw)
  To: frowand.list
  Cc: Guenter Roeck, Pantelis Antoniou, devicetree, Geert Uytterhoeven,
	linux-kernel

On Sun, Apr 04, 2021 at 10:28:45PM -0500, frowand.list@gmail.com wrote:
> From: Frank Rowand <frank.rowand@sony.com>
> 
> 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@roeck-us.net/
> 
> Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
> Reported-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
> 
> ---
> 
> 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@roeck-us.net/
> 
> I will create a separate patch to fix that problem.

Got an ETA for that?

Rob

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()
  2021-04-05  3:37 ` Frank Rowand
@ 2021-04-05 23:03   ` Guenter Roeck
  0 siblings, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2021-04-05 23:03 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Rob Herring, Pantelis Antoniou, devicetree, Geert Uytterhoeven,
	linux-kernel

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@roeck-us.net/
> 
> 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@roeck-us.net>

> Thanks,
> 
> Frank
> 
> 
> On 4/4/21 10:28 PM, frowand.list@gmail.com wrote:
> > From: Frank Rowand <frank.rowand@sony.com>
> > 
> > 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@roeck-us.net/
> > 
> > Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
> > Reported-by: Guenter Roeck <linux@roeck-us.net>
> > Signed-off-by: Frank Rowand <frank.rowand@sony.com>
> > 
> > ---
> > 
> > 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@roeck-us.net/
> > 
> > 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;
> >  	}
> > 
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] of: properly check for error returned by fdt_get_name()
  2021-04-05  3:28 frowand.list
@ 2021-04-05  3:37 ` Frank Rowand
  2021-04-05 23:03   ` Guenter Roeck
  2021-04-06 19:21 ` Rob Herring
  2021-04-06 19:21 ` Rob Herring
  2 siblings, 1 reply; 8+ messages in thread
From: Frank Rowand @ 2021-04-05  3:37 UTC (permalink / raw)
  To: Rob Herring, Guenter Roeck
  Cc: Pantelis Antoniou, devicetree, Geert Uytterhoeven, linux-kernel

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@roeck-us.net/

Just after start of unittest you should see a warning about
testcases.

Thanks,

Frank


On 4/4/21 10:28 PM, frowand.list@gmail.com wrote:
> From: Frank Rowand <frank.rowand@sony.com>
> 
> 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@roeck-us.net/
> 
> Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
> Reported-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
> 
> ---
> 
> 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@roeck-us.net/
> 
> 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;
>  	}
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/1] of: properly check for error returned by fdt_get_name()
@ 2021-04-05  3:28 frowand.list
  2021-04-05  3:37 ` Frank Rowand
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: frowand.list @ 2021-04-05  3:28 UTC (permalink / raw)
  To: Rob Herring, Guenter Roeck
  Cc: Pantelis Antoniou, devicetree, Geert Uytterhoeven, linux-kernel

From: Frank Rowand <frank.rowand@sony.com>

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@roeck-us.net/

Fixes: commit 79edff12060f ("scripts/dtc: Update to upstream version v1.6.0-51-g183df9e9c2b9")
Reported-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Frank Rowand <frank.rowand@sony.com>

---

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@roeck-us.net/

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;
 	}
-- 
Frank Rowand <frank.rowand@sony.com>


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-04-07 21:04 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-05 17:02 [PATCH 1/1] of: properly check for error returned by fdt_get_name() Guenter Roeck
  -- strict thread matches above, loose matches on Subject: below --
2021-04-05  3:28 frowand.list
2021-04-05  3:37 ` Frank Rowand
2021-04-05 23:03   ` Guenter Roeck
2021-04-06 19:21 ` Rob Herring
2021-04-06 20:30   ` Frank Rowand
2021-04-07 21:04     ` Frank Rowand
2021-04-06 19:21 ` Rob Herring

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).