[syslinux:master] core, chdir: collapse slashes, avoid copy-to-self

syslinux-bot for H. Peter Anvin hpa at zytor.com
Sun Jun 27 18:54:13 PDT 2010


Commit-ID:  7e63729cfd781f69f7cb47b85cf8b1fee6b3e62a
Gitweb:     http://syslinux.zytor.com/commit/7e63729cfd781f69f7cb47b85cf8b1fee6b3e62a
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Sun, 27 Jun 2010 18:46:36 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Sun, 27 Jun 2010 18:46:36 -0700

core, chdir: collapse slashes, avoid copy-to-self

Collapse multiple slashes into one (this still doesn't resolve . and
.. in the path, since that requires awareness of symlinks.)

This code also avoids a copy-over-self bug by introducing a temporary
buffer.

Reported-by: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 core/fs/chdir.c |   59 ++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index bfce9bc..9e8dfd2 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -16,15 +16,56 @@ void pm_realpath(com32sys_t *regs)
     realpath(dst, src, FILENAME_MAX);
 }
 
+#define EMIT(x)		     		\
+do {		     			\
+    if (++n < bufsize)	 		\
+    	*q++ = (x);			\
+} while (0)
+
+static size_t join_paths(char *dst, size_t bufsize,
+			 const char *s1, const char *s2)
+{
+    const char *list[2];
+    int i;
+    char c;
+    const char *p;
+    char *q  = dst;
+    size_t n = 0;
+    bool slash = false;
+    
+    list[0] = s1;
+    list[1] = s2;
+
+    for (i = 0; i < 2; i++) {
+	p = list[i];
+
+	while ((c = *p++)) {
+	    if (c == '/') {
+		if (!slash)
+		    EMIT(c);
+		slash = true;
+	    } else {
+		EMIT(c);
+		slash = false;
+	    }
+	}
+    }
+
+    if (bufsize)
+	*q = '\0';
+
+    return n;
+}
+
 size_t realpath(char *dst, const char *src, size_t bufsize)
 {
     if (this_fs->fs_ops->realpath) {
 	return this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
     } else {
 	/* Filesystems with "common" pathname resolution */
-	return snprintf(dst, bufsize, "%s%s",
-			src[0] == '/' ? "" : this_fs->cwd_name,
-			src);
+	return join_paths(dst, bufsize, 
+			  src[0] == '/' ? "" : this_fs->cwd_name,
+			  src);
     }
 }
 
@@ -32,7 +73,7 @@ int chdir(const char *src)
 {
     int rv;
     struct file *file;
-    char *p;
+    char cwd_buf[CURRENTDIR_MAX];
 
     if (this_fs->fs_ops->chdir)
 	return this_fs->fs_ops->chdir(this_fs, src);
@@ -53,14 +94,10 @@ int chdir(const char *src)
     _close_file(file);
 
     /* Save the current working directory */
-    realpath(this_fs->cwd_name, src, CURRENTDIR_MAX);
-    p = strchr(this_fs->cwd_name, '\0');
+    realpath(cwd_buf, src, CURRENTDIR_MAX);
 
     /* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */
-    if (p < this_fs->cwd_name + CURRENTDIR_MAX - 1 &&
-	(p == this_fs->cwd_name || p[1] != '/')) {
-	p[0] = '/';
-	p[1] = '\0';
-    }
+    join_paths(this_fs->cwd_name, CURRENTDIR_MAX, cwd_buf, "/");
+
     return 0;
 }



More information about the Syslinux-commits mailing list