From 88135203af9df27c0f9c76c27bbbf48833bb31c8 Mon Sep 17 00:00:00 2001 From: Theo Niessink Date: Fri, 27 May 2011 18:00:38 +0200 Subject: [PATCH 1/5] A Windows path starting with a backslash is absolute This fixes prefix_path() not recognizing e.g. \foo\bar as an absolute path on Windows. Signed-off-by: Theo Niessink Signed-off-by: Erik Faye-Lund Signed-off-by: Junio C Hamano --- cache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache.h b/cache.h index 5e9675d76d..9d3d92cf9e 100644 --- a/cache.h +++ b/cache.h @@ -715,7 +715,7 @@ extern char *expand_user_path(const char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { - return path[0] == '/' || has_dos_drive_prefix(path); + return is_dir_sep(path[0]) || has_dos_drive_prefix(path); } int is_directory(const char *); const char *make_absolute_path(const char *path); From d1c69255a1014ccaeb9841f2114e20f048556391 Mon Sep 17 00:00:00 2001 From: Theo Niessink Date: Fri, 27 May 2011 18:00:39 +0200 Subject: [PATCH 2/5] real_path: do not assume '/' is the path seperator real_path currently assumes it's input had '/' as path seperator. This assumption does not hold true for the code-path from prefix_path (on Windows), where real_path can be called before normalize_path_copy. Fix real_path so it doesn't make this assumption. Create a helper function to reverse-search for the last path-seperator in a string. Signed-off-by: Theo Niessink Signed-off-by: Erik Faye-Lund Signed-off-by: Junio C Hamano --- abspath.c | 4 ++-- compat/mingw.h | 9 +++++++++ git-compat-util.h | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/abspath.c b/abspath.c index ff140689ed..54899008f8 100644 --- a/abspath.c +++ b/abspath.c @@ -33,7 +33,7 @@ const char *make_absolute_path(const char *path) while (depth--) { if (!is_directory(buf)) { - char *last_slash = strrchr(buf, '/'); + char *last_slash = find_last_dir_sep(buf); if (last_slash) { *last_slash = '\0'; last_elem = xstrdup(last_slash + 1); @@ -58,7 +58,7 @@ const char *make_absolute_path(const char *path) if (len + strlen(last_elem) + 2 > PATH_MAX) die ("Too long path name: '%s/%s'", buf, last_elem); - if (len && buf[len-1] != '/') + if (len && !is_dir_sep(buf[len-1])) buf[len++] = '/'; strcpy(buf + len, last_elem); free(last_elem); diff --git a/compat/mingw.h b/compat/mingw.h index 14211c6214..bea909d76f 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -299,6 +299,15 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +static inline char *mingw_find_last_dir_sep(const char *path) +{ + char *ret = NULL; + for (; *path; ++path) + if (is_dir_sep(*path)) + ret = (char *)path; + return ret; +} +#define find_last_dir_sep mingw_find_last_dir_sep #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 79b5122b4f..15bf3ef810 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -215,6 +215,10 @@ extern char *gitbasename(char *); #define is_dir_sep(c) ((c) == '/') #endif +#ifndef find_last_dir_sep +#define find_last_dir_sep(path) strrchr(path, '/') +#endif + #if __HP_cc >= 61000 #define NORETURN __attribute__((noreturn)) #define NORETURN_PTR From 56948cb6aa8189e3b77c700119d179172e0f8c4a Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Fri, 27 May 2011 18:00:40 +0200 Subject: [PATCH 3/5] verify_path: consider dos drive prefix If someone manage to create a repo with a 'C:' entry in the root-tree, files can be written outside of the working-dir. This opens up a can-of-worms of exploits. Fix it by explicitly checking for a dos drive prefix when verifying a paht. While we're at it, make sure that paths beginning with '\' is considered absolute as well. Noticed-by: Theo Niessink Signed-off-by: Erik Faye-Lund Signed-off-by: Junio C Hamano --- read-cache.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/read-cache.c b/read-cache.c index 0480d9455c..31cf0b503a 100644 --- a/read-cache.c +++ b/read-cache.c @@ -774,11 +774,14 @@ int verify_path(const char *path) { char c; + if (has_dos_drive_prefix(path)) + return 0; + goto inside; for (;;) { if (!c) return 1; - if (c == '/') { + if (is_dir_sep(c)) { inside: c = *path++; switch (c) { From 3bdf09c7f555d553b4fee00c00c760b546812d4f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 6 Jun 2011 20:49:06 -0700 Subject: [PATCH 4/5] verify_path(): simplify check at the directory boundary We simply want to say "At a directory boundary, be careful with a name that begins with a dot, forbid a name that ends with the boundary character or has duplicated bounadry characters". Signed-off-by: Junio C Hamano --- read-cache.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/read-cache.c b/read-cache.c index 31cf0b503a..3593291f7c 100644 --- a/read-cache.c +++ b/read-cache.c @@ -784,16 +784,9 @@ int verify_path(const char *path) if (is_dir_sep(c)) { inside: c = *path++; - switch (c) { - default: - continue; - case '/': case '\0': - break; - case '.': - if (verify_dotfile(path)) - continue; - } - return 0; + if ((c == '.' && !verify_dotfile(path)) || + is_dir_sep(c) || c == '\0') + return 0; } c = *path++; } From e0f530ff8afbd252170f57e70a8609a83a7cabe1 Mon Sep 17 00:00:00 2001 From: Theo Niessink Date: Wed, 8 Jun 2011 14:04:41 +0200 Subject: [PATCH 5/5] verify_dotfile(): do not assume '/' is the path seperator verify_dotfile() currently assumes that the path seperator is '/', but on Windows it can also be '\\', so use is_dir_sep() instead. Signed-off-by: Theo Niessink Signed-off-by: Junio C Hamano --- read-cache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/read-cache.c b/read-cache.c index 3593291f7c..e7c9684218 100644 --- a/read-cache.c +++ b/read-cache.c @@ -747,11 +747,12 @@ static int verify_dotfile(const char *rest) * has already been discarded, we now test * the rest. */ - switch (*rest) { + /* "." is not allowed */ - case '\0': case '/': + if (*rest == '\0' || is_dir_sep(*rest)) return 0; + switch (*rest) { /* * ".git" followed by NUL or slash is bad. This * shares the path end test with the ".." case. @@ -764,7 +765,7 @@ static int verify_dotfile(const char *rest) rest += 2; /* fallthrough */ case '.': - if (rest[1] == '\0' || rest[1] == '/') + if (rest[1] == '\0' || is_dir_sep(rest[1])) return 0; } return 1;