All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer
@ 2026-10-01 12:10 Ayan Kumar Halder
  2026-10-01 15:10 ` Herve Codina
  2026-10-06  2:59 ` David Gibson
  0 siblings, 2 replies; 6+ messages in thread
From: Ayan Kumar Halder @ 2026-10-01 12:10 UTC (permalink / raw)
  To: devicetree-compiler
  Cc: David Gibson, Rob Herring, Andrew Cooper, Jan Beulich,
	Julien Grall, Stefano Stabellini, Michal Orzel, Bertrand Marquis,
	Ayan Kumar Halder

fdt_get_path() walks the tree from the root, appending each node's name
to the caller's buffer as it goes down and removing the last component
again as it comes back up.  It keeps the number of components currently
in the buffer in pdepth, and removes components while pdepth is greater
than the depth reported by fdt_next_node().

fdt_next_node() reports that it has left the tree by taking the depth
negative, but the offset it returns at that point is the offset of the
end tag, which is not negative.  The loop only tests the offset, so for a
nodeoffset at or past the end tag it runs one more time with a negative
depth.  pdepth still counts the components in the buffer, so the removal
loop is asked to remove more components than are there: it takes the
index down to zero and carries on scanning backwards for a '/' that is
not in the buffer.

Stop the walk when the depth shows it has left the tree.  Offsets that
far along are rejected by the error paths below in any case, so this
does not change what callers see.

Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
---
 libfdt/fdt_ro.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
index 11f2e2e..32689c7 100644
--- a/libfdt/fdt_ro.c
+++ b/libfdt/fdt_ro.c
@@ -582,7 +582,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
 		return -FDT_ERR_NOSPACE;
 
 	for (offset = 0, depth = 0;
-	     (offset >= 0) && (offset <= nodeoffset);
+	     (offset >= 0) && (depth >= 0) && (offset <= nodeoffset);
 	     offset = fdt_next_node(fdt, offset, &depth)) {
 		while (pdepth > depth) {
 			do {
-- 
2.25.1


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

* Re: [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer
  2026-10-01 12:10 [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer Ayan Kumar Halder
@ 2026-10-01 15:10 ` Herve Codina
  2026-10-01 17:18   ` Halder, Ayan Kumar
  2026-10-06  2:59 ` David Gibson
  1 sibling, 1 reply; 6+ messages in thread
From: Herve Codina @ 2026-10-01 15:10 UTC (permalink / raw)
  To: Ayan Kumar Halder
  Cc: devicetree-compiler, David Gibson, Rob Herring, Andrew Cooper,
	Jan Beulich, Julien Grall, Stefano Stabellini, Michal Orzel,
	Bertrand Marquis

Hi Ayan,

On Thu, 1 Oct 2026 13:10:36 +0100
Ayan Kumar Halder <ayan.kumar.halder@amd.com> wrote:

> fdt_get_path() walks the tree from the root, appending each node's name
> to the caller's buffer as it goes down and removing the last component
> again as it comes back up.  It keeps the number of components currently
> in the buffer in pdepth, and removes components while pdepth is greater
> than the depth reported by fdt_next_node().
> 
> fdt_next_node() reports that it has left the tree by taking the depth
> negative, but the offset it returns at that point is the offset of the
> end tag, which is not negative.  The loop only tests the offset, so for a

fdt_next_node() returns an error (-FDT_ERR_NOTFOUND) when it reaches the
FDT_END tag [1].

I don't understand your point. Maybe I've missed something.
Can you clarify?

[1] https://github.com/dgibson/dtc/blob/7a1e017926004ecff5fce62d62d42ce9f3e00082/libfdt/fdt.c#L283

> nodeoffset at or past the end tag it runs one more time with a negative
> depth.  pdepth still counts the components in the buffer, so the removal
> loop is asked to remove more components than are there: it takes the
> index down to zero and carries on scanning backwards for a '/' that is
> not in the buffer.
> 
> Stop the walk when the depth shows it has left the tree.  Offsets that
> far along are rejected by the error paths below in any case, so this
> does not change what callers see.

If fdt_next_node() can return an offset (positive value) which is not pointing
to a node without any errors (negative returned value), fdt_next_node() has
to be fixed not callers.

Can you give details leading fdt_next_node() returning a valid offset which
doesn't point to a node?

Best regards,
Hervé

> 
> Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
> ---
>  libfdt/fdt_ro.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
> index 11f2e2e..32689c7 100644
> --- a/libfdt/fdt_ro.c
> +++ b/libfdt/fdt_ro.c
> @@ -582,7 +582,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
>  		return -FDT_ERR_NOSPACE;
>  
>  	for (offset = 0, depth = 0;
> -	     (offset >= 0) && (offset <= nodeoffset);
> +	     (offset >= 0) && (depth >= 0) && (offset <= nodeoffset);
>  	     offset = fdt_next_node(fdt, offset, &depth)) {
>  		while (pdepth > depth) {
>  			do {

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

* Re: [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer
  2026-10-01 15:10 ` Herve Codina
@ 2026-10-01 17:18   ` Halder, Ayan Kumar
  2026-10-02  9:28     ` Herve Codina
  0 siblings, 1 reply; 6+ messages in thread
From: Halder, Ayan Kumar @ 2026-10-01 17:18 UTC (permalink / raw)
  To: Herve Codina, Ayan Kumar Halder
  Cc: devicetree-compiler, David Gibson, Rob Herring, Andrew Cooper,
	Jan Beulich, Julien Grall, Stefano Stabellini, Michal Orzel,
	Bertrand Marquis


On 01/10/2026 16:10, Herve Codina wrote:
> Hi Ayan,

Hi Herve,

Thanks for the review.

>
> On Thu, 1 Oct 2026 13:10:36 +0100
> Ayan Kumar Halder <ayan.kumar.halder@amd.com> wrote:
>
>> fdt_get_path() walks the tree from the root, appending each node's name
>> to the caller's buffer as it goes down and removing the last component
>> again as it comes back up.  It keeps the number of components currently
>> in the buffer in pdepth, and removes components while pdepth is greater
>> than the depth reported by fdt_next_node().
>>
>> fdt_next_node() reports that it has left the tree by taking the depth
>> negative, but the offset it returns at that point is the offset of the
>> end tag, which is not negative.  The loop only tests the offset, so for a
> fdt_next_node() returns an error (-FDT_ERR_NOTFOUND) when it reaches the
> FDT_END tag [1].
>
> I don't understand your point. Maybe I've missed something.
> Can you clarify?
Sorry, my wording was wrong.  I meant the FDT_END_NODE case, just above
the one you linked:

     case FDT_END_NODE:
         if (depth && ((--(*depth)) < 0))
             return nextoffset;

Leaving the root node is an FDT_END_NODE tag, so --(*depth) takes the
depth from 0 to -1 and fdt_next_node() returns nextoffset, which is not
negative.  FDT_END is only reached on the next call.

>
> [1] https://github.com/dgibson/dtc/blob/7a1e017926004ecff5fce62d62d42ce9f3e00082/libfdt/fdt.c#L283
>
>> nodeoffset at or past the end tag it runs one more time with a negative
>> depth.  pdepth still counts the components in the buffer, so the removal
>> loop is asked to remove more components than are there: it takes the
>> index down to zero and carries on scanning backwards for a '/' that is
>> not in the buffer.
>>
>> Stop the walk when the depth shows it has left the tree.  Offsets that
>> far along are rejected by the error paths below in any case, so this
>> does not change what callers see.
> If fdt_next_node() can return an offset (positive value) which is not pointing
> to a node without any errors (negative returned value), fdt_next_node() has
> to be fixed not callers.
>
> Can you give details leading fdt_next_node() returning a valid offset which
> doesn't point to a node?
The offset is the one past root's FDT_END_NODE tag, so on
tests/test_tree1.dtb:

   offset   depth
   540      2
   560      -1    <- FDT_END_NODE: offset >= 0, depth < 0
   -4       -1    <- FDT_ERR_BADOFFSET, from the next call

Does it make sense ?

I discovered this issue by building libfdt with AddressSanitizer.

( I am new to this, so it may be my misunderstanding )

- Ayan


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

* Re: [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer
  2026-10-01 17:18   ` Halder, Ayan Kumar
@ 2026-10-02  9:28     ` Herve Codina
  0 siblings, 0 replies; 6+ messages in thread
From: Herve Codina @ 2026-10-02  9:28 UTC (permalink / raw)
  To: Halder, Ayan Kumar
  Cc: Ayan Kumar Halder, devicetree-compiler, David Gibson, Rob Herring,
	Andrew Cooper, Jan Beulich, Julien Grall, Stefano Stabellini,
	Michal Orzel, Bertrand Marquis

On Thu, 1 Oct 2026 18:18:54 +0100
"Halder, Ayan Kumar" <ayankuma@amd.com> wrote:

> On 01/10/2026 16:10, Herve Codina wrote:
> > Hi Ayan,  
> 
> Hi Herve,
> 
> Thanks for the review.
> 
> >
> > On Thu, 1 Oct 2026 13:10:36 +0100
> > Ayan Kumar Halder <ayan.kumar.halder@amd.com> wrote:
> >  
> >> fdt_get_path() walks the tree from the root, appending each node's name
> >> to the caller's buffer as it goes down and removing the last component
> >> again as it comes back up.  It keeps the number of components currently
> >> in the buffer in pdepth, and removes components while pdepth is greater
> >> than the depth reported by fdt_next_node().
> >>
> >> fdt_next_node() reports that it has left the tree by taking the depth
> >> negative, but the offset it returns at that point is the offset of the
> >> end tag, which is not negative.  The loop only tests the offset, so for a  
> > fdt_next_node() returns an error (-FDT_ERR_NOTFOUND) when it reaches the
> > FDT_END tag [1].
> >
> > I don't understand your point. Maybe I've missed something.
> > Can you clarify?  
> Sorry, my wording was wrong.  I meant the FDT_END_NODE case, just above
> the one you linked:
> 
>      case FDT_END_NODE:
>          if (depth && ((--(*depth)) < 0))
>              return nextoffset;
> 
> Leaving the root node is an FDT_END_NODE tag, so --(*depth) takes the
> depth from 0 to -1 and fdt_next_node() returns nextoffset, which is not
> negative.  FDT_END is only reached on the next call.

Ok

> 
> >
> > [1] https://github.com/dgibson/dtc/blob/7a1e017926004ecff5fce62d62d42ce9f3e00082/libfdt/fdt.c#L283
> >  
> >> nodeoffset at or past the end tag it runs one more time with a negative
> >> depth.  pdepth still counts the components in the buffer, so the removal
> >> loop is asked to remove more components than are there: it takes the
> >> index down to zero and carries on scanning backwards for a '/' that is
> >> not in the buffer.
> >>
> >> Stop the walk when the depth shows it has left the tree.  Offsets that
> >> far along are rejected by the error paths below in any case, so this
> >> does not change what callers see.  
> > If fdt_next_node() can return an offset (positive value) which is not pointing
> > to a node without any errors (negative returned value), fdt_next_node() has
> > to be fixed not callers.
> >
> > Can you give details leading fdt_next_node() returning a valid offset which
> > doesn't point to a node?  
> The offset is the one past root's FDT_END_NODE tag, so on
> tests/test_tree1.dtb:
> 
>    offset   depth
>    540      2
>    560      -1    <- FDT_END_NODE: offset >= 0, depth < 0
>    -4       -1    <- FDT_ERR_BADOFFSET, from the next call
> 
> Does it make sense ?

It could but I still don't see where the issue is.

I mean, in the fdt_get_path() we have the following loop:

	for (offset = 0, depth = 0;
	     (offset >= 0) && (offset <= nodeoffset);
	     offset = fdt_next_node(fdt, offset, &depth)) {
		...
	}

fdt_next_node() returns an offset past the root's FDT_END_NODE tag.

In that case, how the 'offset <= nodeoffset' condition can be true in order
to continue the loop?

nodeoffset is an offset to a node. It is either the root node or a node
inside the root tree. And so this offset points to something before the
root's FDT_END_NODE tag offset.

Do I miss something?

Best regards,
Hervé

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

* Re: [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer
  2026-10-01 12:10 [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer Ayan Kumar Halder
  2026-10-01 15:10 ` Herve Codina
@ 2026-10-06  2:59 ` David Gibson
  2026-10-08 12:15   ` Simon Glass
  1 sibling, 1 reply; 6+ messages in thread
From: David Gibson @ 2026-10-06  2:59 UTC (permalink / raw)
  To: Ayan Kumar Halder
  Cc: devicetree-compiler, Rob Herring, Andrew Cooper, Jan Beulich,
	Julien Grall, Stefano Stabellini, Michal Orzel, Bertrand Marquis

[-- Attachment #1: Type: text/plain, Size: 2235 bytes --]

On Thu, Oct 01, 2026 at 01:10:36PM +0100, Ayan Kumar Halder wrote:
> fdt_get_path() walks the tree from the root, appending each node's name
> to the caller's buffer as it goes down and removing the last component
> again as it comes back up.  It keeps the number of components currently
> in the buffer in pdepth, and removes components while pdepth is greater
> than the depth reported by fdt_next_node().
> 
> fdt_next_node() reports that it has left the tree by taking the depth
> negative, but the offset it returns at that point is the offset of the
> end tag, which is not negative.  The loop only tests the offset, so for a
> nodeoffset at or past the end tag it runs one more time with a negative
> depth.  pdepth still counts the components in the buffer, so the removal
> loop is asked to remove more components than are there: it takes the
> index down to zero and carries on scanning backwards for a '/' that is
> not in the buffer.
> 
> Stop the walk when the depth shows it has left the tree.  Offsets that
> far along are rejected by the error paths below in any case, so this
> does not change what callers see.
> 
> Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>

I think this is a bug in fdt_next_node() rather than in
fdt_get_path().  It should not be returning offsets that are not valid
node offsets (excepting negative error codes, of course).

> ---
>  libfdt/fdt_ro.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
> index 11f2e2e..32689c7 100644
> --- a/libfdt/fdt_ro.c
> +++ b/libfdt/fdt_ro.c
> @@ -582,7 +582,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
>  		return -FDT_ERR_NOSPACE;
>  
>  	for (offset = 0, depth = 0;
> -	     (offset >= 0) && (offset <= nodeoffset);
> +	     (offset >= 0) && (depth >= 0) && (offset <= nodeoffset);
>  	     offset = fdt_next_node(fdt, offset, &depth)) {
>  		while (pdepth > depth) {
>  			do {
> -- 
> 2.25.1
> 
> 

-- 
David Gibson (he or they)	| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you, not the other way
				| around.
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer
  2026-10-06  2:59 ` David Gibson
@ 2026-10-08 12:15   ` Simon Glass
  0 siblings, 0 replies; 6+ messages in thread
From: Simon Glass @ 2026-10-08 12:15 UTC (permalink / raw)
  To: David Gibson
  Cc: Ayan Kumar Halder, devicetree-compiler, Rob Herring,
	Andrew Cooper, Jan Beulich, Julien Grall, Stefano Stabellini,
	Michal Orzel, Bertrand Marquis

Hi,

On Tue, 6 Oct 2026 at 04:01, David Gibson <david@gibson.dropbear.id.au> wrote:
>
> On Thu, Oct 01, 2026 at 01:10:36PM +0100, Ayan Kumar Halder wrote:
> > fdt_get_path() walks the tree from the root, appending each node's name
> > to the caller's buffer as it goes down and removing the last component
> > again as it comes back up.  It keeps the number of components currently
> > in the buffer in pdepth, and removes components while pdepth is greater
> > than the depth reported by fdt_next_node().
> >
> > fdt_next_node() reports that it has left the tree by taking the depth
> > negative, but the offset it returns at that point is the offset of the
> > end tag, which is not negative.  The loop only tests the offset, so for a
> > nodeoffset at or past the end tag it runs one more time with a negative
> > depth.  pdepth still counts the components in the buffer, so the removal
> > loop is asked to remove more components than are there: it takes the
> > index down to zero and carries on scanning backwards for a '/' that is
> > not in the buffer.
> >
> > Stop the walk when the depth shows it has left the tree.  Offsets that
> > far along are rejected by the error paths below in any case, so this
> > does not change what callers see.
> >
> > Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
>
> I think this is a bug in fdt_next_node() rather than in
> fdt_get_path().  It should not be returning offsets that are not valid
> node offsets (excepting negative error codes, of course).

The bug is only with an invalid nodeoffset past the root's FDT_END_NODE

I don't think fdt_next_node() should change - fdt_node_end_offset_()
relies on it returning the offset after the FDT_END_NODE when depth
goes negative, and fdt_nop_node() and fdt_del_node() use that. For the
last child of a node, that offset is the parent's FDT_END_NODE, so it
is not a node offset.

One option would be to reject nodeoffset up front with fdt_check_node_offset_()

For the commit message, as you mention, use 'FDT_END_NODE' rather than
'end tag' and make it clear this needs a bad nodeoffset - also try to
explain the problem in the first paragraph.

Also please add a bad-offset case to tests/get_path.c

Regards,
Simon

>
> > ---
> >  libfdt/fdt_ro.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
> > index 11f2e2e..32689c7 100644
> > --- a/libfdt/fdt_ro.c
> > +++ b/libfdt/fdt_ro.c
> > @@ -582,7 +582,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
> >               return -FDT_ERR_NOSPACE;
> >
> >       for (offset = 0, depth = 0;
> > -          (offset >= 0) && (offset <= nodeoffset);
> > +          (offset >= 0) && (depth >= 0) && (offset <= nodeoffset);
> >            offset = fdt_next_node(fdt, offset, &depth)) {
> >               while (pdepth > depth) {
> >                       do {
> > --
> > 2.25.1
> >
> >

[..]

Regards,
SImon

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

end of thread, other threads:[~2026-10-08 12:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-01 12:10 [PATCH] libfdt: Fix fdt_get_path() reading before the start of the buffer Ayan Kumar Halder
2026-10-01 15:10 ` Herve Codina
2026-10-01 17:18   ` Halder, Ayan Kumar
2026-10-02  9:28     ` Herve Codina
2026-10-06  2:59 ` David Gibson
2026-10-08 12:15   ` Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.