Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Feb 2003 18:37:38 +0100
From:      Johan Karlsson <johan@freebsd.org>
To:        audit@freebsd.org, Sheldon Hearn <sheldonh@starjuice.net>
Subject:   realpath(3) improvement
Message-ID:  <20030202173738.GA759@numeri.campus.luth.se>

next in thread | raw e-mail | index | archive | help

--FL5UXtIhxfXey3p5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi

I intend to commit the attached patch to realpath(3) unless
there are objections.

Currently realpath(3) return an error if current directory 
is unreadable.

k@numeri ~/realpathtes >ll
total 8
drwxr-xr-x   3 k  staff   512 Feb  2 17:52 ./
drwxr-xr-x  55 k  staff  3584 Feb  2 17:44 ../
d-wx--x--x   3 k  staff   512 Feb  2 16:29 realpathtest/
k@numeri ~/realpathtes >cd realpathtest/
k@numeri ~/realpathtes/realpathtest >/bin/realpath home
realpath: .: Permission denied
k@numeri ~/realpathtes/realpathtest >


With the attached patch one get
k@numeri ~/realpathtes/realpathtest >/home/builds/home/k/FreeBSD-src/current/src/bin/realpath/realpath /home
/home
k@numeri ~/realpathtes/realpathtest >

The problem is in libc not in bin/realpath.

The patch to correct this is from PR 12244.

The attached patch also changes realpath(3) to use strlcpy instead
of strncpy (submitted by imp@). Accordning to strncpy(3) it is 
preferable to use strlcpy when portablility isn't an issue.
I would like to know if this is ok to commit as well.

Please have a look at the attached patch and let me know if
you find any problems with it.

Take care
/Johan K

-- 
Johan Karlsson		mailto:johan@FreeBSD.org

--FL5UXtIhxfXey3p5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="realpath.c.diff"

Index: lib/libc/stdlib/realpath.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/stdlib/realpath.c,v
retrieving revision 1.12
diff -u -r1.12 realpath.c
--- lib/libc/stdlib/realpath.c	15 Jan 2003 21:22:55 -0000	1.12
+++ lib/libc/stdlib/realpath.c	2 Feb 2003 17:01:49 -0000
@@ -65,13 +65,19 @@
 {
 	struct stat sb;
 	int fd, n, rootd, serrno;
-	char *p, *q, wbuf[PATH_MAX];
+	char *p, *q, scwd[PATH_MAX], wbuf[PATH_MAX];
 	int symlinks = 0;
 
-	/* Save the starting point. */
+	/*
+	 * Save the starting point:
+	 * First, try open()/fchdir() method and, if this fails,
+	 * then try getcwd()/chdir().
+	 */
 	if ((fd = _open(".", O_RDONLY)) < 0) {
-		(void)strcpy(resolved, ".");
-		return (NULL);
+		if (getcwd(scwd, PATH_MAX) == 0) {
+			(void)strcpy(resolved, ".");
+			return (NULL);
+		}
 	}
 
 	/*
@@ -82,8 +88,7 @@
 	 *     if it is a directory, then change to that directory.
 	 * get the current directory name and append the basename.
 	 */
-	(void)strncpy(resolved, path, PATH_MAX - 1);
-	resolved[PATH_MAX - 1] = '\0';
+	(void)strlcpy(resolved, path, PATH_MAX);
 loop:
 	q = strrchr(resolved, '/');
 	if (q != NULL) {
@@ -98,7 +103,7 @@
 			q = resolved;
 		}
 		if (chdir(q) < 0)
-			goto err1;
+			goto err;
 	} else
 		p = resolved;
 
@@ -107,17 +112,17 @@
 		if (S_ISLNK(sb.st_mode)) {
 			if (++symlinks > MAXSYMLINKS) {
 				errno = ELOOP;
-				goto err1;
+				goto err;
 			}
 			n = readlink(p, resolved, PATH_MAX - 1);
 			if (n < 0)
-				goto err1;
+				goto err;
 			resolved[n] = '\0';
 			goto loop;
 		}
 		if (S_ISDIR(sb.st_mode)) {
 			if (chdir(p) < 0)
-				goto err1;
+				goto err;
 			p = "";
 		}
 	}
@@ -128,7 +133,7 @@
 	 */
 	(void)strcpy(wbuf, p);
 	if (getcwd(resolved, PATH_MAX) == 0)
-		goto err1;
+		goto err;
 
 	/*
 	 * Join the two strings together, ensuring that the right thing
@@ -142,26 +147,38 @@
 	if (*wbuf) {
 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > PATH_MAX) {
 			errno = ENAMETOOLONG;
-			goto err1;
+			goto err;
 		}
 		if (rootd == 0)
 			(void)strcat(resolved, "/");
 		(void)strcat(resolved, wbuf);
 	}
 
-	/* Go back to where we came from. */
-	if (fchdir(fd) < 0) {
-		serrno = errno;
-		goto err2;
+	/*
+	 * Go back to where we came from. If fd < 0, we are using the
+	 * getcwd()/chdir() method; else, we are using open()/fchdir().
+	 */
+	if (fd < 0) {
+		if (chdir(scwd) < 0)
+			return (NULL);
+	} else  if (fchdir(fd) < 0) {
+			serrno = errno;
+			(void)_close(fd);
+			errno = serrno;
+			return (NULL);
 	}
 
 	/* It's okay if the close fails, what's an fd more or less? */
 	(void)_close(fd);
 	return (resolved);
 
-err1:	serrno = errno;
-	(void)fchdir(fd);
-err2:	(void)_close(fd);
+err:	serrno = errno;
+	if (fd < 0)
+		(void)chdir(scwd);
+	else {
+		(void)fchdir(fd);
+		(void)_close(fd);
+	}
 	errno = serrno;
 	return (NULL);
 }

--FL5UXtIhxfXey3p5--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030202173738.GA759>