From: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
To: <devicetree-compiler@vger.kernel.org>
Cc: David Gibson <david@gibson.dropbear.id.au>,
Rob Herring <robh@kernel.org>,
Herve Codina <herve.codina@bootlin.com>,
Simon Glass <sjg@chromium.org>,
Andrew Cooper <andrew.cooper3@citrix.com>,
Jan Beulich <jbeulich@suse.com>, Julien Grall <julien@xen.org>,
Stefano Stabellini <sstabellini@kernel.org>,
Michal Orzel <michal.orzel@amd.com>,
Bertrand Marquis <bertrand.marquis@arm.com>
Subject: [PATCH v3] libfdt: Fix fdt_get_path() reading before the start of the buffer
Date: Thu, 5 Nov 2026 18:04:39 +0000 [thread overview]
Message-ID: <20261105180439.955822-1-ayan.kumar.halder@amd.com> (raw)
Asking fdt_get_path() for an offset past the root node's FDT_END_NODE
tag makes it read before the start of the caller's buffer. Such an
offset is not a node offset, so fdt_get_path() should return
-FDT_ERR_BADOFFSET.
fdt_get_path() trims a component off the buffer for each level the walk
comes back up, comparing the components it has against the depth from
fdt_next_node(). On leaving the root node, fdt_next_node() takes the
depth negative and returns the offset just past that tag rather than an
error, as commit ce4d9c0f ("libfdt: Rework fdt_next_node()") intended so
that fdt_node_end_offset_() can find where a node ends. The loop only
tests the offset, so it runs once more and tries to trim a component
that is not there, scanning back past the start of the buffer.
Stop the walk once the depth goes negative, as
fdt_subnode_offset_namelen() and fdt_node_end_offset_() already do, and
reject the offset up front with fdt_check_node_offset_() where input is
not assumed valid. Add a bad-offset case to tests/get_path.c; run it
under valgrind (tests/run_tests.sh -m) to catch the read.
Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
---
Changes in v3:
- Reworded the opening sentence to say fdt_get_path() should return
-FDT_ERR_BADOFFSET (Simon).
- tests/get_path.c: allocate the buffer with xmalloc() so valgrind sees
the read before the start of the block, rather than only when the scan
runs past the stack pointer (Simon).
- tests/get_path.c: accept only -FDT_ERR_BADOFFSET, since the up-front
fdt_check_node_offset_() makes -FDT_ERR_BADSTRUCTURE unreachable for
these offsets (Simon).
Changes in v2:
- Reworded the commit message: say FDT_END_NODE rather than "end tag",
state the problem first, and make clear it needs a bad nodeoffset
(Simon, David).
- Referenced commit ce4d9c0f ("libfdt: Rework fdt_next_node()") for why
fdt_next_node() returns that offset (David).
- Also reject the offset up front with fdt_check_node_offset_(), under
can_assume(VALID_INPUT) (Simon, David).
- Added a bad-offset case to tests/get_path.c (Simon, David).
libfdt/fdt_ro.c | 8 ++++++--
tests/get_path.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
index fed2f9f..05903e3 100644
--- a/libfdt/fdt_ro.c
+++ b/libfdt/fdt_ro.c
@@ -583,7 +583,7 @@ const char *fdt_get_symbol(const void *fdt, const char *name)
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
int pdepth = 0, p = 0;
- int offset, depth, namelen;
+ int offset, depth, namelen, err;
const char *name;
FDT_RO_PROBE(fdt);
@@ -591,8 +591,12 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
if (buflen < 2)
return -FDT_ERR_NOSPACE;
+ if (!can_assume(VALID_INPUT)
+ && ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
+ return err;
+
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 {
diff --git a/tests/get_path.c b/tests/get_path.c
index 7349898..da8b26a 100644
--- a/tests/get_path.c
+++ b/tests/get_path.c
@@ -63,6 +63,36 @@ static void check_path(void *fdt, const char *path)
check_path_buf(fdt, path, pathlen, 2);
}
+/*
+ * An offset past the root node's FDT_END_NODE tag is not a node offset,
+ * but fdt_next_node() still returns it rather than an error (see commit
+ * ce4d9c0f "libfdt: Rework fdt_next_node()"), so fdt_get_path() has to
+ * recognise it from the depth going negative. Before it did, the path
+ * trimming scanned back past the start of the buffer for such an offset.
+ */
+static void check_path_bad_offset(void *fdt)
+{
+ int offset, depth = 0, badoffset = 0;
+ int buflen = 64;
+ char *buf = xmalloc(buflen);
+ int len, i;
+
+ /* The offset fdt_next_node() reports once it has left the tree. */
+ for (offset = 0; offset >= 0; offset = fdt_next_node(fdt, offset, &depth))
+ badoffset = offset;
+
+ for (i = 0; i < 8; i++) {
+ memset(buf, POISON, buflen);
+
+ len = fdt_get_path(fdt, badoffset + i, buf, buflen);
+ if (len != -FDT_ERR_BADOFFSET)
+ FAIL("fdt_get_path(%d) returns %d instead of "
+ "-FDT_ERR_BADOFFSET", badoffset + i, len);
+ }
+
+ free(buf);
+}
+
int main(int argc, char *argv[])
{
void *fdt;
@@ -76,5 +106,7 @@ int main(int argc, char *argv[])
check_path(fdt, "/subnode@1/subsubnode");
check_path(fdt, "/subnode@2/subsubnode@0");
+ check_path_bad_offset(fdt);
+
PASS();
}
--
2.25.1
next reply other threads:[~2026-11-05 18:05 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 18:04 Ayan Kumar Halder [this message]
2026-11-05 22:11 ` [PATCH v3] libfdt: Fix fdt_get_path() reading before the start of the buffer Simon Glass
2026-11-06 7:03 ` Herve Codina
2026-11-11 2:50 ` David Gibson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105180439.955822-1-ayan.kumar.halder@amd.com \
--to=ayan.kumar.halder@amd.com \
--cc=andrew.cooper3@citrix.com \
--cc=bertrand.marquis@arm.com \
--cc=david@gibson.dropbear.id.au \
--cc=devicetree-compiler@vger.kernel.org \
--cc=herve.codina@bootlin.com \
--cc=jbeulich@suse.com \
--cc=julien@xen.org \
--cc=michal.orzel@amd.com \
--cc=robh@kernel.org \
--cc=sjg@chromium.org \
--cc=sstabellini@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.