Skip to content

Commit aea8cc3

Browse files
committed
Merge branch 'jk/asan-bonanza'
Various issues detected by Asan have been corrected. * jk/asan-bonanza: t: enable ASan's strict_string_checks option fsck: avoid parse_timestamp() on buffer that isn't NUL-terminated fsck: remove redundant date timestamp check fsck: avoid strcspn() in fsck_ident() fsck: assert newline presence in fsck_ident() cache-tree: avoid strtol() on non-string buffer Makefile: turn on NO_MMAP when building with ASan pack-bitmap: handle name-hash lookups in incremental bitmaps compat/mmap: mark unused argument in git_munmap()
2 parents 6912d80 + a031b61 commit aea8cc3

File tree

7 files changed

+122
-40
lines changed

7 files changed

+122
-40
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,7 @@ SANITIZE_LEAK = YesCompiledWithIt
15881588
endif
15891589
ifneq ($(filter address,$(SANITIZERS)),)
15901590
NO_REGEX = NeededForASAN
1591+
NO_MMAP = NeededForASAN
15911592
SANITIZE_ADDRESS = YesCompiledWithIt
15921593
endif
15931594
endif

cache-tree.c

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -548,12 +548,41 @@ void cache_tree_write(struct strbuf *sb, struct cache_tree *root)
548548
trace2_region_leave("cache_tree", "write", the_repository);
549549
}
550550

551+
static int parse_int(const char **ptr, unsigned long *len_p, int *out)
552+
{
553+
const char *s = *ptr;
554+
unsigned long len = *len_p;
555+
int ret = 0;
556+
int sign = 1;
557+
558+
while (len && *s == '-') {
559+
sign *= -1;
560+
s++;
561+
len--;
562+
}
563+
564+
while (len) {
565+
if (!isdigit(*s))
566+
break;
567+
ret *= 10;
568+
ret += *s - '0';
569+
s++;
570+
len--;
571+
}
572+
573+
if (s == *ptr)
574+
return -1;
575+
576+
*ptr = s;
577+
*len_p = len;
578+
*out = sign * ret;
579+
return 0;
580+
}
581+
551582
static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
552583
{
553584
const char *buf = *buffer;
554585
unsigned long size = *size_p;
555-
const char *cp;
556-
char *ep;
557586
struct cache_tree *it;
558587
int i, subtree_nr;
559588
const unsigned rawsz = the_hash_algo->rawsz;
@@ -569,19 +598,14 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
569598
buf++; size--;
570599
it = cache_tree();
571600

572-
cp = buf;
573-
it->entry_count = strtol(cp, &ep, 10);
574-
if (cp == ep)
601+
if (parse_int(&buf, &size, &it->entry_count) < 0)
575602
goto free_return;
576-
cp = ep;
577-
subtree_nr = strtol(cp, &ep, 10);
578-
if (cp == ep)
603+
if (!size || *buf != ' ')
579604
goto free_return;
580-
while (size && *buf && *buf != '\n') {
581-
size--;
582-
buf++;
583-
}
584-
if (!size)
605+
buf++; size--;
606+
if (parse_int(&buf, &size, &subtree_nr) < 0)
607+
goto free_return;
608+
if (!size || *buf != '\n')
585609
goto free_return;
586610
buf++; size--;
587611
if (0 <= it->entry_count) {

compat/mmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
3838
return start;
3939
}
4040

41-
int git_munmap(void *start, size_t length)
41+
int git_munmap(void *start, size_t length UNUSED)
4242
{
4343
free(start);
4444
return 0;

fsck.c

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -860,31 +860,60 @@ static int verify_headers(const void *data, unsigned long size,
860860
FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
861861
}
862862

863-
static int fsck_ident(const char **ident,
863+
static timestamp_t parse_timestamp_from_buf(const char **start, const char *end)
864+
{
865+
const char *p = *start;
866+
char buf[24]; /* big enough for 2^64 */
867+
size_t i = 0;
868+
869+
while (p < end && isdigit(*p)) {
870+
if (i >= ARRAY_SIZE(buf) - 1)
871+
return TIME_MAX;
872+
buf[i++] = *p++;
873+
}
874+
buf[i] = '\0';
875+
*start = p;
876+
return parse_timestamp(buf, NULL, 10);
877+
}
878+
879+
static int fsck_ident(const char **ident, const char *ident_end,
864880
const struct object_id *oid, enum object_type type,
865881
struct fsck_options *options)
866882
{
867883
const char *p = *ident;
868-
char *end;
884+
const char *nl;
869885

870-
*ident = strchrnul(*ident, '\n');
871-
if (**ident == '\n')
872-
(*ident)++;
886+
nl = memchr(p, '\n', ident_end - p);
887+
if (!nl)
888+
BUG("verify_headers() should have made sure we have a newline");
889+
*ident = nl + 1;
873890

874891
if (*p == '<')
875892
return report(options, oid, type, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
876-
p += strcspn(p, "<>\n");
877-
if (*p == '>')
878-
return report(options, oid, type, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
879-
if (*p != '<')
880-
return report(options, oid, type, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
893+
for (;;) {
894+
if (p >= ident_end || *p == '\n')
895+
return report(options, oid, type, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
896+
if (*p == '>')
897+
return report(options, oid, type, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
898+
if (*p == '<')
899+
break; /* end of name, beginning of email */
900+
901+
/* otherwise, skip past arbitrary name char */
902+
p++;
903+
}
881904
if (p[-1] != ' ')
882905
return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
883-
p++;
884-
p += strcspn(p, "<>\n");
885-
if (*p != '>')
886-
return report(options, oid, type, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
887-
p++;
906+
p++; /* skip past '<' we found */
907+
for (;;) {
908+
if (p >= ident_end || *p == '<' || *p == '\n')
909+
return report(options, oid, type, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
910+
if (*p == '>')
911+
break; /* end of email */
912+
913+
/* otherwise, skip past arbitrary email char */
914+
p++;
915+
}
916+
p++; /* skip past '>' we found */
888917
if (*p != ' ')
889918
return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
890919
p++;
@@ -904,11 +933,11 @@ static int fsck_ident(const char **ident,
904933
"invalid author/committer line - bad date");
905934
if (*p == '0' && p[1] != ' ')
906935
return report(options, oid, type, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
907-
if (date_overflows(parse_timestamp(p, &end, 10)))
936+
if (date_overflows(parse_timestamp_from_buf(&p, ident_end)))
908937
return report(options, oid, type, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
909-
if ((end == p || *end != ' '))
938+
if (*p != ' ')
910939
return report(options, oid, type, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
911-
p = end + 1;
940+
p++;
912941
if ((*p != '+' && *p != '-') ||
913942
!isdigit(p[1]) ||
914943
!isdigit(p[2]) ||
@@ -958,7 +987,7 @@ static int fsck_commit(const struct object_id *oid,
958987
author_count = 0;
959988
while (buffer < buffer_end && skip_prefix(buffer, "author ", &buffer)) {
960989
author_count++;
961-
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
990+
err = fsck_ident(&buffer, buffer_end, oid, OBJ_COMMIT, options);
962991
if (err)
963992
return err;
964993
}
@@ -970,7 +999,7 @@ static int fsck_commit(const struct object_id *oid,
970999
return err;
9711000
if (buffer >= buffer_end || !skip_prefix(buffer, "committer ", &buffer))
9721001
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
973-
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
1002+
err = fsck_ident(&buffer, buffer_end, oid, OBJ_COMMIT, options);
9741003
if (err)
9751004
return err;
9761005
if (memchr(buffer_begin, '\0', size)) {
@@ -1065,7 +1094,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
10651094
goto done;
10661095
}
10671096
else
1068-
ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
1097+
ret = fsck_ident(&buffer, buffer_end, oid, OBJ_TAG, options);
10691098

10701099
if (buffer < buffer_end && (skip_prefix(buffer, "gpgsig ", &buffer) || skip_prefix(buffer, "gpgsig-sha256 ", &buffer))) {
10711100
eol = memchr(buffer, '\n', buffer_end - buffer);

meson.build

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,12 +1411,18 @@ if host_machine.system() == 'windows'
14111411
libgit_c_args += '-DUSE_WIN32_MMAP'
14121412
else
14131413
checkfuncs += {
1414-
'mmap' : ['mmap.c'],
14151414
# provided by compat/mingw.c.
14161415
'unsetenv' : ['unsetenv.c'],
14171416
# provided by compat/mingw.c.
14181417
'getpagesize' : [],
14191418
}
1419+
1420+
if get_option('b_sanitize').contains('address')
1421+
libgit_c_args += '-DNO_MMAP'
1422+
libgit_sources += 'compat/mmap.c'
1423+
else
1424+
checkfuncs += { 'mmap': ['mmap.c'] }
1425+
endif
14201426
endif
14211427

14221428
foreach func, impls : checkfuncs

pack-bitmap.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,28 @@ static uint32_t bitmap_num_objects(struct bitmap_index *index)
213213
return index->pack->num_objects;
214214
}
215215

216+
static uint32_t bitmap_name_hash(struct bitmap_index *index, uint32_t pos)
217+
{
218+
if (bitmap_is_midx(index)) {
219+
while (index && pos < index->midx->num_objects_in_base) {
220+
ASSERT(bitmap_is_midx(index));
221+
index = index->base;
222+
}
223+
224+
if (!index)
225+
BUG("NULL base bitmap for object position: %"PRIu32, pos);
226+
227+
pos -= index->midx->num_objects_in_base;
228+
if (pos >= index->midx->num_objects)
229+
BUG("out-of-bounds midx bitmap object at %"PRIu32, pos);
230+
}
231+
232+
if (!index->hashes)
233+
return 0;
234+
235+
return get_be32(index->hashes + pos);
236+
}
237+
216238
static struct repository *bitmap_repo(struct bitmap_index *bitmap_git)
217239
{
218240
if (bitmap_is_midx(bitmap_git))
@@ -1724,8 +1746,7 @@ static void show_objects_for_type(
17241746
pack = bitmap_git->pack;
17251747
}
17261748

1727-
if (bitmap_git->hashes)
1728-
hash = get_be32(bitmap_git->hashes + index_pos);
1749+
hash = bitmap_name_hash(bitmap_git, index_pos);
17291750

17301751
show_reach(&oid, object_type, 0, hash, pack, ofs, payload);
17311752
}
@@ -3124,8 +3145,8 @@ uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
31243145

31253146
if (oe) {
31263147
reposition[i] = oe_in_pack_pos(mapping, oe) + 1;
3127-
if (bitmap_git->hashes && !oe->hash)
3128-
oe->hash = get_be32(bitmap_git->hashes + index_pos);
3148+
if (!oe->hash)
3149+
oe->hash = bitmap_name_hash(bitmap_git, index_pos);
31293150
}
31303151
}
31313152

t/test-lib.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ prepend_var GIT_SAN_OPTIONS : strip_path_prefix="$GIT_BUILD_DIR/"
7777
# want that one to complain to stderr).
7878
prepend_var ASAN_OPTIONS : $GIT_SAN_OPTIONS
7979
prepend_var ASAN_OPTIONS : detect_leaks=0
80+
prepend_var ASAN_OPTIONS : strict_string_checks=1
8081
export ASAN_OPTIONS
8182

8283
prepend_var LSAN_OPTIONS : $GIT_SAN_OPTIONS

0 commit comments

Comments
 (0)