mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Quentin Rameau <quinq@fifth.space>
To: musl@lists.openwall.com
Subject: Re: realpath() depends on a mounted /proc to work
Date: Thu, 3 Nov 2016 18:03:21 +0100	[thread overview]
Message-ID: <20161103170321.GA28912@alpha.fifth.space> (raw)
In-Reply-To: <20160608175032.GV10893@brightrain.aerifal.cx>

[-- Attachment #1: Type: text/plain, Size: 1183 bytes --]

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!

[-- Attachment #2: 0001-realpath-add-fallback-processing-without-proc_pointers.patch --]
[-- Type: text/plain, Size: 2619 bytes --]

From 5c2c2717e4bd8cf8a9f816c043e102e317e1d949 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
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


[-- Attachment #3: 0001-realpath-add-fallback-processing-without-proc_arrays.patch --]
[-- Type: text/plain, Size: 2581 bytes --]

From 304b193729b4eb5218218a71320cb5c93b1d19ca Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
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


      reply	other threads:[~2016-11-03 17:03 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-07  0:27 Lei Zhang
2016-06-07  1:15 ` Rich Felker
2016-06-07  5:17   ` Luca Barbato
2016-06-07  5:45   ` Timo Teras
2016-06-07  7:13     ` FRIGN
2016-06-08 17:50     ` Rich Felker
2016-11-03 17:03       ` Quentin Rameau [this message]

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=20161103170321.GA28912@alpha.fifth.space \
    --to=quinq@fifth.space \
    --cc=musl@lists.openwall.com \
    /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.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).