This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 152ebca59969b5dc84415572a626e9fdb570471b Author: vela-autotest05 <[email protected]> AuthorDate: Tue Jul 28 04:11:08 2026 +0800 fs/inode: fix relative-path truncation causing wrong EISDIR Root cause: _inode_search() built the absolute form of a relative path with snprintf(buf, PATH_MAX, "%s/%s", cwd, path), silently truncating it when cwd + "/" + path exceeded PATH_MAX. The truncated buffer was then handed to _inode_canonicalize(), which collapsed ".." segments against the wrong cut-off suffix. A valid relative path of PATH_MAX-1 bytes (legal per pathconf(_PC_PATH_MAX)) could thus collapse onto a directory and open() returned EISDIR instead of resolving the file. Fix: size the temp buffer to hold the full uncanonicalized "<cwd>/<path>" form so canonicalization sees the complete path. lib_get_tempbuffer falls back to a malloc'd buffer when the size exceeds PATH_MAX (CONFIG_LIBC_TEMPBUFFER_MALLOC). The existing PATH_MAX check in _inode_canonicalize() still rejects any canonicalized result that is too long, so ENAMETOOLONG semantics are preserved. Signed-off-by: dengwenqi <[email protected]> --- fs/inode/fs_inodesearch.c | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/fs/inode/fs_inodesearch.c b/fs/inode/fs_inodesearch.c index 969ded7453b..fac611a7c8f 100644 --- a/fs/inode/fs_inodesearch.c +++ b/fs/inode/fs_inodesearch.c @@ -398,25 +398,50 @@ static int _inode_search(FAR struct inode_search_s *desc) if (desc->buffer == NULL) { - desc->buffer = lib_get_tempbuffer(PATH_MAX); + FAR const char *cwd = NULL; + size_t buflen; + + /* For a relative path the absolute form is "<cwd>/<path>". That + * concatenation can exceed PATH_MAX even when the relative path + * itself is within PATH_MAX: a relative path of PATH_MAX-1 bytes + * is legal per pathconf(_PC_PATH_MAX), but the prefix added by the + * cwd pushes the uncanonicalized form past the limit. Size the + * buffer to hold the full absolute form so that ".." segments are + * collapsed against the correct suffix; truncating first could + * drop the trailing component and let ".." collapse the path onto + * a directory (yielding the wrong errno, e.g. EISDIR, instead of + * resolving the file). _inode_canonicalize() still rejects any + * result whose canonicalized length reaches PATH_MAX. + */ + + if (*desc->path != '/') + { + cwd = _inode_getcwd(); + buflen = strlen(cwd) + 1 + strlen(desc->path) + 1; + } + else + { + buflen = strlen(desc->path) + 1; + } + + if (buflen < PATH_MAX) + { + buflen = PATH_MAX; + } + + desc->buffer = lib_get_tempbuffer(buflen); if (desc->buffer == NULL) { return -ENOMEM; } - /* Convert relative path to absolute, or just copy absolute path. - * Use desc->path directly (points to caller's string) as source - * to avoid overlap with desc->buffer. - */ - - if (*desc->path != '/') + if (cwd != NULL) { - snprintf(desc->buffer, PATH_MAX, "%s/%s", - _inode_getcwd(), desc->path); + snprintf(desc->buffer, buflen, "%s/%s", cwd, desc->path); } else { - strlcpy(desc->buffer, desc->path, PATH_MAX); + strlcpy(desc->buffer, desc->path, buflen); } desc->path = desc->buffer;
