From 82b2f1993b8d6b2963006f8f531bddc32141a192 Mon Sep 17 00:00:00 2001 From: Junbo Zheng Date: Fri, 2 Oct 2026 23:07:43 +0800 Subject: [PATCH] libc/termios: Fix the ttyname_r buffer overflow with long tty paths. ttyname_r() passed the caller buffer straight to fcntl(F_GETPATH) whenever buflen >= TTY_NAME_MAX, but every FIOC_FILEPATH handler writes the path bounded by PATH_MAX and ignores the caller buffer size. A tty registered under a nested /dev path, or reached through rpmsgfs, has a path longer than TTY_NAME_MAX and overwrote the caller buffer, silently corrupting memory behind a zero return code. The small-buffer branch had the same defect against its own stack local char name[TTY_NAME_MAX]. Gate the direct write on PATH_MAX instead and stage the path through a PATH_MAX path buffer obtained via lib_get_tempbuffer(), returning ERANGE when it does not fit. Verified on sim:nsh with a test driver registered at an 85-character tty path: pre-fix, ttyname_r(buf, TTY_NAME_MAX) returned 0 and smashed the canaries behind the buffer, and the small-buffer branch panicked; post-fix both cases return ERANGE with the canaries intact. Assisted-by: Claude Code (glm-5.3) Signed-off-by: Junbo Zheng --- libs/libc/termios/lib_ttynamer.c | 35 ++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/libs/libc/termios/lib_ttynamer.c b/libs/libc/termios/lib_ttynamer.c index 8a30257a3ae..1efa84608b3 100644 --- a/libs/libc/termios/lib_ttynamer.c +++ b/libs/libc/termios/lib_ttynamer.c @@ -29,6 +29,8 @@ #include #include +#include + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -63,25 +65,36 @@ int ttyname_r(int fd, FAR char *buf, size_t buflen) return ENOTTY; } - if (buflen >= TTY_NAME_MAX) + /* The F_GETPATH handler copies the file path into the caller buffer + * bounded by PATH_MAX, not by any tty-specific limit, so the path must + * always land in a PATH_MAX-sized buffer first. Only a caller buffer + * of that size can receive it directly. + */ + + if (buflen >= PATH_MAX) { return fcntl(fd, F_GETPATH, buf) < 0 ? get_errno() : 0; } else { - char name[TTY_NAME_MAX]; + FAR char *path = lib_get_tempbuffer(PATH_MAX); + int ret; - if (fcntl(fd, F_GETPATH, name) < 0) + if (fcntl(fd, F_GETPATH, path) < 0) { - return get_errno(); + ret = get_errno(); + } + else if (strlen(path) >= buflen) + { + ret = ERANGE; + } + else + { + strlcpy(buf, path, buflen); + ret = OK; } - if (strlen(name) >= buflen) - { - return ERANGE; - } - - strlcpy(buf, name, buflen); - return OK; + lib_put_tempbuffer(path); + return ret; } }