Skip to content

Commit

Permalink
Merge branch 'js/realpath-pathdup-fix'
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gitster committed Mar 13, 2017
2 parents fb070d2 + ce83ead commit ba37c92
Show file tree
Hide file tree
Showing 9 changed files with 25 additions and 17 deletions.
4 changes: 2 additions & 2 deletions abspath.c
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions builtin/init-db.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion cache.h
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions dir.c
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion environment.c
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions setup.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
10 changes: 5 additions & 5 deletions submodule.c
Expand Up @@ -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)
Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions t/t1501-work-tree.sh
Expand Up @@ -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
2 changes: 1 addition & 1 deletion worktree.c
Expand Up @@ -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;
Expand Down

0 comments on commit ba37c92

Please sign in to comment.