Date: Mon, 26 May 2003 10:58:15 +0200 From: Uwe Doering <gemini@geminix.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: bin/52686: Problem with realpath(3) when traversing / Message-ID: <E19KDo7-0001cb-00@geminix.org> Resent-Message-ID: <200305260900.h4Q90TZg062214@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 52686 >Category: bin >Synopsis: Problem with realpath(3) when traversing / >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon May 26 02:00:28 PDT 2003 >Closed-Date: >Last-Modified: >Originator: Uwe Doering >Release: FreeBSD 4.5-RELEASE i386 >Organization: EscapeBox - Managed On-Demand UNIX Servers http://www.escapebox.net >Environment: System: FreeBSD geminix.private.geminix.org 4.5-RELEASE FreeBSD 4.5-RELEASE #2: Fri Mar 21 13:43:46 MET 2003 root@geminix.private.geminix.org:/usr/src/sys/compile/GEMINIX i386 libc/libc_r updated with 'src/lib/libc/stdlib/realpath.c' revision 1.9.2.1 (as MFC'ed to RELENG_4 a couple of days ago). >Description: The new impementation of 'realpath.c' (thread-safe) contains a bug that causes it to return an empty string occasionally. When truncating the path string due to '..' components in the path given as argument it removes not only the rightmost component but also the slash preceding this component. Normally, this slash will be re-appended with the next loop iteration, but in case of only one component left the string length drops to zero, which is clearly an illegal condition given the way the rest of the code is written. With the next loop iteration the code that is supposed to re-append the trailing slash checks the path string buffer with an index of -1. Now, depending on whether it by chance finds a slash there it won't append another slash and therefore leaves the string empty. Here's the code fragment causing 'resolved_len' to become zero (line 113): else if (strcmp(next_token, "..") == 0) { /* * Strip the last path component except when we have * single "/" */ if (resolved_len > 1) { resolved[resolved_len - 1] = '\0'; q = strrchr(resolved, '/'); *q = '\0'; resolved_len = q - resolved; } continue; And this is where it can break with the next iteration step (line 101): if (resolved[resolved_len - 1] != '/') { if (resolved_len + 1 >= PATH_MAX) { errno = ENAMETOOLONG; return (NULL); } resolved[resolved_len++] = '/'; resolved[resolved_len] = '\0'; } >How-To-Repeat: With a version of libc/libc_r containing the new implementation of realpath(3) and a version of realpath(1) built with these libs (linked statically!), try cd /usr/src realpath ../.. In case there is (by chance) a slash at the -1 index position of the 'resolved' string buffer this sequence will return an empty string instead of a single slash. >Fix: Code that removes the rightmost component of the path string exists in two locations, that outlined above and also in case we follow a relative symlink (line 156). The fix is to leave the slash preceding the component to be removed intact. This doesn't hurt since it otherwise gets re-appended with the next loop iteration, anyway. The difference is that it does the right thing in case only one component is left. Here is the patch I suggest. It fixes the problem for me. ----------------------- cut here ---------------------- --- src/lib/libc/stdlib/realpath.c.orig Sat May 24 15:20:37 2003 +++ src/lib/libc/stdlib/realpath.c Sat May 24 15:20:53 2003 @@ -117,7 +117,7 @@ */ if (resolved_len > 1) { resolved[resolved_len - 1] = '\0'; - q = strrchr(resolved, '/'); + q = strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } @@ -156,7 +156,7 @@ } else if (resolved_len > 1) { /* Strip the last path component. */ resolved[resolved_len - 1] = '\0'; - q = strrchr(resolved, '/'); + q = strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } ----------------------- cut here ---------------------- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E19KDo7-0001cb-00>