Merge branch 'js/realpath-pathdup-fix'
authorJunio C Hamano <gitster@pobox.com>
Mon, 13 Mar 2017 06:21:33 +0000 (23:21 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 13 Mar 2017 06:21:33 +0000 (23:21 -0700)
Git v2.12 was shipped with an embarrassing breakage where various
operations that verify paths given from the user stopped dying when
seeing an issue, and instead later triggering segfault.

* js/realpath-pathdup-fix:
real_pathdup(): fix callsites that wanted it to die on error
t1501: demonstrate NULL pointer access with invalid GIT_WORK_TREE

abspath.c
builtin/init-db.c
cache.h
dir.c
environment.c
setup.c
submodule.c
t/t1501-work-tree.sh
worktree.c
index 2f0c26e0e2cbee88aa671f3960d21720e4307aba..b02e068aa347db683b00246061b48bfafabbc1c0 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -214,12 +214,12 @@ const char *real_path_if_valid(const char *path)
        return strbuf_realpath(&realpath, path, 0);
 }
 
-char *real_pathdup(const char *path)
+char *real_pathdup(const char *path, int die_on_error)
 {
        struct strbuf realpath = STRBUF_INIT;
        char *retval = NULL;
 
-       if (strbuf_realpath(&realpath, path, 0))
+       if (strbuf_realpath(&realpath, path, die_on_error))
                retval = strbuf_detach(&realpath, NULL);
 
        strbuf_release(&realpath);
index 1d4d6a0078919636dfc0ffefa2aec1699a9827f1..8a6acb0ec69330f7aae20d34fb5c5733f0058c67 100644 (file)
@@ -338,7 +338,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
 {
        int reinit;
        int exist_ok = flags & INIT_DB_EXIST_OK;
-       char *original_git_dir = real_pathdup(git_dir);
+       char *original_git_dir = real_pathdup(git_dir, 1);
 
        if (real_git_dir) {
                struct stat st;
@@ -489,7 +489,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
 
        if (real_git_dir && !is_absolute_path(real_git_dir))
-               real_git_dir = real_pathdup(real_git_dir);
+               real_git_dir = real_pathdup(real_git_dir, 1);
 
        if (argc == 1) {
                int mkdir_tried = 0;
@@ -560,7 +560,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                const char *git_dir_parent = strrchr(git_dir, '/');
                if (git_dir_parent) {
                        char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
-                       git_work_tree_cfg = real_pathdup(rel);
+                       git_work_tree_cfg = real_pathdup(rel, 1);
                        free(rel);
                }
                if (!git_work_tree_cfg)
diff --git a/cache.h b/cache.h
index 283ab8fb40ecb79d470b5e7984dcd81a98cf3ff6..8c0e6442076eb91571dc0c5cf55db478ab47d2ad 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1150,7 +1150,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
                      int die_on_error);
 const char *real_path(const char *path);
 const char *real_path_if_valid(const char *path);
-char *real_pathdup(const char *path);
+char *real_pathdup(const char *path, int die_on_error);
 const char *absolute_path(const char *path);
 char *absolute_pathdup(const char *path);
 const char *remove_leading_path(const char *in, const char *prefix);
diff --git a/dir.c b/dir.c
index 4541f9e1460cde7945e2443f2fee5c7df18073f5..aeeb5ce10490ef1e0adb907d1e21bcbbbbb401ac 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -2730,8 +2730,8 @@ void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_)
 {
        struct strbuf file_name = STRBUF_INIT;
        struct strbuf rel_path = STRBUF_INIT;
-       char *git_dir = real_pathdup(git_dir_);
-       char *work_tree = real_pathdup(work_tree_);
+       char *git_dir = real_pathdup(git_dir_, 1);
+       char *work_tree = real_pathdup(work_tree_, 1);
 
        /* Update gitfile */
        strbuf_addf(&file_name, "%s/.git", work_tree);
index c07fb17fb70bdb3cdf3ae9ab23196af9a0b7ad1b..42dc3106d2fae1976dcfdfbf264a1a9ed96a71b6 100644 (file)
@@ -259,7 +259,7 @@ void set_git_work_tree(const char *new_work_tree)
                return;
        }
        git_work_tree_initialized = 1;
-       work_tree = real_pathdup(new_work_tree);
+       work_tree = real_pathdup(new_work_tree, 1);
 }
 
 const char *get_git_work_tree(void)
diff --git a/setup.c b/setup.c
index f14cbcd3383528566e37cdf76b1fcf517cd31f1e..8f64fbdfb28fc2e487cfdba76561e5b3a25766f0 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -698,7 +698,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
                if (offset != cwd->len && !is_absolute_path(gitdir))
-                       gitdir = real_pathdup(gitdir);
+                       gitdir = real_pathdup(gitdir, 1);
                if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
                return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
@@ -806,7 +806,7 @@ static int canonicalize_ceiling_entry(struct string_list_item *item,
                /* Keep entry but do not canonicalize it */
                return 1;
        } else {
-               char *real_path = real_pathdup(ceil);
+               char *real_path = real_pathdup(ceil, 0);
                if (!real_path) {
                        return 0;
                }
index 3b98766a6bcfe983e5f94e84edd6fcec7ce74f8d..0a2831d846d27e694ada4bc557a7d54a8bf2d8df 100644 (file)
@@ -1403,7 +1403,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
                /* If it is an actual gitfile, it doesn't need migration. */
                return;
 
-       real_old_git_dir = real_pathdup(old_git_dir);
+       real_old_git_dir = real_pathdup(old_git_dir, 1);
 
        sub = submodule_from_path(null_sha1, path);
        if (!sub)
@@ -1412,7 +1412,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
        new_git_dir = git_path("modules/%s", sub->name);
        if (safe_create_leading_directories_const(new_git_dir) < 0)
                die(_("could not create directory '%s'"), new_git_dir);
-       real_new_git_dir = real_pathdup(new_git_dir);
+       real_new_git_dir = real_pathdup(new_git_dir, 1);
 
        if (!prefix)
                prefix = get_super_prefix();
@@ -1472,14 +1472,14 @@ void absorb_git_dir_into_superproject(const char *prefix,
                new_git_dir = git_path("modules/%s", sub->name);
                if (safe_create_leading_directories_const(new_git_dir) < 0)
                        die(_("could not create directory '%s'"), new_git_dir);
-               real_new_git_dir = real_pathdup(new_git_dir);
+               real_new_git_dir = real_pathdup(new_git_dir, 1);
                connect_work_tree_and_git_dir(path, real_new_git_dir);
 
                free(real_new_git_dir);
        } else {
                /* Is it already absorbed into the superprojects git dir? */
-               char *real_sub_git_dir = real_pathdup(sub_git_dir);
-               char *real_common_git_dir = real_pathdup(get_git_common_dir());
+               char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
+               char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
 
                if (!starts_with(real_sub_git_dir, real_common_git_dir))
                        relocate_single_git_dir_into_superproject(prefix, path);
index cc5b870e5875bab8326393aea3a8d9f944210de6..b06210ec5e8ffa30b59314b1c79ebc9bdb8f6476 100755 (executable)
@@ -423,4 +423,12 @@ test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
        )
 '
 
+test_expect_success 'error out gracefully on invalid $GIT_WORK_TREE' '
+       (
+               GIT_WORK_TREE=/.invalid/work/tree &&
+               export GIT_WORK_TREE &&
+               test_expect_code 128 git rev-parse
+       )
+'
+
 test_done
index d7b911aac730001b466379c26faa390fb21a5bfb..fa7bc67a50a6d52116b0ca994b473668998f1c3f 100644 (file)
@@ -255,7 +255,7 @@ struct worktree *find_worktree(struct worktree **list,
                return wt;
 
        arg = prefix_filename(prefix, strlen(prefix), arg);
-       path = real_pathdup(arg);
+       path = real_pathdup(arg, 1);
        for (; *list; list++)
                if (!fspathcmp(path, real_path((*list)->path)))
                        break;