From 41284eb0f944fe2d73708bb4105a8e3ccd0297df Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 21 Oct 2015 13:54:11 -0400 Subject: name-hash: don't reuse cache_entry in dir_entry Stop reusing cache_entry in dir_entry; doing so causes a use-after-free bug. During merges, we free entries that we no longer need in the destination index. But those entries might have also been stored in the dir_entry cache, and when a later call to add_to_index found them, they would be used after being freed. To prevent this, change dir_entry to store a copy of the name instead of a pointer to a cache_entry. This entails some refactoring of code that expects the cache_entry. Keith McGuigan diagnosed this bug and wrote the initial patch, but this version does not use any of Keith's code. Helped-by: Keith McGuigan Helped-by: Junio C Hamano Signed-off-by: David Turner Signed-off-by: Junio C Hamano --- dir.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'dir.c') diff --git a/dir.c b/dir.c index 3f7a0256b6..8545922ee2 100644 --- a/dir.c +++ b/dir.c @@ -964,29 +964,15 @@ enum exist_status { */ static enum exist_status directory_exists_in_index_icase(const char *dirname, int len) { - const struct cache_entry *ce = cache_dir_exists(dirname, len); - unsigned char endchar; + struct cache_entry *ce; - if (!ce) - return index_nonexistent; - endchar = ce->name[len]; - - /* - * The cache_entry structure returned will contain this dirname - * and possibly additional path components. - */ - if (endchar == '/') + if (cache_dir_exists(dirname, len)) return index_directory; - /* - * If there are no additional path components, then this cache_entry - * represents a submodule. Submodules, despite being directories, - * are stored in the cache without a closing slash. - */ - if (!endchar && S_ISGITLINK(ce->ce_mode)) + ce = cache_file_exists(dirname, len, ignore_case); + if (ce && S_ISGITLINK(ce->ce_mode)) return index_gitdir; - /* This should never be hit, but it exists just in case. */ return index_nonexistent; } -- cgit v1.3