diff options
Diffstat (limited to 'src')
47 files changed, 488 insertions, 117 deletions
diff --git a/src/array.h b/src/array.h index af9eafa43..ca5a35ffe 100644 --- a/src/array.h +++ b/src/array.h @@ -45,15 +45,28 @@ typedef git_array_t(char) git_array_generic_t; GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size) { volatile git_array_generic_t *a = _a; - uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2; - char *new_array = git__realloc(a->ptr, new_size * item_size); - if (!new_array) { - git_array_clear(*a); - return NULL; + uint32_t new_size; + char *new_array; + + if (a->size < 8) { + new_size = 8; } else { - a->ptr = new_array; a->asize = new_size; a->size++; - return a->ptr + (a->size - 1) * item_size; + if (GIT_ALLOC_OVERFLOW_MULTIPLY(a->size, 3 / 2)) + goto on_oom; + + new_size = a->size * 3 / 2; } + + if (GIT_ALLOC_OVERFLOW_MULTIPLY(new_size, item_size) || + (new_array = git__realloc(a->ptr, new_size * item_size)) == NULL) + goto on_oom; + + a->ptr = new_array; a->asize = new_size; a->size++; + return a->ptr + (a->size - 1) * item_size; + +on_oom: + git_array_clear(*a); + return NULL; } #define git_array_alloc(a) \ diff --git a/src/blame.c b/src/blame.c index 2cc5e552b..4a12cb85b 100644 --- a/src/blame.c +++ b/src/blame.c @@ -76,6 +76,10 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk) hunk->lines_in_hunk, hunk->orig_start_line_number, hunk->orig_path); + + if (!newhunk) + return NULL; + git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id); git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id); newhunk->boundary = hunk->boundary; @@ -221,6 +225,10 @@ static git_blame_hunk *split_hunk_in_vector( new_line_count = hunk->lines_in_hunk - rel_line; nh = new_hunk((uint16_t)(hunk->final_start_line_number+rel_line), (uint16_t)new_line_count, (uint16_t)(hunk->orig_start_line_number+rel_line), hunk->orig_path); + + if (!nh) + return NULL; + git_oid_cpy(&nh->final_commit_id, &hunk->final_commit_id); git_oid_cpy(&nh->orig_commit_id, &hunk->orig_commit_id); @@ -270,6 +278,10 @@ static git_blame_hunk* hunk_from_entry(git_blame__entry *e) { git_blame_hunk *h = new_hunk( e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path); + + if (!h) + return NULL; + git_oid_cpy(&h->final_commit_id, git_commit_id(e->suspect->commit)); git_oid_cpy(&h->orig_commit_id, git_commit_id(e->suspect->commit)); git_signature_dup(&h->final_signature, git_commit_author(e->suspect->commit)); @@ -307,6 +319,8 @@ static int blame_internal(git_blame *blame) blame->final_buf_size = git_blob_rawsize(blame->final_blob); ent = git__calloc(1, sizeof(git_blame__entry)); + GITERR_CHECK_ALLOC(ent); + ent->num_lines = index_blob_lines(blame); ent->lno = blame->options.min_line - 1; ent->num_lines = ent->num_lines - blame->options.min_line + 1; @@ -322,8 +336,9 @@ static int blame_internal(git_blame *blame) cleanup: for (ent = blame->ent; ent; ) { git_blame__entry *e = ent->next; + git_blame_hunk *h = hunk_from_entry(ent); - git_vector_insert(&blame->hunks, hunk_from_entry(ent)); + git_vector_insert(&blame->hunks, h); git_blame__free_entry(ent); ent = e; @@ -392,11 +407,14 @@ static int buffer_hunk_cb( if (!blame->current_hunk) { /* Line added at the end of the file */ blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path); + GITERR_CHECK_ALLOC(blame->current_hunk); + git_vector_insert(&blame->hunks, blame->current_hunk); } else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ /* If this hunk doesn't start between existing hunks, split a hunk up so it does */ blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk, wedge_line - blame->current_hunk->orig_start_line_number, true); + GITERR_CHECK_ALLOC(blame->current_hunk); } return 0; @@ -425,6 +443,8 @@ static int buffer_line_cb( /* Create a new buffer-blame hunk with this line */ shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); blame->current_hunk = new_hunk((uint16_t)blame->current_diff_line, 1, 0, blame->path); + GITERR_CHECK_ALLOC(blame->current_hunk); + git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL); } blame->current_diff_line++; @@ -464,10 +484,14 @@ int git_blame_buffer( assert(out && reference && buffer && buffer_len); blame = git_blame__alloc(reference->repository, reference->options, reference->path); + GITERR_CHECK_ALLOC(blame); /* Duplicate all of the hunk structures in the reference blame */ git_vector_foreach(&reference->hunks, i, hunk) { - git_vector_insert(&blame->hunks, dup_hunk(hunk)); + git_blame_hunk *h = dup_hunk(hunk); + GITERR_CHECK_ALLOC(h); + + git_vector_insert(&blame->hunks, h); } /* Diff to the reference blob */ diff --git a/src/blame_git.c b/src/blame_git.c index 72afb852b..05aef5d99 100644 --- a/src/blame_git.c +++ b/src/blame_git.c @@ -35,10 +35,14 @@ static void origin_decref(git_blame__origin *o) /* Given a commit and a path in it, create a new origin structure. */ static int make_origin(git_blame__origin **out, git_commit *commit, const char *path) { - int error = 0; git_blame__origin *o; + size_t path_len = strlen(path); + int error = 0; + + GITERR_CHECK_ALLOC_ADD(sizeof(*o), path_len); + GITERR_CHECK_ALLOC_ADD(sizeof(*o) + path_len, 1); - o = git__calloc(1, sizeof(*o) + strlen(path) + 1); + o = git__calloc(1, sizeof(*o) + path_len + 1); GITERR_CHECK_ALLOC(o); o->commit = commit; o->refcnt = 1; diff --git a/src/buf_text.c b/src/buf_text.c index cb3661edb..ace54d725 100644 --- a/src/buf_text.c +++ b/src/buf_text.c @@ -29,6 +29,8 @@ int git_buf_text_puts_escaped( scan += count; } + GITERR_CHECK_ALLOC_ADD(buf->size, total); + GITERR_CHECK_ALLOC_ADD(buf->size + total, 1); if (git_buf_grow(buf, buf->size + total + 1) < 0) return -1; @@ -73,8 +75,10 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src) return git_buf_set(tgt, src->ptr, src->size); /* reduce reallocs while in the loop */ + GITERR_CHECK_ALLOC_ADD(src->size, 1); if (git_buf_grow(tgt, src->size + 1) < 0) return -1; + out = tgt->ptr; tgt->size = 0; @@ -117,13 +121,15 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) return git_buf_set(tgt, src->ptr, src->size); /* attempt to reduce reallocs while in the loop */ + GITERR_CHECK_ALLOC_ADD(src->size, src->size >> 4); + GITERR_CHECK_ALLOC_ADD(src->size + (src->size >> 4), 1); if (git_buf_grow(tgt, src->size + (src->size >> 4) + 1) < 0) return -1; tgt->size = 0; for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) { size_t copylen = next - scan; - size_t needsize = tgt->size + copylen + 2 + 1; + size_t needsize; /* if we find mixed line endings, bail */ if (next > start && next[-1] == '\r') { @@ -131,6 +137,10 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) return GIT_PASSTHROUGH; } + GITERR_CHECK_ALLOC_ADD(tgt->size, copylen); + GITERR_CHECK_ALLOC_ADD(tgt->size + copylen, 3); + needsize = tgt->size + copylen + 3; + if (tgt->asize < needsize && git_buf_grow(tgt, needsize) < 0) return -1; diff --git a/src/buffer.c b/src/buffer.c index 8013457c5..ee8bba4ec 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -63,6 +63,14 @@ int git_buf_try_grow( /* round allocation up to multiple of 8 */ new_size = (new_size + 7) & ~7; + if (new_size < buf->size) { + if (mark_oom) + buf->ptr = git_buf__oom; + + giterr_set_oom(); + return -1; + } + new_ptr = git__realloc(new_ptr, new_size); if (!new_ptr) { @@ -131,6 +139,7 @@ int git_buf_set(git_buf *buf, const void *data, size_t len) git_buf_clear(buf); } else { if (data != buf->ptr) { + GITERR_CHECK_ALLOC_ADD(len, 1); ENSURE_SIZE(buf, len + 1); memmove(buf->ptr, data, len); } @@ -160,6 +169,7 @@ int git_buf_sets(git_buf *buf, const char *string) int git_buf_putc(git_buf *buf, char c) { + GITERR_CHECK_ALLOC_ADD(buf->size, 2); ENSURE_SIZE(buf, buf->size + 2); buf->ptr[buf->size++] = c; buf->ptr[buf->size] = '\0'; @@ -168,6 +178,8 @@ int git_buf_putc(git_buf *buf, char c) int git_buf_putcn(git_buf *buf, char c, size_t len) { + GITERR_CHECK_ALLOC_ADD(buf->size, len); + GITERR_CHECK_ALLOC_ADD(buf->size + len, 1); ENSURE_SIZE(buf, buf->size + len + 1); memset(buf->ptr + buf->size, c, len); buf->size += len; @@ -179,6 +191,8 @@ int git_buf_put(git_buf *buf, const char *data, size_t len) { if (len) { assert(data); + GITERR_CHECK_ALLOC_ADD(buf->size, len); + GITERR_CHECK_ALLOC_ADD(buf->size + len, 1); ENSURE_SIZE(buf, buf->size + len + 1); memmove(buf->ptr + buf->size, data, len); buf->size += len; @@ -201,8 +215,12 @@ int git_buf_encode_base64(git_buf *buf, const char *data, size_t len) size_t extra = len % 3; uint8_t *write, a, b, c; const uint8_t *read = (const uint8_t *)data; + size_t blocks = (len / 3) + !!extra; - ENSURE_SIZE(buf, buf->size + 4 * ((len / 3) + !!extra) + 1); + GITERR_CHECK_ALLOC_MULTIPLY(blocks, 4); + GITERR_CHECK_ALLOC_ADD(buf->size, 4 * blocks); + GITERR_CHECK_ALLOC_ADD(buf->size + 4 * blocks, 1); + ENSURE_SIZE(buf, buf->size + 4 * blocks + 1); write = (uint8_t *)&buf->ptr[buf->size]; /* convert each run of 3 bytes into 4 output bytes */ @@ -256,6 +274,8 @@ int git_buf_decode_base64(git_buf *buf, const char *base64, size_t len) size_t orig_size = buf->size; assert(len % 4 == 0); + GITERR_CHECK_ALLOC_ADD(buf->size, len / 4 * 3); + GITERR_CHECK_ALLOC_ADD(buf->size + (len / 4 * 3), 1); ENSURE_SIZE(buf, buf->size + (len / 4 * 3) + 1); for (i = 0; i < len; i += 4) { @@ -284,7 +304,12 @@ static const char b85str[] = int git_buf_encode_base85(git_buf *buf, const char *data, size_t len) { - ENSURE_SIZE(buf, buf->size + (5 * ((len / 4) + !!(len % 4))) + 1); + size_t blocks = (len / 4) + !!(len % 4); + + GITERR_CHECK_ALLOC_MULTIPLY(blocks, 5); + GITERR_CHECK_ALLOC_ADD(buf->size, 5 * blocks); + GITERR_CHECK_ALLOC_ADD(buf->size + 5 * blocks, 1); + ENSURE_SIZE(buf, buf->size + blocks * 5 + 1); while (len) { uint32_t acc = 0; @@ -317,8 +342,14 @@ int git_buf_encode_base85(git_buf *buf, const char *data, size_t len) int git_buf_vprintf(git_buf *buf, const char *format, va_list ap) { + size_t expected_size = strlen(format); int len; - const size_t expected_size = buf->size + (strlen(format) * 2); + + GITERR_CHECK_ALLOC_MULTIPLY(expected_size, 2); + expected_size *= 2; + + GITERR_CHECK_ALLOC_ADD(expected_size, buf->size); + expected_size += buf->size; ENSURE_SIZE(buf, expected_size); @@ -345,6 +376,8 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap) break; } + GITERR_CHECK_ALLOC_ADD(buf->size, len); + GITERR_CHECK_ALLOC_ADD(buf->size + len, 1); ENSURE_SIZE(buf, buf->size + len + 1); } @@ -481,6 +514,9 @@ int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) /* expand buffer if needed */ if (total_size == 0) return 0; + + GITERR_CHECK_ALLOC_ADD(buf->size, total_size); + GITERR_CHECK_ALLOC_ADD(buf->size + total_size, 1); if (git_buf_grow(buf, buf->size + total_size + 1) < 0) return -1; @@ -559,6 +595,9 @@ int git_buf_join( if (str_a >= buf->ptr && str_a < buf->ptr + buf->size) offset_a = str_a - buf->ptr; + GITERR_CHECK_ALLOC_ADD(strlen_a, strlen_b); + GITERR_CHECK_ALLOC_ADD(strlen_a + strlen_b, need_sep); + GITERR_CHECK_ALLOC_ADD(strlen_a + strlen_b + need_sep, 1); if (git_buf_grow(buf, strlen_a + strlen_b + need_sep + 1) < 0) return -1; assert(buf->ptr); @@ -607,6 +646,11 @@ int git_buf_join3( sep_b = (str_b[len_b - 1] != separator); } + GITERR_CHECK_ALLOC_ADD(len_a, sep_a); + GITERR_CHECK_ALLOC_ADD(len_a + sep_a, len_b); + GITERR_CHECK_ALLOC_ADD(len_a + sep_a + len_b, sep_b); + GITERR_CHECK_ALLOC_ADD(len_a + sep_a + len_b + sep_b, len_c); + GITERR_CHECK_ALLOC_ADD(len_a + sep_a + len_b + sep_b + len_c, 1); if (git_buf_grow(buf, len_a + sep_a + len_b + sep_b + len_c + 1) < 0) return -1; @@ -660,6 +704,8 @@ int git_buf_splice( const char *data, size_t nb_to_insert) { + size_t new_size; + assert(buf && where <= git_buf_len(buf) && where + nb_to_remove <= git_buf_len(buf)); @@ -667,7 +713,13 @@ int git_buf_splice( /* Ported from git.git * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176 */ - ENSURE_SIZE(buf, buf->size + nb_to_insert - nb_to_insert + 1); + new_size = buf->size - nb_to_remove; + + GITERR_CHECK_ALLOC_ADD(new_size, nb_to_insert); + new_size += nb_to_insert; + + GITERR_CHECK_ALLOC_ADD(new_size, 1); + ENSURE_SIZE(buf, new_size + 1); memmove(buf->ptr + where + nb_to_insert, buf->ptr + where + nb_to_remove, @@ -675,7 +727,7 @@ int git_buf_splice( memcpy(buf->ptr + where, data, nb_to_insert); - buf->size = buf->size + nb_to_insert - nb_to_remove; + buf->size = new_size; buf->ptr[buf->size] = '\0'; return 0; } diff --git a/src/common.h b/src/common.h index 4b4a99775..b53798eaf 100644 --- a/src/common.h +++ b/src/common.h @@ -174,6 +174,28 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v GITERR_CHECK_VERSION(&(VERSION), _tmpl.version, #TYPE); \ memcpy((PTR), &_tmpl, sizeof(_tmpl)); } while (0) +/** Check for integer overflow from addition or multiplication */ +#define GIT_ALLOC_OVERFLOW_ADD(one, two) \ + ((one) + (two) < (one)) + +/** Check for integer overflow from multiplication */ +#define GIT_ALLOC_OVERFLOW_MULTIPLY(one, two) \ + (one && ((one) * (two)) / (one) != (two)) + +/** Check for additive overflow, failing if it would occur. */ +#define GITERR_CHECK_ALLOC_ADD(one, two) \ + if (GIT_ALLOC_OVERFLOW_ADD(one, two)) { \ + giterr_set_oom(); \ + return -1; \ + } + +/** Check for multiplicative overflow, failing if it would occur. */ +#define GITERR_CHECK_ALLOC_MULTIPLY(nelem, elsize) \ + if (GIT_ALLOC_OVERFLOW_MULTIPLY(nelem, elsize)) { \ + giterr_set_oom(); \ + return -1; \ + } + /* NOTE: other giterr functions are in the public errors.h header file */ #include "util.h" diff --git a/src/config_file.c b/src/config_file.c index 4f041e7e3..36f78563b 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -903,9 +903,11 @@ static char *reader_readline(struct reader *reader, bool skip_whitespace) line_len = line_end - line_src; - line = git__malloc(line_len + 1); - if (line == NULL) + if (GIT_ALLOC_OVERFLOW_ADD(line_len, 1) || + (line = git__malloc(line_len + 1)) == NULL) { + giterr_set_oom(); return NULL; + } memcpy(line, line_src, line_len); @@ -958,6 +960,8 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con int c, rpos; char *first_quote, *last_quote; git_buf buf = GIT_BUF_INIT; + size_t quoted_len, base_name_len = strlen(base_name); + /* * base_name is what came before the space. We should be at the * first quotation mark, except for now, line isn't being kept in @@ -966,13 +970,17 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con first_quote = strchr(line, '"'); last_quote = strrchr(line, '"'); + quoted_len = last_quote - first_quote; - if (last_quote - first_quote == 0) { + if (quoted_len == 0) { set_parse_error(reader, 0, "Missing closing quotation mark in section header"); return -1; } - git_buf_grow(&buf, strlen(base_name) + last_quote - first_quote + 2); + GITERR_CHECK_ALLOC_ADD(base_name_len, quoted_len); + GITERR_CHECK_ALLOC_ADD(base_name_len + quoted_len, 2); + + git_buf_grow(&buf, base_name_len + quoted_len + 2); git_buf_printf(&buf, "%s.", base_name); rpos = 0; @@ -1029,6 +1037,7 @@ static int parse_section_header(struct reader *reader, char **section_out) int name_length, c, pos; int result; char *line; + size_t line_len; line = reader_readline(reader, true); if (line == NULL) @@ -1042,7 +1051,10 @@ static int parse_section_header(struct reader *reader, char **section_out) return -1; } - name = (char *)git__malloc((size_t)(name_end - line) + 1); + line_len = (size_t)(name_end - line); + + GITERR_CHECK_ALLOC_ADD(line_len, 1); + name = git__malloc(line_len); GITERR_CHECK_ALLOC(name); name_length = 0; @@ -1603,11 +1615,16 @@ static char *escape_value(const char *ptr) /* '\"' -> '"' etc */ static char *fixup_line(const char *ptr, int quote_count) { - char *str = git__malloc(strlen(ptr) + 1); - char *out = str, *esc; + char *str, *out, *esc; + size_t ptr_len = strlen(ptr); - if (str == NULL) + if (GIT_ALLOC_OVERFLOW_ADD(ptr_len, 1) || + (str = git__malloc(ptr_len + 1)) == NULL) { + giterr_set_oom(); return NULL; + } + + out = str; while (*ptr != '\0') { if (*ptr == '"') { diff --git a/src/delta-apply.c b/src/delta-apply.c index a39c7af5c..e46c9631c 100644 --- a/src/delta-apply.c +++ b/src/delta-apply.c @@ -74,6 +74,7 @@ int git__delta_apply( return -1; } + GITERR_CHECK_ALLOC_ADD(res_sz, 1); res_dp = git__malloc(res_sz + 1); GITERR_CHECK_ALLOC(res_dp); diff --git a/src/delta.c b/src/delta.c index 8375a2c4d..f704fdfb1 100644 --- a/src/delta.c +++ b/src/delta.c @@ -119,6 +119,36 @@ struct git_delta_index { struct index_entry *hash[GIT_FLEX_ARRAY]; }; +static int lookup_index_alloc( + void **out, unsigned long *out_len, size_t entries, size_t hash_count) +{ + size_t entries_len, hash_len, + index_len = sizeof(struct git_delta_index); + + GITERR_CHECK_ALLOC_MULTIPLY(entries, sizeof(struct index_entry)); + entries_len = entries * sizeof(struct index_entry); + + GITERR_CHECK_ALLOC_ADD(index_len, entries_len); + index_len += entries_len; + + GITERR_CHECK_ALLOC_MULTIPLY(hash_count, sizeof(struct index_entry *)); + hash_len = hash_count * sizeof(struct index_entry *); + + GITERR_CHECK_ALLOC_ADD(index_len, hash_len); + index_len += hash_len; + + if (!git__is_ulong(index_len)) { + giterr_set_oom(); + return -1; + } + + *out = git__malloc(index_len); + GITERR_CHECK_ALLOC(*out); + + *out_len = index_len; + return 0; +} + struct git_delta_index * git_delta_create_index(const void *buf, unsigned long bufsize) { @@ -148,13 +178,9 @@ git_delta_create_index(const void *buf, unsigned long bufsize) hsize = 1 << i; hmask = hsize - 1; - /* allocate lookup index */ - memsize = sizeof(*index) + - sizeof(*hash) * hsize + - sizeof(*entry) * entries; - mem = git__malloc(memsize); - if (!mem) + if (lookup_index_alloc(&mem, &memsize, entries, hsize) < 0) return NULL; + index = mem; mem = index->hash; hash = mem; diff --git a/src/diff.c b/src/diff.c index e23d3891f..75e9ae9a3 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1558,8 +1558,10 @@ int git_diff_format_email( goto on_error; } + GITERR_CHECK_ALLOC_ADD(offset, 1); summary = git__calloc(offset + 1, sizeof(char)); GITERR_CHECK_ALLOC(summary); + strncpy(summary, opts->summary, offset); } diff --git a/src/diff_driver.c b/src/diff_driver.c index c3c5f365b..67f1c591d 100644 --- a/src/diff_driver.c +++ b/src/diff_driver.c @@ -158,6 +158,29 @@ static git_diff_driver_registry *git_repository_driver_registry( return repo->diff_drivers; } +static int diff_driver_alloc( + git_diff_driver **out, size_t *namelen_out, const char *name) +{ + git_diff_driver *driver; + size_t driverlen = sizeof(git_diff_driver), + namelen = strlen(name); + + GITERR_CHECK_ALLOC_ADD(driverlen, namelen); + GITERR_CHECK_ALLOC_ADD(driverlen + namelen, 1); + + driver = git__calloc(1, driverlen + namelen + 1); + GITERR_CHECK_ALLOC(driver); + + memcpy(driver->name, name, namelen); + + *out = driver; + + if (namelen_out) + *namelen_out = namelen; + + return 0; +} + static int git_diff_driver_builtin( git_diff_driver **out, git_diff_driver_registry *reg, @@ -166,7 +189,7 @@ static int git_diff_driver_builtin( int error = 0; git_diff_driver_definition *ddef = NULL; git_diff_driver *drv = NULL; - size_t namelen, idx; + size_t idx; for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) { if (!strcasecmp(driver_name, builtin_defs[idx].name)) { @@ -177,13 +200,10 @@ static int git_diff_driver_builtin( if (!ddef) goto done; - namelen = strlen(ddef->name); - - drv = git__calloc(1, sizeof(git_diff_driver) + namelen + 1); - GITERR_CHECK_ALLOC(drv); + if ((error = diff_driver_alloc(&drv, NULL, ddef->name)) < 0) + goto done; drv->type = DIFF_DRIVER_PATTERNLIST; - memcpy(drv->name, ddef->name, namelen); if (ddef->fns && (error = diff_driver_add_patterns( @@ -217,9 +237,9 @@ static int git_diff_driver_load( int error = 0; git_diff_driver_registry *reg; git_diff_driver *drv = NULL; - size_t namelen = strlen(driver_name); + size_t namelen; khiter_t pos; - git_config *cfg; + git_config *cfg = NULL; git_buf name = GIT_BUF_INIT; const git_config_entry *ce; bool found_driver = false; @@ -233,10 +253,10 @@ static int git_diff_driver_load( return 0; } - drv = git__calloc(1, sizeof(git_diff_driver) + namelen + 1); - GITERR_CHECK_ALLOC(drv); + if ((error = diff_driver_alloc(&drv, &namelen, driver_name)) < 0) + goto done; + drv->type = DIFF_DRIVER_AUTO; - memcpy(drv->name, driver_name, namelen); /* if you can't read config for repo, just use default driver */ if (git_repository_config_snapshot(&cfg, repo) < 0) { diff --git a/src/diff_patch.c b/src/diff_patch.c index a15107753..f5eecae66 100644 --- a/src/diff_patch.c +++ b/src/diff_patch.c @@ -388,8 +388,18 @@ static int diff_patch_with_delta_alloc( diff_patch_with_delta *pd; size_t old_len = *old_path ? strlen(*old_path) : 0; size_t new_len = *new_path ? strlen(*new_path) : 0; + size_t alloc_len = sizeof(*pd); - *out = pd = git__calloc(1, sizeof(*pd) + old_len + new_len + 2); + GITERR_CHECK_ALLOC_ADD(alloc_len, old_len); + alloc_len += old_len; + + GITERR_CHECK_ALLOC_ADD(alloc_len, new_len); + alloc_len += new_len; + + GITERR_CHECK_ALLOC_ADD(alloc_len, 2); + alloc_len += 2; + + *out = pd = git__calloc(1, alloc_len); GITERR_CHECK_ALLOC(pd); pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED; diff --git a/src/diff_tform.c b/src/diff_tform.c index 9133a9b14..cad1356c3 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -831,6 +831,7 @@ int git_diff_find_similar( if ((opts.flags & GIT_DIFF_FIND_ALL) == 0) goto cleanup; + GITERR_CHECK_ALLOC_MULTIPLY(num_deltas, 2); sigcache = git__calloc(num_deltas * 2, sizeof(void *)); GITERR_CHECK_ALLOC(sigcache); diff --git a/src/filebuf.c b/src/filebuf.c index 25f6e52ef..1a9157558 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -271,6 +271,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode GITERR_CHECK_ALLOC(file->path_original); /* create the locking path by appending ".lock" to the original */ + GITERR_CHECK_ALLOC_ADD(path_len, GIT_FILELOCK_EXTLENGTH); file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH); GITERR_CHECK_ALLOC(file->path_lock); @@ -437,8 +438,8 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...) } while ((size_t)len + 1 <= space_left); - tmp_buffer = git__malloc(len + 1); - if (!tmp_buffer) { + if (GIT_ALLOC_OVERFLOW_ADD(len, 1) || + !(tmp_buffer = git__malloc(len + 1))) { file->last_error = BUFERR_MEM; return -1; } diff --git a/src/fileops.c b/src/fileops.c index eddd5a804..eb24013e8 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -127,6 +127,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) git_buf_clear(buf); + GITERR_CHECK_ALLOC_ADD(len, 1); if (git_buf_grow(buf, len + 1) < 0) return -1; @@ -708,7 +709,10 @@ static int cp_link(const char *from, const char *to, size_t link_size) { int error = 0; ssize_t read_len; - char *link_data = git__malloc(link_size + 1); + char *link_data; + + GITERR_CHECK_ALLOC_ADD(link_size, 1); + link_data = git__malloc(link_size + 1); GITERR_CHECK_ALLOC(link_data); read_len = p_readlink(from, link_data, link_size); diff --git a/src/filter.c b/src/filter.c index 22eaf51a2..d5c669f01 100644 --- a/src/filter.c +++ b/src/filter.c @@ -228,7 +228,7 @@ int git_filter_register( const char *name, git_filter *filter, int priority) { git_filter_def *fdef; - size_t nattr = 0, nmatch = 0; + size_t nattr = 0, nmatch = 0, alloc_len; git_buf attrs = GIT_BUF_INIT; assert(name && filter); @@ -245,8 +245,16 @@ int git_filter_register( if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0) return -1; - fdef = git__calloc( - sizeof(git_filter_def) + 2 * nattr * sizeof(char *), 1); + GITERR_CHECK_ALLOC_MULTIPLY(nattr, 2); + alloc_len = nattr * 2; + + GITERR_CHECK_ALLOC_MULTIPLY(alloc_len, sizeof(char *)); + alloc_len *= sizeof(char *); + + GITERR_CHECK_ALLOC_ADD(alloc_len, sizeof(git_filter_def)); + alloc_len += sizeof(git_filter_def); + + fdef = git__calloc(1, alloc_len); GITERR_CHECK_ALLOC(fdef); fdef->filter_name = git__strdup(name); @@ -379,6 +387,9 @@ static int filter_list_new( git_filter_list *fl = NULL; size_t pathlen = src->path ? strlen(src->path) : 0; + GITERR_CHECK_ALLOC_ADD(sizeof(git_filter_list), pathlen); + GITERR_CHECK_ALLOC_ADD(sizeof(git_filter_list) + pathlen, 1); + fl = git__calloc(1, sizeof(git_filter_list) + pathlen + 1); GITERR_CHECK_ALLOC(fl); diff --git a/src/index.c b/src/index.c index cbace3606..70090d12c 100644 --- a/src/index.c +++ b/src/index.c @@ -779,7 +779,9 @@ static int index_entry_create( return -1; } - entry = git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1); + GITERR_CHECK_ALLOC_ADD(sizeof(struct entry_internal), pathlen); + GITERR_CHECK_ALLOC_ADD(sizeof(struct entry_internal) + pathlen, 1); + entry = git__calloc(1, sizeof(struct entry_internal) + pathlen + 1); GITERR_CHECK_ALLOC(entry); entry->pathlen = pathlen; @@ -826,9 +828,17 @@ static int index_entry_init( static git_index_reuc_entry *reuc_entry_alloc(const char *path) { - size_t pathlen = strlen(path); - struct reuc_entry_internal *entry = - git__calloc(sizeof(struct reuc_entry_internal) + pathlen + 1, 1); + size_t pathlen = strlen(path), + structlen = sizeof(struct reuc_entry_internal); + struct reuc_entry_internal *entry; + + if (GIT_ALLOC_OVERFLOW_ADD(structlen, pathlen) || + GIT_ALLOC_OVERFLOW_ADD(structlen + pathlen, 1)) { + giterr_set_oom(); + return NULL; + } + + entry = git__calloc(1, structlen + pathlen + 1); if (!entry) return NULL; diff --git a/src/iterator.c b/src/iterator.c index 196adddbf..e90cf30ff 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -336,7 +336,7 @@ static int tree_iterator__push_frame(tree_iterator *ti) { int error = 0; tree_iterator_frame *head = ti->head, *tf = NULL; - size_t i, n_entries = 0; + size_t i, n_entries = 0, alloclen; if (head->current >= head->n_entries || !head->entries[head->current]->tree) return GIT_ITEROVER; @@ -344,8 +344,13 @@ static int tree_iterator__push_frame(tree_iterator *ti) for (i = head->current; i < head->next; ++i) n_entries += git_tree_entrycount(head->entries[i]->tree); - tf = git__calloc(sizeof(tree_iterator_frame) + - n_entries * sizeof(tree_iterator_entry *), 1); + GITERR_CHECK_ALLOC_MULTIPLY(sizeof(tree_iterator_entry *), n_entries); + alloclen = sizeof(tree_iterator_entry *) * n_entries; + + GITERR_CHECK_ALLOC_ADD(alloclen, sizeof(tree_iterator_frame)); + alloclen += sizeof(tree_iterator_frame); + + tf = git__calloc(1, alloclen); GITERR_CHECK_ALLOC(tf); tf->n_entries = n_entries; diff --git a/src/merge.c b/src/merge.c index 7c38b5692..25d7bd7aa 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1169,6 +1169,7 @@ int git_merge_diff_list__find_renames( goto done; if (diff_list->conflicts.length <= opts->target_limit) { + GITERR_CHECK_ALLOC_MULTIPLY(diff_list->conflicts.length, 3); cache_size = diff_list->conflicts.length * 3; cache = git__calloc(cache_size, sizeof(void *)); GITERR_CHECK_ALLOC(cache); @@ -2228,6 +2229,7 @@ static int merge_ancestor_head( assert(repo && our_head && their_heads); + GITERR_CHECK_ALLOC_ADD(their_heads_len, 1); oids = git__calloc(their_heads_len + 1, sizeof(git_oid)); GITERR_CHECK_ALLOC(oids); diff --git a/src/notes.c b/src/notes.c index f44c0bd95..1850e81c7 100644 --- a/src/notes.c +++ b/src/notes.c @@ -314,7 +314,7 @@ static int note_new( { git_note *note = NULL; - note = (git_note *)git__malloc(sizeof(git_note)); + note = git__malloc(sizeof(git_note)); GITERR_CHECK_ALLOC(note); git_oid_cpy(¬e->id, note_oid); @@ -233,6 +233,7 @@ int git_odb__hashlink(git_oid *out, const char *path) char *link_data; ssize_t read_len; + GITERR_CHECK_ALLOC_ADD(size, 1); link_data = git__malloc((size_t)(size + 1)); GITERR_CHECK_ALLOC(link_data); diff --git a/src/odb_loose.c b/src/odb_loose.c index ea9bdc4a0..e43b261fa 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -64,6 +64,8 @@ static int object_file_name( git_buf *name, const loose_backend *be, const git_oid *id) { /* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */ + GITERR_CHECK_ALLOC_ADD(be->objects_dirlen, GIT_OID_HEXSZ); + GITERR_CHECK_ALLOC_ADD(be->objects_dirlen + GIT_OID_HEXSZ, 3); if (git_buf_grow(name, be->objects_dirlen + GIT_OID_HEXSZ + 3) < 0) return -1; @@ -268,7 +270,8 @@ static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr) * initial sequence of inflated data from the tail of the * head buffer, if any. */ - if ((buf = git__malloc(hdr->size + 1)) == NULL) { + if (GIT_ALLOC_OVERFLOW_ADD(hdr->size, 1) || + (buf = git__malloc(hdr->size + 1)) == NULL) { inflateEnd(s); return NULL; } @@ -321,6 +324,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj) /* * allocate a buffer and inflate the data into it */ + GITERR_CHECK_ALLOC_ADD(hdr.size, 1); buf = git__malloc(hdr.size + 1); GITERR_CHECK_ALLOC(buf); @@ -520,6 +524,8 @@ static int locate_object_short_oid( int error; /* prealloc memory for OBJ_DIR/xx/xx..38x..xx */ + GITERR_CHECK_ALLOC_ADD(dir_len, GIT_OID_HEXSZ); + GITERR_CHECK_ALLOC_ADD(dir_len + GIT_OID_HEXSZ, 3); if (git_buf_grow(object_location, dir_len + 3 + GIT_OID_HEXSZ) < 0) return -1; @@ -563,6 +569,8 @@ static int locate_object_short_oid( return error; /* Update the location according to the oid obtained */ + GITERR_CHECK_ALLOC_ADD(dir_len, GIT_OID_HEXSZ); + GITERR_CHECK_ALLOC_ADD(dir_len + GIT_OID_HEXSZ, 2); git_buf_truncate(object_location, dir_len); if (git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2) < 0) @@ -928,6 +936,8 @@ int git_odb_backend_loose( objects_dirlen = strlen(objects_dir); + GITERR_CHECK_ALLOC_ADD(sizeof(loose_backend), objects_dirlen); + GITERR_CHECK_ALLOC_ADD(sizeof(loose_backend) + objects_dirlen, 2); backend = git__calloc(1, sizeof(loose_backend) + objects_dirlen + 2); GITERR_CHECK_ALLOC(backend); diff --git a/src/odb_mempack.c b/src/odb_mempack.c index d9b3a1824..a71d8db4b 100644 --- a/src/odb_mempack.c +++ b/src/odb_mempack.c @@ -47,6 +47,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void if (rval == 0) return 0; + GITERR_CHECK_ALLOC_ADD(sizeof(struct memobject), len); obj = git__malloc(sizeof(struct memobject) + len); GITERR_CHECK_ALLOC(obj); @@ -261,6 +261,7 @@ struct git_oid_shorten { static int resize_trie(git_oid_shorten *self, size_t new_size) { + GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(trie_node)); self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node)); GITERR_CHECK_ALLOC(self->nodes); diff --git a/src/pack-objects.c b/src/pack-objects.c index 0040a826b..aea4770af 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -201,7 +201,11 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, return 0; if (pb->nr_objects >= pb->nr_alloc) { + GITERR_CHECK_ALLOC_ADD(pb->nr_alloc, 1024); + GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc + 1024, 3 / 2); pb->nr_alloc = (pb->nr_alloc + 1024) * 3 / 2; + + GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc, sizeof(*po)); pb->object_list = git__realloc(pb->object_list, pb->nr_alloc * sizeof(*po)); GITERR_CHECK_ALLOC(pb->object_list); @@ -499,8 +503,13 @@ static int cb_tag_foreach(const char *name, git_oid *oid, void *data) static git_pobject **compute_write_order(git_packbuilder *pb) { unsigned int i, wo_end, last_untagged; + git_pobject **wo; - git_pobject **wo = git__malloc(sizeof(*wo) * pb->nr_objects); + if (GIT_ALLOC_OVERFLOW_MULTIPLY(pb->nr_objects, sizeof(*wo)) || + (wo = git__malloc(pb->nr_objects * sizeof(*wo))) == NULL) { + giterr_set_oom(); + return NULL; + } for (i = 0; i < pb->nr_objects; i++) { git_pobject *po = pb->object_list + i; @@ -770,10 +779,13 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg, *mem_usage += sz; } if (!src->data) { - if (git_odb_read(&obj, pb->odb, &src_object->id) < 0) + size_t obj_sz; + + if (git_odb_read(&obj, pb->odb, &src_object->id) < 0 || + !git__is_ulong(obj_sz = git_odb_object_size(obj))) return -1; - sz = (unsigned long)git_odb_object_size(obj); + sz = (unsigned long)obj_sz; src->data = git__malloc(sz); GITERR_CHECK_ALLOC(src->data); memcpy(src->data, git_odb_object_data(obj), sz); @@ -817,7 +829,9 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg, trg_object->delta_data = NULL; } if (delta_cacheable(pb, src_size, trg_size, delta_size)) { + GITERR_CHECK_ALLOC_ADD(pb->delta_cache_size, delta_size); pb->delta_cache_size += delta_size; + git_packbuilder__cache_unlock(pb); trg_object->delta_data = git__realloc(delta_buf, delta_size); @@ -1088,6 +1102,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, return 0; } + GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_threads, sizeof(*p)); p = git__malloc(pb->nr_threads * sizeof(*p)); GITERR_CHECK_ALLOC(p); @@ -1239,6 +1254,7 @@ static int prepare_pack(git_packbuilder *pb) if (pb->progress_cb) pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload); + GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_objects, sizeof(*delta_list)); delta_list = git__malloc(pb->nr_objects * sizeof(*delta_list)); GITERR_CHECK_ALLOC(delta_list); diff --git a/src/pack.c b/src/pack.c index 47ce854c4..d475b28ee 100644 --- a/src/pack.c +++ b/src/pack.c @@ -683,8 +683,11 @@ int git_packfile_unpack( */ if (cached && stack_size == 1) { void *data = obj->data; + + GITERR_CHECK_ALLOC_ADD(obj->len, 1); obj->data = git__malloc(obj->len + 1); GITERR_CHECK_ALLOC(obj->data); + memcpy(obj->data, data, obj->len + 1); git_atomic_dec(&cached->refcount); goto cleanup; @@ -841,6 +844,7 @@ int packfile_unpack_compressed( z_stream stream; unsigned char *buffer, *in; + GITERR_CHECK_ALLOC_ADD(size, 1); buffer = git__calloc(1, size + 1); GITERR_CHECK_ALLOC(buffer); @@ -1092,6 +1096,9 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) if (path_len < strlen(".idx")) return git_odb__error_notfound("invalid packfile path", NULL); + GITERR_CHECK_ALLOC_ADD(sizeof(*p), path_len); + GITERR_CHECK_ALLOC_ADD(sizeof(*p) + path_len, 2); + p = git__calloc(1, sizeof(*p) + path_len + 2); GITERR_CHECK_ALLOC(p); diff --git a/src/path.c b/src/path.c index 58d71921b..3dbd7187b 100644 --- a/src/path.c +++ b/src/path.c @@ -622,7 +622,9 @@ static bool _check_dir_contents( size_t sub_size = strlen(sub); /* leave base valid even if we could not make space for subdir */ - if (git_buf_try_grow(dir, dir_size + sub_size + 2, false, false) < 0) + if (GIT_ALLOC_OVERFLOW_ADD(dir_size, sub_size) || + GIT_ALLOC_OVERFLOW_ADD(dir_size + sub_size, 2) || + git_buf_try_grow(dir, dir_size + sub_size + 2, false, false) < 0) return false; /* save excursion */ @@ -822,6 +824,9 @@ int git_path_make_relative(git_buf *path, const char *parent) for (; (q = strchr(q, '/')) && *(q + 1); q++) depth++; + GITERR_CHECK_ALLOC_MULTIPLY(depth, 3); + GITERR_CHECK_ALLOC_ADD(depth * 3, plen); + GITERR_CHECK_ALLOC_ADD(depth * 3, 1); newlen = (depth * 3) + plen; /* save the offset as we might realllocate the pointer */ @@ -881,6 +886,7 @@ int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen) git_buf_clear(&ic->buf); while (1) { + GITERR_CHECK_ALLOC_ADD(wantlen, 1); if (git_buf_grow(&ic->buf, wantlen + 1) < 0) return -1; @@ -1057,6 +1063,45 @@ int git_path_direach( return error; } +static int entry_path_alloc( + char **out, + const char *path, + size_t path_len, + const char *de_path, + size_t de_len, + size_t alloc_extra) +{ + int need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0; + size_t alloc_size = path_len; + char *entry_path; + + GITERR_CHECK_ALLOC_ADD(alloc_size, de_len); + alloc_size += de_len; + + GITERR_CHECK_ALLOC_ADD(alloc_size, need_slash); + alloc_size += need_slash; + + GITERR_CHECK_ALLOC_ADD(alloc_size, 1); + alloc_size++; + + GITERR_CHECK_ALLOC_ADD(alloc_size, alloc_extra); + alloc_size += alloc_extra; + + entry_path = git__calloc(1, alloc_size); + GITERR_CHECK_ALLOC(entry_path); + + if (path_len) + memcpy(entry_path, path, path_len); + + if (need_slash) + entry_path[path_len] = '/'; + + memcpy(&entry_path[path_len + need_slash], de_path, de_len); + + *out = entry_path; + return 0; +} + int git_path_dirload( const char *path, size_t prefix_len, @@ -1064,7 +1109,7 @@ int git_path_dirload( unsigned int flags, git_vector *contents) { - int error, need_slash; + int error; DIR *dir; size_t path_len; path_dirent_data de_data; @@ -1096,11 +1141,10 @@ int git_path_dirload( path += prefix_len; path_len -= prefix_len; - need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0; while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) { char *entry_path, *de_path = de->d_name; - size_t alloc_size, de_len = strlen(de_path); + size_t de_len = strlen(de_path); if (git_path_is_dot_or_dotdot(de_path)) continue; @@ -1110,17 +1154,9 @@ int git_path_dirload( break; #endif - alloc_size = path_len + need_slash + de_len + 1 + alloc_extra; - if ((entry_path = git__calloc(alloc_size, 1)) == NULL) { - error = -1; + if ((error = entry_path_alloc(&entry_path, + path, path_len, de_path, de_len, alloc_extra)) < 0) break; - } - - if (path_len) - memcpy(entry_path, path, path_len); - if (need_slash) - entry_path[path_len] = '/'; - memcpy(&entry_path[path_len + need_slash], de_path, de_len); if ((error = git_vector_insert(contents, entry_path)) < 0) { git__free(entry_path); diff --git a/src/pool.c b/src/pool.c index 7350c04c1..1599fc7a2 100644 --- a/src/pool.c +++ b/src/pool.c @@ -116,9 +116,11 @@ static void *pool_alloc_page(git_pool *pool, uint32_t size) pool->has_large_page_alloc = 1; } - page = git__calloc(1, alloc_size + sizeof(git_pool_page)); - if (!page) + if (GIT_ALLOC_OVERFLOW_ADD(alloc_size, sizeof(git_pool_page)) || + !(page = git__calloc(1, alloc_size + sizeof(git_pool_page)))) { + giterr_set_oom(); return NULL; + } page->size = alloc_size; page->avail = alloc_size - size; diff --git a/src/refs.c b/src/refs.c index 43c7333f2..33e931db5 100644 --- a/src/refs.c +++ b/src/refs.c @@ -37,10 +37,14 @@ enum { static git_reference *alloc_ref(const char *name) { git_reference *ref; - size_t namelen = strlen(name); + size_t namelen = strlen(name), reflen = sizeof(git_reference); - if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) + if (GIT_ALLOC_OVERFLOW_ADD(reflen, namelen) || + GIT_ALLOC_OVERFLOW_ADD(reflen + namelen, 1) || + (ref = git__calloc(1, reflen + namelen + 1)) == NULL) { + giterr_set_oom(); return NULL; + } memcpy(ref->name, name, namelen + 1); @@ -94,10 +98,14 @@ git_reference *git_reference__set_name( git_reference *ref, const char *name) { size_t namelen = strlen(name); - git_reference *rewrite = - git__realloc(ref, sizeof(git_reference) + namelen + 1); - if (rewrite != NULL) + size_t reflen = sizeof(git_reference); + git_reference *rewrite = NULL; + + if (!GIT_ALLOC_OVERFLOW_ADD(reflen, namelen) && + !GIT_ALLOC_OVERFLOW_ADD(reflen + namelen, 1) && + (rewrite = git__realloc(ref, reflen + namelen + 1)) != NULL) memcpy(rewrite->name, name, namelen + 1); + return rewrite; } diff --git a/src/remote.c b/src/remote.c index 5ba7735ae..d96274f1d 100644 --- a/src/remote.c +++ b/src/remote.c @@ -383,10 +383,9 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name) if ((error = git_repository_config_snapshot(&config, repo)) < 0) return error; - remote = git__malloc(sizeof(git_remote)); + remote = git__calloc(1, sizeof(git_remote)); GITERR_CHECK_ALLOC(remote); - memset(remote, 0x0, sizeof(git_remote)); remote->update_fetchhead = 1; remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); diff --git a/src/revwalk.c b/src/revwalk.c index e44385d48..2ba000c6b 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -503,13 +503,9 @@ static int prepare_walk(git_revwalk *walk) int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) { - git_revwalk *walk; - - walk = git__malloc(sizeof(git_revwalk)); + git_revwalk *walk = git__calloc(1, sizeof(git_revwalk)); GITERR_CHECK_ALLOC(walk); - memset(walk, 0x0, sizeof(git_revwalk)); - walk->commits = git_oidmap_alloc(); GITERR_CHECK_ALLOC(walk->commits); diff --git a/src/sortedcache.c b/src/sortedcache.c index c6b226153..021f79632 100644 --- a/src/sortedcache.c +++ b/src/sortedcache.c @@ -15,7 +15,9 @@ int git_sortedcache_new( pathlen = path ? strlen(path) : 0; - sc = git__calloc(sizeof(git_sortedcache) + pathlen + 1, 1); + GITERR_CHECK_ALLOC_ADD(sizeof(git_sortedcache), pathlen); + GITERR_CHECK_ALLOC_ADD(sizeof(git_sortedcache) + pathlen, 1); + sc = git__calloc(1, sizeof(git_sortedcache) + pathlen + 1); GITERR_CHECK_ALLOC(sc); if (git_pool_init(&sc->pool, 1, 0) < 0 || @@ -117,6 +117,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) text_len = search - buffer; + GITERR_CHECK_ALLOC_ADD(text_len, 1); tag->tag_name = git__malloc(text_len + 1); GITERR_CHECK_ALLOC(tag->tag_name); @@ -141,6 +142,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) text_len = buffer_end - ++buffer; + GITERR_CHECK_ALLOC_ADD(text_len, 1); tag->message = git__malloc(text_len + 1); GITERR_CHECK_ALLOC(tag->message); diff --git a/src/transports/cred.c b/src/transports/cred.c index 1b4d29c0a..8e5447d18 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -311,6 +311,9 @@ int git_cred_username_new(git_cred **cred, const char *username) assert(cred); len = strlen(username); + + GITERR_CHECK_ALLOC_ADD(sizeof(git_cred_username), len); + GITERR_CHECK_ALLOC_ADD(sizeof(git_cred_username) + len, 1); c = git__malloc(sizeof(git_cred_username) + len + 1); GITERR_CHECK_ALLOC(c); diff --git a/src/transports/git.c b/src/transports/git.c index 6f25736b1..5ec98d867 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -154,7 +154,7 @@ static int git_proto_stream_alloc( if (!stream) return -1; - s = git__calloc(sizeof(git_proto_stream), 1); + s = git__calloc(1, sizeof(git_proto_stream)); GITERR_CHECK_ALLOC(s); s->parent.subtransport = &t->parent; @@ -347,7 +347,7 @@ int git_smart_subtransport_git(git_smart_subtransport **out, git_transport *owne if (!out) return -1; - t = git__calloc(sizeof(git_subtransport), 1); + t = git__calloc(1, sizeof(git_subtransport)); GITERR_CHECK_ALLOC(t); t->owner = owner; diff --git a/src/transports/local.c b/src/transports/local.c index c01755e34..89f2651cd 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -420,7 +420,7 @@ static int local_push( const git_error *last; char *ref = spec->refspec.dst; - status = git__calloc(sizeof(push_status), 1); + status = git__calloc(1, sizeof(push_status)); if (!status) goto on_error; diff --git a/src/transports/smart.c b/src/transports/smart.c index ec0ba3784..69b9d22cc 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -380,7 +380,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) if (!param) return -1; - t = git__calloc(sizeof(transport_smart), 1); + t = git__calloc(1, sizeof(transport_smart)); GITERR_CHECK_ALLOC(t); t->parent.version = GIT_TRANSPORT_VERSION; diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index b5f9d6dbe..2f83e0d7b 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -103,6 +103,8 @@ static int comment_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_comment *pkt; + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_comment), len); + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_comment) + len, 1); pkt = git__malloc(sizeof(git_pkt_comment) + len + 1); GITERR_CHECK_ALLOC(pkt); @@ -122,6 +124,9 @@ static int err_pkt(git_pkt **out, const char *line, size_t len) /* Remove "ERR " from the line */ line += 4; len -= 4; + + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_progress), len); + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_progress) + len, 1); pkt = git__malloc(sizeof(git_pkt_err) + len + 1); GITERR_CHECK_ALLOC(pkt); @@ -141,6 +146,8 @@ static int data_pkt(git_pkt **out, const char *line, size_t len) line++; len--; + + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_progress), len); pkt = git__malloc(sizeof(git_pkt_data) + len); GITERR_CHECK_ALLOC(pkt); @@ -159,6 +166,8 @@ static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len) line++; len--; + + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_progress), len); pkt = git__malloc(sizeof(git_pkt_progress) + len); GITERR_CHECK_ALLOC(pkt); @@ -177,6 +186,9 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) line++; len--; + + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_err), len); + GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_err) + len, 1); pkt = git__malloc(sizeof(git_pkt_err) + len + 1); GITERR_CHECK_ALLOC(pkt); @@ -220,6 +232,7 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) if (line[len - 1] == '\n') --len; + GITERR_CHECK_ALLOC_ADD(len, 1); pkt->head.name = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->head.name); @@ -249,9 +262,13 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len) pkt->type = GIT_PKT_OK; line += 3; /* skip "ok " */ - ptr = strchr(line, '\n'); + if (!(ptr = strchr(line, '\n'))) { + giterr_set(GITERR_NET, "Invalid packet line"); + return -1; + } len = ptr - line; + GITERR_CHECK_ALLOC_ADD(len, 1); pkt->ref = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->ref); @@ -273,9 +290,13 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) pkt->type = GIT_PKT_NG; line += 3; /* skip "ng " */ - ptr = strchr(line, ' '); + if (!(ptr = strchr(line, ' '))) { + giterr_set(GITERR_NET, "Invalid packet line"); + return -1; + } len = ptr - line; + GITERR_CHECK_ALLOC_ADD(len, 1); pkt->ref = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->ref); @@ -283,9 +304,13 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) pkt->ref[len] = '\0'; line = ptr + 1; - ptr = strchr(line, '\n'); + if (!(ptr = strchr(line, '\n'))) { + giterr_set(GITERR_NET, "Invalid packet line"); + return -1; + } len = ptr - line; + GITERR_CHECK_ALLOC_ADD(len, 1); pkt->msg = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->msg); diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 5f1b99892..f023db4df 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -685,7 +685,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt) switch (pkt->type) { case GIT_PKT_OK: - status = git__calloc(sizeof(push_status), 1); + status = git__calloc(1, sizeof(push_status)); GITERR_CHECK_ALLOC(status); status->msg = NULL; status->ref = git__strdup(((git_pkt_ok *)pkt)->ref); @@ -696,7 +696,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt) } break; case GIT_PKT_NG: - status = git__calloc(sizeof(push_status), 1); + status = git__calloc(1, sizeof(push_status)); GITERR_CHECK_ALLOC(status); status->ref = git__strdup(((git_pkt_ng *)pkt)->ref); status->msg = git__strdup(((git_pkt_ng *)pkt)->msg); diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 56b7c99f9..278ef22c4 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -1178,7 +1178,7 @@ static int winhttp_stream_alloc(winhttp_subtransport *t, winhttp_stream **stream if (!stream) return -1; - s = git__calloc(sizeof(winhttp_stream), 1); + s = git__calloc(1, sizeof(winhttp_stream)); GITERR_CHECK_ALLOC(s); s->parent.subtransport = &t->parent; @@ -1329,7 +1329,7 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own if (!out) return -1; - t = git__calloc(sizeof(winhttp_subtransport), 1); + t = git__calloc(1, sizeof(winhttp_subtransport)); GITERR_CHECK_ALLOC(t); t->owner = (transport_smart *)owner; diff --git a/src/tree.c b/src/tree.c index 9693f4eca..2c8b89291 100644 --- a/src/tree.c +++ b/src/tree.c @@ -84,11 +84,15 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2) static git_tree_entry *alloc_entry(const char *filename) { git_tree_entry *entry = NULL; - size_t filename_len = strlen(filename); + size_t filename_len = strlen(filename), + tree_len = sizeof(git_tree_entry); - entry = git__malloc(sizeof(git_tree_entry) + filename_len + 1); - if (!entry) + if (GIT_ALLOC_OVERFLOW_ADD(tree_len, filename_len) || + GIT_ALLOC_OVERFLOW_ADD(tree_len + filename_len, 1) || + !(entry = git__malloc(tree_len + filename_len + 1))) { + giterr_set_oom(); return NULL; + } memset(entry, 0x0, sizeof(git_tree_entry)); memcpy(entry->filename, filename, filename_len); @@ -205,12 +209,16 @@ void git_tree_entry_free(git_tree_entry *entry) int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source) { - size_t total_size; + size_t total_size = sizeof(git_tree_entry); git_tree_entry *copy; assert(source); - total_size = sizeof(git_tree_entry) + source->filename_len + 1; + GITERR_CHECK_ALLOC_ADD(total_size, source->filename_len); + total_size += source->filename_len; + + GITERR_CHECK_ALLOC_ADD(total_size, 1); + total_size++; copy = git__malloc(total_size); GITERR_CHECK_ALLOC(copy); diff --git a/src/tsort.c b/src/tsort.c index 4885e435b..b92e52056 100644 --- a/src/tsort.c +++ b/src/tsort.c @@ -184,7 +184,10 @@ static int check_invariant(struct tsort_run *stack, ssize_t stack_curr) static int resize(struct tsort_store *store, size_t new_size) { if (store->alloc < new_size) { - void **tempstore = git__realloc(store->storage, new_size * sizeof(void *)); + void **tempstore; + + GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(void *)); + tempstore = git__realloc(store->storage, new_size * sizeof(void *)); /** * Do not propagate on OOM; this will abort the sort and diff --git a/src/util.h b/src/util.h index 89816a8c9..6c94a5aa0 100644 --- a/src/util.h +++ b/src/util.h @@ -64,7 +64,12 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n) length = p_strnlen(str, n); - ptr = (char*)git__malloc(length + 1); + if (GIT_ALLOC_OVERFLOW_ADD(length, 1)) { + giterr_set_oom(); + return NULL; + } + + ptr = git__malloc(length + 1); if (!ptr) return NULL; @@ -80,7 +85,13 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n) /* NOTE: This doesn't do null or '\0' checking. Watch those boundaries! */ GIT_INLINE(char *) git__substrdup(const char *start, size_t n) { - char *ptr = (char*)git__malloc(n+1); + char *ptr; + + if (GIT_ALLOC_OVERFLOW_ADD(n, 1) || !(ptr = git__malloc(n+1))) { + giterr_set_oom(); + return NULL; + } + memcpy(ptr, start, n); ptr[n] = '\0'; return ptr; diff --git a/src/vector.c b/src/vector.c index c769b696a..b636032b1 100644 --- a/src/vector.c +++ b/src/vector.c @@ -29,12 +29,12 @@ GIT_INLINE(size_t) compute_new_size(git_vector *v) GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size) { - size_t new_bytes = new_size * sizeof(void *); + size_t new_bytes; void *new_contents; /* Check for overflow */ - if (new_bytes / sizeof(void *) != new_size) - GITERR_CHECK_ALLOC(NULL); + GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(void *)); + new_bytes = new_size * sizeof(void *); new_contents = git__realloc(v->contents, new_bytes); GITERR_CHECK_ALLOC(new_contents); @@ -51,6 +51,7 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) assert(v && src); + GITERR_CHECK_ALLOC_MULTIPLY(src->length, sizeof(void *)); bytes = src->length * sizeof(void *); v->_alloc_size = src->length; diff --git a/src/win32/dir.c b/src/win32/dir.c index c7427ea54..9953289f6 100644 --- a/src/win32/dir.c +++ b/src/win32/dir.c @@ -18,9 +18,13 @@ git__DIR *git__opendir(const char *dir) dirlen = strlen(dir); - new = git__calloc(sizeof(*new) + dirlen + 1, 1); - if (!new) + if (GIT_ALLOC_OVERFLOW_ADD(sizeof(*new), dirlen) || + GIT_ALLOC_OVERFLOW_ADD(sizeof(*new) + dirlen, 1) || + !(new = git__calloc(1, sizeof(*new) + dirlen + 1))) { + giterr_set_oom(); return NULL; + } + memcpy(new->dir, dir, dirlen); new->h = FindFirstFileW(filter_w, &new->f); diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c index b0205b019..624611205 100644 --- a/src/win32/utf-conv.c +++ b/src/win32/utf-conv.c @@ -99,9 +99,8 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src) return -1; } - *dest = git__malloc(utf16_size * sizeof(wchar_t)); - - if (!*dest) { + if (GIT_ALLOC_OVERFLOW_MULTIPLY(utf16_size, sizeof(wchar_t)) || + !(*dest = git__malloc(utf16_size * sizeof(wchar_t)))) { errno = ENOMEM; return -1; } diff --git a/src/zstream.c b/src/zstream.c index e75fb265e..06660e981 100644 --- a/src/zstream.c +++ b/src/zstream.c @@ -134,6 +134,7 @@ int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len) while (!git_zstream_done(&zs)) { size_t step = git_zstream_suggest_output_len(&zs), written; + GITERR_CHECK_ALLOC_ADD(out->size, step); if ((error = git_buf_grow(out, out->size + step)) < 0) goto done; |