From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/10701 Path: news.gmane.org!.POSTED!not-for-mail From: Quentin Rameau Newsgroups: gmane.linux.lib.musl.general Subject: Re: realpath() depends on a mounted /proc to work Date: Thu, 3 Nov 2016 18:03:21 +0100 Message-ID: <20161103170321.GA28912@alpha.fifth.space> References: <20160607011538.GU10893@brightrain.aerifal.cx> <20160607084521.08cf94ec@vostro.util.wtbts.net> <20160608175032.GV10893@brightrain.aerifal.cx> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="VqG+RLxVPb8Xon/g" Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1478192650 15809 195.159.176.226 (3 Nov 2016 17:04:10 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Thu, 3 Nov 2016 17:04:10 +0000 (UTC) User-Agent: Mutt/1.6.2 (2016-07-01) To: musl@lists.openwall.com Original-X-From: musl-return-10714-gllmg-musl=m.gmane.org@lists.openwall.com Thu Nov 03 18:04:06 2016 Return-path: Envelope-to: gllmg-musl@m.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by blaine.gmane.org with smtp (Exim 4.84_2) (envelope-from ) id 1c2LQX-0001GF-QI for gllmg-musl@m.gmane.org; Thu, 03 Nov 2016 18:03:45 +0100 Original-Received: (qmail 11449 invoked by uid 550); 3 Nov 2016 17:03:46 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Original-Received: (qmail 11397 invoked from network); 3 Nov 2016 17:03:44 -0000 Content-Disposition: inline In-Reply-To: <20160608175032.GV10893@brightrain.aerifal.cx> Xref: news.gmane.org gmane.linux.lib.musl.general:10701 Archived-At: --VqG+RLxVPb8Xon/g Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit Hi, > > > > I observed that realpath() doesn't work correctly without a mounted > > > > /proc while experimenting in a chroot system, where musl is the > > > > default libc. OTOH, the same program statically linked against glibc > > > > worked just as expected. […] > > Given the above, I would vote realpath() to have fallback code. It's > > far more widely used, and would fix several chroot usage scenarios. > > That seems reasonable. Fallback code should avoid using significant > additional stack space and should probably only be used if the proc > version fails with ENOENT (proc not mounted) and not on transient > errors, so that it doesn't become a bug surface that could affect > properly configured systems under low-resource conditions. I encountered the same issue and after finding this thread I decided to have a go at implementing a naive realpath fallback. I tried to follow the coding style of what I saw in musl but I'm not sure which approach would be preferred so I joint two patches to this mail, first using pointers, second using array indexes. I'll gladly rework on this first batch if you're interested in it but not satisfied yet with it. Thanks! --VqG+RLxVPb8Xon/g Content-Type: text/plain; charset=utf-8 Content-Disposition: attachment; filename="0001-realpath-add-fallback-processing-without-proc_pointers.patch" >From 5c2c2717e4bd8cf8a9f816c043e102e317e1d949 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Tue, 1 Nov 2016 12:53:53 +0100 Subject: [PATCH] realpath: add fallback processing without /proc --- src/misc/realpath.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/src/misc/realpath.c b/src/misc/realpath.c index 88c849c..b387b59 100644 --- a/src/misc/realpath.c +++ b/src/misc/realpath.c @@ -9,13 +9,48 @@ void __procfdname(char *, unsigned); +int mergepaths(char *restrict absolute, const char *restrict relative) +{ + char *a = absolute; + const char *r = relative; + + /* if relative is absolute, skip absolute */ + if (*r == '/') { + *a = '/'; + ++r; + } else { + /* slash terminate absolute if needed */ + for (; *a; ++a); + if (*r && (a[-1] != '/')) *a = '/'; + else --a; + } + + /* resolve . and .. */ + for (; *r; ++r) { + if (*r == '.') { + if (r[1] == '/' || !r[1]) continue; + if (r[1] == '.' && (r[2] == '/' || !r[2])) { + while (a > absolute && *--a != '/'); + continue; + } + } else if (*r == '/' && *a == '/') continue; + *++a = *r; + } + /* terminate absolute */ + if (*a == '/' && a > absolute) --a; + *++a = 0; + + return a - absolute; +} + char *realpath(const char *restrict filename, char *restrict resolved) { int fd; ssize_t r; struct stat st1, st2; char buf[15+3*sizeof(int)]; - char tmp[PATH_MAX]; + char tmp[PATH_MAX], link[PATH_MAX]; + char *p; if (!filename) { errno = EINVAL; @@ -27,7 +62,7 @@ char *realpath(const char *restrict filename, char *restrict resolved) __procfdname(buf, fd); r = readlink(buf, tmp, sizeof tmp - 1); - if (r < 0) goto err; + if (r < 0) goto noproc; tmp[r] = 0; fstat(fd, &st1); @@ -37,8 +72,34 @@ char *realpath(const char *restrict filename, char *restrict resolved) goto err; } +end: __syscall(SYS_close, fd); return resolved ? strcpy(resolved, tmp) : strdup(tmp); + +noproc: + if (*filename != '/') + if (syscall(SYS_getcwd, tmp, sizeof(tmp)) < 0) goto err; + + /* concatenate cwd and target */ + r = mergepaths(tmp, filename); + + if (lstat(tmp, &st1) < 0) goto err; + /* resolve link chain if any */ + while (S_ISLNK(st1.st_mode)) { + if ((r = readlink(tmp, link, sizeof(link))) < 0) goto err; + link[r] = 0; + + /* remove link name */ + for (p = tmp; *p; ++p); + while (p > tmp && *--p != '/'); + *p = 0; + + /* merge path and link target */ + mergepaths(tmp, link); + if (lstat(tmp, &st1) < 0) goto err; + } + goto end; + err: __syscall(SYS_close, fd); return 0; -- 2.10.2 --VqG+RLxVPb8Xon/g Content-Type: text/plain; charset=utf-8 Content-Disposition: attachment; filename="0001-realpath-add-fallback-processing-without-proc_arrays.patch" >From 304b193729b4eb5218218a71320cb5c93b1d19ca Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Tue, 1 Nov 2016 12:53:53 +0100 Subject: [PATCH] realpath: add fallback processing without /proc --- src/misc/realpath.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/src/misc/realpath.c b/src/misc/realpath.c index 88c849c..e48420d 100644 --- a/src/misc/realpath.c +++ b/src/misc/realpath.c @@ -9,13 +9,48 @@ void __procfdname(char *, unsigned); +int mergepaths(char *restrict a, const char *restrict r) +{ + size_t i, j; + i = j = 0; + + /* if r is absolute, skip a content */ + if (r[0] == '/') { + a[0] = '/'; + j = 1; + } else { + /* slash terminate a if needed */ + i = strlen(a)-1; + if (r[0] && (a[i-1] != '/')) a[i] = '/'; + else --i; + } + + /* resolve . and .. */ + for (; r[j]; ++j) { + if (r[j] == '.') { + if (r[j+1] == '/' || !r[j+1]) continue; + if (r[j+1] == '.' && (r[j+2] == '/' || !r[j+2])) { + while (i > 0 && a[--i] != '/'); + continue; + } + } else if (r[j] == '/' && a[i] == '/') continue; + a[++i] = r[j]; + } + /* terminate a */ + if (a[i] == '/' && i > 0) --i; + a[++i] = 0; + + return i; +} + char *realpath(const char *restrict filename, char *restrict resolved) { int fd; ssize_t r; + size_t i; struct stat st1, st2; char buf[15+3*sizeof(int)]; - char tmp[PATH_MAX]; + char tmp[PATH_MAX], link[PATH_MAX]; if (!filename) { errno = EINVAL; @@ -27,7 +62,7 @@ char *realpath(const char *restrict filename, char *restrict resolved) __procfdname(buf, fd); r = readlink(buf, tmp, sizeof tmp - 1); - if (r < 0) goto err; + if (r < 0) goto noproc; tmp[r] = 0; fstat(fd, &st1); @@ -37,8 +72,34 @@ char *realpath(const char *restrict filename, char *restrict resolved) goto err; } +end: __syscall(SYS_close, fd); return resolved ? strcpy(resolved, tmp) : strdup(tmp); + +noproc: + if (*filename != '/') + if (syscall(SYS_getcwd, tmp, sizeof(tmp)) < 0) goto err; + + /* concatenate cwd and target */ + r = mergepaths(tmp, filename); + + if (lstat(tmp, &st1) < 0) goto err; + /* resolve link chain if any */ + while (S_ISLNK(st1.st_mode)) { + if ((r = readlink(tmp, link, sizeof(link))) < 0) goto err; + link[r] = 0; + + /* remove link name */ + i = strlen(tmp) - 1; + while (i > 0 && tmp[--i] != '/'); + tmp[i] = 0; + + /* merge path and link target */ + mergepaths(tmp, link); + if (lstat(tmp, &st1) < 0) goto err; + } + goto end; + err: __syscall(SYS_close, fd); return 0; -- 2.10.2 --VqG+RLxVPb8Xon/g--