Skip to content

Commit 9cb18f5

Browse files
meyeringgitster
authored andcommitted
Don't smash stack when $GIT_ALTERNATE_OBJECT_DIRECTORIES is too long
There is no restriction on the length of the name returned by get_object_directory, other than the fact that it must be a stat'able git object directory. That means its name may have length up to PATH_MAX-1 (i.e., often 4095) not counting the trailing NUL. Combine that with the assumption that the concatenation of that name and suffixes like "/info/alternates" and "/pack/---long-name---.idx" will fit in a buffer of length PATH_MAX, and you see the problem. Here's a fix: sha1_file.c (prepare_packed_git_one): Lengthen "path" buffer so we are guaranteed to be able to append "/pack/" without checking. Skip any directory entry that is too long to be appended. (read_info_alternates): Protect against a similar buffer overrun. Before this change, using the following admittedly contrived environment setting would cause many git commands to clobber their stack and segfault on a system with PATH_MAX == 4096: t=$(perl -e '$s=".git/objects";$n=(4096-6-length($s))/2;print "./"x$n . $s') export GIT_ALTERNATE_OBJECT_DIRECTORIES=$t touch g ./git-update-index --add g If you run the above commands, you'll soon notice that many git commands now segfault, so you'll want to do this: unset GIT_ALTERNATE_OBJECT_DIRECTORIES Signed-off-by: Jim Meyering <jim@meyering.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent e8964a5 commit 9cb18f5

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

sha1_file.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,14 @@ static void read_info_alternates(const char * relative_base, int depth)
352352
char *map;
353353
size_t mapsz;
354354
struct stat st;
355-
char path[PATH_MAX];
355+
const char alt_file_name[] = "info/alternates";
356+
/* Given that relative_base is no longer than PATH_MAX,
357+
ensure that "path" has enough space to append "/", the
358+
file name, "info/alternates", and a trailing NUL. */
359+
char path[PATH_MAX + 1 + sizeof alt_file_name];
356360
int fd;
357361

358-
sprintf(path, "%s/info/alternates", relative_base);
362+
sprintf(path, "%s/%s", relative_base, alt_file_name);
359363
fd = open(path, O_RDONLY);
360364
if (fd < 0)
361365
return;
@@ -814,7 +818,10 @@ void install_packed_git(struct packed_git *pack)
814818

815819
static void prepare_packed_git_one(char *objdir, int local)
816820
{
817-
char path[PATH_MAX];
821+
/* Ensure that this buffer is large enough so that we can
822+
append "/pack/" without clobbering the stack even if
823+
strlen(objdir) were PATH_MAX. */
824+
char path[PATH_MAX + 1 + 4 + 1 + 1];
818825
int len;
819826
DIR *dir;
820827
struct dirent *de;
@@ -836,6 +843,9 @@ static void prepare_packed_git_one(char *objdir, int local)
836843
if (!has_extension(de->d_name, ".idx"))
837844
continue;
838845

846+
if (len + namelen + 1 > sizeof(path))
847+
continue;
848+
839849
/* Don't reopen a pack we already have. */
840850
strcpy(path + len, de->d_name);
841851
for (p = packed_git; p; p = p->next) {

0 commit comments

Comments
 (0)