Skip to content

Commit dc732bd

Browse files
peffgitster
authored andcommitted
read_info_alternates: read contents into strbuf
This patch fixes a regression in v2.11.1 where we might read past the end of an mmap'd buffer. It was introduced in cf3c635. The link_alt_odb_entries() function has always taken a ptr/len pair as input. Until cf3c635 (alternates: accept double-quoted paths, 2016-12-12), we made a copy of those bytes in a string. But after that commit, we switched to parsing the input left-to-right, and we ignore "len" totally, instead reading until we hit a NUL. This has mostly gone unnoticed for a few reasons: 1. All but one caller passes a NUL-terminated string, with "len" pointing to the NUL. 2. The remaining caller, read_info_alternates(), passes in an mmap'd file. Unless the file is an exact multiple of the page size, it will generally be followed by NUL padding to the end of the page, which just works. The easiest way to demonstrate the problem is to build with: make SANITIZE=address NO_MMAP=Nope test Any test which involves $GIT_DIR/info/alternates will fail, as the mmap emulation (correctly) does not add an extra NUL, and ASAN complains about reading past the end of the buffer. One solution would be to teach link_alt_odb_entries() to respect "len". But it's actually a bit tricky, since we depend on unquote_c_style() under the hood, and it has no ptr/len variant. We could also just make a NUL-terminated copy of the input bytes and operate on that. But since all but one caller already is passing a string, instead let's just fix that caller to provide NUL-terminated input in the first place, by swapping out mmap for strbuf_read_file(). There's no advantage to using mmap on the alternates file. It's not expected to be large (and anyway, we're copying its contents into an in-memory linked list). Nor is using git_open() buying us anything here, since we don't keep the descriptor open for a long period of time. Let's also drop the "len" parameter entirely from link_alt_odb_entries(), since it's completely ignored. That will avoid any new callers re-introducing a similar bug. Reported-by: Michael Haggerty <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3b82744 commit dc732bd

File tree

1 file changed

+10
-20
lines changed

1 file changed

+10
-20
lines changed

sha1_file.c

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ static const char *parse_alt_odb_entry(const char *string,
359359
return end;
360360
}
361361

362-
static void link_alt_odb_entries(const char *alt, int len, int sep,
362+
static void link_alt_odb_entries(const char *alt, int sep,
363363
const char *relative_base, int depth)
364364
{
365365
struct strbuf objdirbuf = STRBUF_INIT;
@@ -388,28 +388,18 @@ static void link_alt_odb_entries(const char *alt, int len, int sep,
388388

389389
void read_info_alternates(const char * relative_base, int depth)
390390
{
391-
char *map;
392-
size_t mapsz;
393-
struct stat st;
394391
char *path;
395-
int fd;
392+
struct strbuf buf = STRBUF_INIT;
396393

397394
path = xstrfmt("%s/info/alternates", relative_base);
398-
fd = git_open(path);
399-
free(path);
400-
if (fd < 0)
401-
return;
402-
if (fstat(fd, &st) || (st.st_size == 0)) {
403-
close(fd);
395+
if (strbuf_read_file(&buf, path, 1024) < 0) {
396+
free(path);
404397
return;
405398
}
406-
mapsz = xsize_t(st.st_size);
407-
map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0);
408-
close(fd);
409-
410-
link_alt_odb_entries(map, mapsz, '\n', relative_base, depth);
411399

412-
munmap(map, mapsz);
400+
link_alt_odb_entries(buf.buf, '\n', relative_base, depth);
401+
strbuf_release(&buf);
402+
free(path);
413403
}
414404

415405
struct alternate_object_database *alloc_alt_odb(const char *dir)
@@ -464,7 +454,7 @@ void add_to_alternates_file(const char *reference)
464454
if (commit_lock_file(lock))
465455
die_errno("unable to move new alternates file into place");
466456
if (alt_odb_tail)
467-
link_alt_odb_entries(reference, strlen(reference), '\n', NULL, 0);
457+
link_alt_odb_entries(reference, '\n', NULL, 0);
468458
}
469459
free(alts);
470460
}
@@ -477,7 +467,7 @@ void add_to_alternates_memory(const char *reference)
477467
*/
478468
prepare_alt_odb();
479469

480-
link_alt_odb_entries(reference, strlen(reference), '\n', NULL, 0);
470+
link_alt_odb_entries(reference, '\n', NULL, 0);
481471
}
482472

483473
/*
@@ -581,7 +571,7 @@ void prepare_alt_odb(void)
581571
if (!alt) alt = "";
582572

583573
alt_odb_tail = &alt_odb_list;
584-
link_alt_odb_entries(alt, strlen(alt), PATH_SEP, NULL, 0);
574+
link_alt_odb_entries(alt, PATH_SEP, NULL, 0);
585575

586576
read_info_alternates(get_object_directory(), 0);
587577
}

0 commit comments

Comments
 (0)