Commit 392702ee by Edward Thomson Committed by Edward Thomson

allocations: test for overflow of requested size

Introduce some helper macros to test integer overflow from arithmetic
and set error message appropriately.
parent d24a5312
...@@ -45,15 +45,28 @@ typedef git_array_t(char) git_array_generic_t; ...@@ -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) GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
{ {
volatile git_array_generic_t *a = _a; volatile git_array_generic_t *a = _a;
uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2; uint32_t new_size;
char *new_array = git__realloc(a->ptr, new_size * item_size); char *new_array;
if (!new_array) {
git_array_clear(*a); if (a->size < 8) {
return NULL; new_size = 8;
} else { } else {
a->ptr = new_array; a->asize = new_size; a->size++; if (GIT_ALLOC_OVERFLOW_MULTIPLY(a->size, 3 / 2))
return a->ptr + (a->size - 1) * item_size; 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) \ #define git_array_alloc(a) \
......
...@@ -76,6 +76,10 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk) ...@@ -76,6 +76,10 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk)
hunk->lines_in_hunk, hunk->lines_in_hunk,
hunk->orig_start_line_number, hunk->orig_start_line_number,
hunk->orig_path); hunk->orig_path);
if (!newhunk)
return NULL;
git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id); git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id);
git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id); git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id);
newhunk->boundary = hunk->boundary; newhunk->boundary = hunk->boundary;
...@@ -221,6 +225,10 @@ static git_blame_hunk *split_hunk_in_vector( ...@@ -221,6 +225,10 @@ static git_blame_hunk *split_hunk_in_vector(
new_line_count = hunk->lines_in_hunk - rel_line; 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, 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); (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->final_commit_id, &hunk->final_commit_id);
git_oid_cpy(&nh->orig_commit_id, &hunk->orig_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) ...@@ -270,6 +278,10 @@ static git_blame_hunk* hunk_from_entry(git_blame__entry *e)
{ {
git_blame_hunk *h = new_hunk( git_blame_hunk *h = new_hunk(
e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path); 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->final_commit_id, git_commit_id(e->suspect->commit));
git_oid_cpy(&h->orig_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)); git_signature_dup(&h->final_signature, git_commit_author(e->suspect->commit));
...@@ -307,6 +319,8 @@ static int blame_internal(git_blame *blame) ...@@ -307,6 +319,8 @@ static int blame_internal(git_blame *blame)
blame->final_buf_size = git_blob_rawsize(blame->final_blob); blame->final_buf_size = git_blob_rawsize(blame->final_blob);
ent = git__calloc(1, sizeof(git_blame__entry)); ent = git__calloc(1, sizeof(git_blame__entry));
GITERR_CHECK_ALLOC(ent);
ent->num_lines = index_blob_lines(blame); ent->num_lines = index_blob_lines(blame);
ent->lno = blame->options.min_line - 1; ent->lno = blame->options.min_line - 1;
ent->num_lines = ent->num_lines - 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) ...@@ -322,8 +336,9 @@ static int blame_internal(git_blame *blame)
cleanup: cleanup:
for (ent = blame->ent; ent; ) { for (ent = blame->ent; ent; ) {
git_blame__entry *e = ent->next; 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); git_blame__free_entry(ent);
ent = e; ent = e;
...@@ -392,11 +407,14 @@ static int buffer_hunk_cb( ...@@ -392,11 +407,14 @@ static int buffer_hunk_cb(
if (!blame->current_hunk) { if (!blame->current_hunk) {
/* Line added at the end of the file */ /* Line added at the end of the file */
blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path); 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); git_vector_insert(&blame->hunks, blame->current_hunk);
} else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ } 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 */ /* 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, blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk,
wedge_line - blame->current_hunk->orig_start_line_number, true); wedge_line - blame->current_hunk->orig_start_line_number, true);
GITERR_CHECK_ALLOC(blame->current_hunk);
} }
return 0; return 0;
...@@ -425,6 +443,8 @@ static int buffer_line_cb( ...@@ -425,6 +443,8 @@ static int buffer_line_cb(
/* Create a new buffer-blame hunk with this line */ /* Create a new buffer-blame hunk with this line */
shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); 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); 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); git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL);
} }
blame->current_diff_line++; blame->current_diff_line++;
...@@ -464,10 +484,14 @@ int git_blame_buffer( ...@@ -464,10 +484,14 @@ int git_blame_buffer(
assert(out && reference && buffer && buffer_len); assert(out && reference && buffer && buffer_len);
blame = git_blame__alloc(reference->repository, reference->options, reference->path); blame = git_blame__alloc(reference->repository, reference->options, reference->path);
GITERR_CHECK_ALLOC(blame);
/* Duplicate all of the hunk structures in the reference blame */ /* Duplicate all of the hunk structures in the reference blame */
git_vector_foreach(&reference->hunks, i, hunk) { 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 to the reference blob */
......
...@@ -35,10 +35,14 @@ static void origin_decref(git_blame__origin *o) ...@@ -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. */ /* 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) static int make_origin(git_blame__origin **out, git_commit *commit, const char *path)
{ {
int error = 0;
git_blame__origin *o; 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); GITERR_CHECK_ALLOC(o);
o->commit = commit; o->commit = commit;
o->refcnt = 1; o->refcnt = 1;
......
...@@ -29,6 +29,8 @@ int git_buf_text_puts_escaped( ...@@ -29,6 +29,8 @@ int git_buf_text_puts_escaped(
scan += count; 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) if (git_buf_grow(buf, buf->size + total + 1) < 0)
return -1; return -1;
...@@ -73,8 +75,10 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src) ...@@ -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); return git_buf_set(tgt, src->ptr, src->size);
/* reduce reallocs while in the loop */ /* reduce reallocs while in the loop */
GITERR_CHECK_ALLOC_ADD(src->size, 1);
if (git_buf_grow(tgt, src->size + 1) < 0) if (git_buf_grow(tgt, src->size + 1) < 0)
return -1; return -1;
out = tgt->ptr; out = tgt->ptr;
tgt->size = 0; tgt->size = 0;
...@@ -117,13 +121,15 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) ...@@ -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); return git_buf_set(tgt, src->ptr, src->size);
/* attempt to reduce reallocs while in the loop */ /* 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) if (git_buf_grow(tgt, src->size + (src->size >> 4) + 1) < 0)
return -1; return -1;
tgt->size = 0; tgt->size = 0;
for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) { for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) {
size_t copylen = next - 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 we find mixed line endings, bail */
if (next > start && next[-1] == '\r') { if (next > start && next[-1] == '\r') {
...@@ -131,6 +137,10 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) ...@@ -131,6 +137,10 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
return GIT_PASSTHROUGH; 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) if (tgt->asize < needsize && git_buf_grow(tgt, needsize) < 0)
return -1; return -1;
......
...@@ -63,6 +63,14 @@ int git_buf_try_grow( ...@@ -63,6 +63,14 @@ int git_buf_try_grow(
/* round allocation up to multiple of 8 */ /* round allocation up to multiple of 8 */
new_size = (new_size + 7) & ~7; 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); new_ptr = git__realloc(new_ptr, new_size);
if (!new_ptr) { if (!new_ptr) {
...@@ -131,6 +139,7 @@ int git_buf_set(git_buf *buf, const void *data, size_t len) ...@@ -131,6 +139,7 @@ int git_buf_set(git_buf *buf, const void *data, size_t len)
git_buf_clear(buf); git_buf_clear(buf);
} else { } else {
if (data != buf->ptr) { if (data != buf->ptr) {
GITERR_CHECK_ALLOC_ADD(len, 1);
ENSURE_SIZE(buf, len + 1); ENSURE_SIZE(buf, len + 1);
memmove(buf->ptr, data, len); memmove(buf->ptr, data, len);
} }
...@@ -160,6 +169,7 @@ int git_buf_sets(git_buf *buf, const char *string) ...@@ -160,6 +169,7 @@ int git_buf_sets(git_buf *buf, const char *string)
int git_buf_putc(git_buf *buf, char c) int git_buf_putc(git_buf *buf, char c)
{ {
GITERR_CHECK_ALLOC_ADD(buf->size, 2);
ENSURE_SIZE(buf, buf->size + 2); ENSURE_SIZE(buf, buf->size + 2);
buf->ptr[buf->size++] = c; buf->ptr[buf->size++] = c;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
...@@ -168,6 +178,8 @@ int git_buf_putc(git_buf *buf, char c) ...@@ -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) 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); ENSURE_SIZE(buf, buf->size + len + 1);
memset(buf->ptr + buf->size, c, len); memset(buf->ptr + buf->size, c, len);
buf->size += len; buf->size += len;
...@@ -179,6 +191,8 @@ int git_buf_put(git_buf *buf, const char *data, size_t len) ...@@ -179,6 +191,8 @@ int git_buf_put(git_buf *buf, const char *data, size_t len)
{ {
if (len) { if (len) {
assert(data); assert(data);
GITERR_CHECK_ALLOC_ADD(buf->size, len);
GITERR_CHECK_ALLOC_ADD(buf->size + len, 1);
ENSURE_SIZE(buf, buf->size + len + 1); ENSURE_SIZE(buf, buf->size + len + 1);
memmove(buf->ptr + buf->size, data, len); memmove(buf->ptr + buf->size, data, len);
buf->size += len; buf->size += len;
...@@ -201,8 +215,12 @@ int git_buf_encode_base64(git_buf *buf, const char *data, size_t len) ...@@ -201,8 +215,12 @@ int git_buf_encode_base64(git_buf *buf, const char *data, size_t len)
size_t extra = len % 3; size_t extra = len % 3;
uint8_t *write, a, b, c; uint8_t *write, a, b, c;
const uint8_t *read = (const uint8_t *)data; 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]; write = (uint8_t *)&buf->ptr[buf->size];
/* convert each run of 3 bytes into 4 output bytes */ /* 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) ...@@ -256,6 +274,8 @@ int git_buf_decode_base64(git_buf *buf, const char *base64, size_t len)
size_t orig_size = buf->size; size_t orig_size = buf->size;
assert(len % 4 == 0); 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); ENSURE_SIZE(buf, buf->size + (len / 4 * 3) + 1);
for (i = 0; i < len; i += 4) { for (i = 0; i < len; i += 4) {
...@@ -284,7 +304,12 @@ static const char b85str[] = ...@@ -284,7 +304,12 @@ static const char b85str[] =
int git_buf_encode_base85(git_buf *buf, const char *data, size_t len) 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) { while (len) {
uint32_t acc = 0; uint32_t acc = 0;
...@@ -317,8 +342,14 @@ int git_buf_encode_base85(git_buf *buf, const char *data, size_t len) ...@@ -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) int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
{ {
size_t expected_size = strlen(format);
int len; 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); ENSURE_SIZE(buf, expected_size);
...@@ -345,6 +376,8 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap) ...@@ -345,6 +376,8 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
break; break;
} }
GITERR_CHECK_ALLOC_ADD(buf->size, len);
GITERR_CHECK_ALLOC_ADD(buf->size + len, 1);
ENSURE_SIZE(buf, 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, ...) ...@@ -481,6 +514,9 @@ int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
/* expand buffer if needed */ /* expand buffer if needed */
if (total_size == 0) if (total_size == 0)
return 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) if (git_buf_grow(buf, buf->size + total_size + 1) < 0)
return -1; return -1;
...@@ -559,6 +595,9 @@ int git_buf_join( ...@@ -559,6 +595,9 @@ int git_buf_join(
if (str_a >= buf->ptr && str_a < buf->ptr + buf->size) if (str_a >= buf->ptr && str_a < buf->ptr + buf->size)
offset_a = str_a - buf->ptr; 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) if (git_buf_grow(buf, strlen_a + strlen_b + need_sep + 1) < 0)
return -1; return -1;
assert(buf->ptr); assert(buf->ptr);
...@@ -607,6 +646,11 @@ int git_buf_join3( ...@@ -607,6 +646,11 @@ int git_buf_join3(
sep_b = (str_b[len_b - 1] != separator); 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) if (git_buf_grow(buf, len_a + sep_a + len_b + sep_b + len_c + 1) < 0)
return -1; return -1;
...@@ -660,6 +704,8 @@ int git_buf_splice( ...@@ -660,6 +704,8 @@ int git_buf_splice(
const char *data, const char *data,
size_t nb_to_insert) size_t nb_to_insert)
{ {
size_t new_size;
assert(buf && assert(buf &&
where <= git_buf_len(buf) && where <= git_buf_len(buf) &&
where + nb_to_remove <= git_buf_len(buf)); where + nb_to_remove <= git_buf_len(buf));
...@@ -667,7 +713,13 @@ int git_buf_splice( ...@@ -667,7 +713,13 @@ int git_buf_splice(
/* Ported from git.git /* Ported from git.git
* https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176 * 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, memmove(buf->ptr + where + nb_to_insert,
buf->ptr + where + nb_to_remove, buf->ptr + where + nb_to_remove,
...@@ -675,7 +727,7 @@ int git_buf_splice( ...@@ -675,7 +727,7 @@ int git_buf_splice(
memcpy(buf->ptr + where, data, nb_to_insert); 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'; buf->ptr[buf->size] = '\0';
return 0; return 0;
} }
...@@ -174,6 +174,28 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v ...@@ -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); \ GITERR_CHECK_VERSION(&(VERSION), _tmpl.version, #TYPE); \
memcpy((PTR), &_tmpl, sizeof(_tmpl)); } while (0) 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 */ /* NOTE: other giterr functions are in the public errors.h header file */
#include "util.h" #include "util.h"
......
...@@ -903,9 +903,11 @@ static char *reader_readline(struct reader *reader, bool skip_whitespace) ...@@ -903,9 +903,11 @@ static char *reader_readline(struct reader *reader, bool skip_whitespace)
line_len = line_end - line_src; line_len = line_end - line_src;
line = git__malloc(line_len + 1); if (GIT_ALLOC_OVERFLOW_ADD(line_len, 1) ||
if (line == NULL) (line = git__malloc(line_len + 1)) == NULL) {
giterr_set_oom();
return NULL; return NULL;
}
memcpy(line, line_src, line_len); memcpy(line, line_src, line_len);
...@@ -958,6 +960,8 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con ...@@ -958,6 +960,8 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
int c, rpos; int c, rpos;
char *first_quote, *last_quote; char *first_quote, *last_quote;
git_buf buf = GIT_BUF_INIT; 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 * 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 * 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 ...@@ -966,13 +970,17 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
first_quote = strchr(line, '"'); first_quote = strchr(line, '"');
last_quote = strrchr(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"); set_parse_error(reader, 0, "Missing closing quotation mark in section header");
return -1; 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); git_buf_printf(&buf, "%s.", base_name);
rpos = 0; rpos = 0;
...@@ -1029,6 +1037,7 @@ static int parse_section_header(struct reader *reader, char **section_out) ...@@ -1029,6 +1037,7 @@ static int parse_section_header(struct reader *reader, char **section_out)
int name_length, c, pos; int name_length, c, pos;
int result; int result;
char *line; char *line;
size_t line_len;
line = reader_readline(reader, true); line = reader_readline(reader, true);
if (line == NULL) if (line == NULL)
...@@ -1042,7 +1051,10 @@ static int parse_section_header(struct reader *reader, char **section_out) ...@@ -1042,7 +1051,10 @@ static int parse_section_header(struct reader *reader, char **section_out)
return -1; 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); GITERR_CHECK_ALLOC(name);
name_length = 0; name_length = 0;
...@@ -1603,11 +1615,16 @@ static char *escape_value(const char *ptr) ...@@ -1603,11 +1615,16 @@ static char *escape_value(const char *ptr)
/* '\"' -> '"' etc */ /* '\"' -> '"' etc */
static char *fixup_line(const char *ptr, int quote_count) static char *fixup_line(const char *ptr, int quote_count)
{ {
char *str = git__malloc(strlen(ptr) + 1); char *str, *out, *esc;
char *out = str, *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; return NULL;
}
out = str;
while (*ptr != '\0') { while (*ptr != '\0') {
if (*ptr == '"') { if (*ptr == '"') {
......
...@@ -74,6 +74,7 @@ int git__delta_apply( ...@@ -74,6 +74,7 @@ int git__delta_apply(
return -1; return -1;
} }
GITERR_CHECK_ALLOC_ADD(res_sz, 1);
res_dp = git__malloc(res_sz + 1); res_dp = git__malloc(res_sz + 1);
GITERR_CHECK_ALLOC(res_dp); GITERR_CHECK_ALLOC(res_dp);
......
...@@ -119,6 +119,36 @@ struct git_delta_index { ...@@ -119,6 +119,36 @@ struct git_delta_index {
struct index_entry *hash[GIT_FLEX_ARRAY]; 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 * struct git_delta_index *
git_delta_create_index(const void *buf, unsigned long bufsize) git_delta_create_index(const void *buf, unsigned long bufsize)
{ {
...@@ -148,13 +178,9 @@ 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; hsize = 1 << i;
hmask = hsize - 1; hmask = hsize - 1;
/* allocate lookup index */ if (lookup_index_alloc(&mem, &memsize, entries, hsize) < 0)
memsize = sizeof(*index) +
sizeof(*hash) * hsize +
sizeof(*entry) * entries;
mem = git__malloc(memsize);
if (!mem)
return NULL; return NULL;
index = mem; index = mem;
mem = index->hash; mem = index->hash;
hash = mem; hash = mem;
......
...@@ -1558,8 +1558,10 @@ int git_diff_format_email( ...@@ -1558,8 +1558,10 @@ int git_diff_format_email(
goto on_error; goto on_error;
} }
GITERR_CHECK_ALLOC_ADD(offset, 1);
summary = git__calloc(offset + 1, sizeof(char)); summary = git__calloc(offset + 1, sizeof(char));
GITERR_CHECK_ALLOC(summary); GITERR_CHECK_ALLOC(summary);
strncpy(summary, opts->summary, offset); strncpy(summary, opts->summary, offset);
} }
......
...@@ -158,6 +158,29 @@ static git_diff_driver_registry *git_repository_driver_registry( ...@@ -158,6 +158,29 @@ static git_diff_driver_registry *git_repository_driver_registry(
return repo->diff_drivers; 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( static int git_diff_driver_builtin(
git_diff_driver **out, git_diff_driver **out,
git_diff_driver_registry *reg, git_diff_driver_registry *reg,
...@@ -166,7 +189,7 @@ static int git_diff_driver_builtin( ...@@ -166,7 +189,7 @@ static int git_diff_driver_builtin(
int error = 0; int error = 0;
git_diff_driver_definition *ddef = NULL; git_diff_driver_definition *ddef = NULL;
git_diff_driver *drv = NULL; git_diff_driver *drv = NULL;
size_t namelen, idx; size_t idx;
for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) { for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) {
if (!strcasecmp(driver_name, builtin_defs[idx].name)) { if (!strcasecmp(driver_name, builtin_defs[idx].name)) {
...@@ -177,13 +200,10 @@ static int git_diff_driver_builtin( ...@@ -177,13 +200,10 @@ static int git_diff_driver_builtin(
if (!ddef) if (!ddef)
goto done; goto done;
namelen = strlen(ddef->name); if ((error = diff_driver_alloc(&drv, NULL, ddef->name)) < 0)
goto done;
drv = git__calloc(1, sizeof(git_diff_driver) + namelen + 1);
GITERR_CHECK_ALLOC(drv);
drv->type = DIFF_DRIVER_PATTERNLIST; drv->type = DIFF_DRIVER_PATTERNLIST;
memcpy(drv->name, ddef->name, namelen);
if (ddef->fns && if (ddef->fns &&
(error = diff_driver_add_patterns( (error = diff_driver_add_patterns(
...@@ -217,9 +237,9 @@ static int git_diff_driver_load( ...@@ -217,9 +237,9 @@ static int git_diff_driver_load(
int error = 0; int error = 0;
git_diff_driver_registry *reg; git_diff_driver_registry *reg;
git_diff_driver *drv = NULL; git_diff_driver *drv = NULL;
size_t namelen = strlen(driver_name); size_t namelen;
khiter_t pos; khiter_t pos;
git_config *cfg; git_config *cfg = NULL;
git_buf name = GIT_BUF_INIT; git_buf name = GIT_BUF_INIT;
const git_config_entry *ce; const git_config_entry *ce;
bool found_driver = false; bool found_driver = false;
...@@ -233,10 +253,10 @@ static int git_diff_driver_load( ...@@ -233,10 +253,10 @@ static int git_diff_driver_load(
return 0; return 0;
} }
drv = git__calloc(1, sizeof(git_diff_driver) + namelen + 1); if ((error = diff_driver_alloc(&drv, &namelen, driver_name)) < 0)
GITERR_CHECK_ALLOC(drv); goto done;
drv->type = DIFF_DRIVER_AUTO; drv->type = DIFF_DRIVER_AUTO;
memcpy(drv->name, driver_name, namelen);
/* if you can't read config for repo, just use default driver */ /* if you can't read config for repo, just use default driver */
if (git_repository_config_snapshot(&cfg, repo) < 0) { if (git_repository_config_snapshot(&cfg, repo) < 0) {
......
...@@ -388,8 +388,18 @@ static int diff_patch_with_delta_alloc( ...@@ -388,8 +388,18 @@ static int diff_patch_with_delta_alloc(
diff_patch_with_delta *pd; diff_patch_with_delta *pd;
size_t old_len = *old_path ? strlen(*old_path) : 0; size_t old_len = *old_path ? strlen(*old_path) : 0;
size_t new_len = *new_path ? strlen(*new_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); GITERR_CHECK_ALLOC(pd);
pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED; pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED;
......
...@@ -831,6 +831,7 @@ int git_diff_find_similar( ...@@ -831,6 +831,7 @@ int git_diff_find_similar(
if ((opts.flags & GIT_DIFF_FIND_ALL) == 0) if ((opts.flags & GIT_DIFF_FIND_ALL) == 0)
goto cleanup; goto cleanup;
GITERR_CHECK_ALLOC_MULTIPLY(num_deltas, 2);
sigcache = git__calloc(num_deltas * 2, sizeof(void *)); sigcache = git__calloc(num_deltas * 2, sizeof(void *));
GITERR_CHECK_ALLOC(sigcache); GITERR_CHECK_ALLOC(sigcache);
......
...@@ -271,6 +271,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode ...@@ -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); GITERR_CHECK_ALLOC(file->path_original);
/* create the locking path by appending ".lock" to the 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); file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
GITERR_CHECK_ALLOC(file->path_lock); GITERR_CHECK_ALLOC(file->path_lock);
...@@ -437,8 +438,8 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...) ...@@ -437,8 +438,8 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
} while ((size_t)len + 1 <= space_left); } while ((size_t)len + 1 <= space_left);
tmp_buffer = git__malloc(len + 1); if (GIT_ALLOC_OVERFLOW_ADD(len, 1) ||
if (!tmp_buffer) { !(tmp_buffer = git__malloc(len + 1))) {
file->last_error = BUFERR_MEM; file->last_error = BUFERR_MEM;
return -1; return -1;
} }
......
...@@ -127,6 +127,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) ...@@ -127,6 +127,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
git_buf_clear(buf); git_buf_clear(buf);
GITERR_CHECK_ALLOC_ADD(len, 1);
if (git_buf_grow(buf, len + 1) < 0) if (git_buf_grow(buf, len + 1) < 0)
return -1; return -1;
...@@ -708,7 +709,10 @@ static int cp_link(const char *from, const char *to, size_t link_size) ...@@ -708,7 +709,10 @@ static int cp_link(const char *from, const char *to, size_t link_size)
{ {
int error = 0; int error = 0;
ssize_t read_len; 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); GITERR_CHECK_ALLOC(link_data);
read_len = p_readlink(from, link_data, link_size); read_len = p_readlink(from, link_data, link_size);
......
...@@ -228,7 +228,7 @@ int git_filter_register( ...@@ -228,7 +228,7 @@ int git_filter_register(
const char *name, git_filter *filter, int priority) const char *name, git_filter *filter, int priority)
{ {
git_filter_def *fdef; git_filter_def *fdef;
size_t nattr = 0, nmatch = 0; size_t nattr = 0, nmatch = 0, alloc_len;
git_buf attrs = GIT_BUF_INIT; git_buf attrs = GIT_BUF_INIT;
assert(name && filter); assert(name && filter);
...@@ -245,8 +245,16 @@ int git_filter_register( ...@@ -245,8 +245,16 @@ int git_filter_register(
if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0) if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0)
return -1; return -1;
fdef = git__calloc( GITERR_CHECK_ALLOC_MULTIPLY(nattr, 2);
sizeof(git_filter_def) + 2 * nattr * sizeof(char *), 1); 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); GITERR_CHECK_ALLOC(fdef);
fdef->filter_name = git__strdup(name); fdef->filter_name = git__strdup(name);
...@@ -379,6 +387,9 @@ static int filter_list_new( ...@@ -379,6 +387,9 @@ static int filter_list_new(
git_filter_list *fl = NULL; git_filter_list *fl = NULL;
size_t pathlen = src->path ? strlen(src->path) : 0; 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); fl = git__calloc(1, sizeof(git_filter_list) + pathlen + 1);
GITERR_CHECK_ALLOC(fl); GITERR_CHECK_ALLOC(fl);
......
...@@ -779,7 +779,9 @@ static int index_entry_create( ...@@ -779,7 +779,9 @@ static int index_entry_create(
return -1; 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); GITERR_CHECK_ALLOC(entry);
entry->pathlen = pathlen; entry->pathlen = pathlen;
...@@ -826,9 +828,17 @@ static int index_entry_init( ...@@ -826,9 +828,17 @@ static int index_entry_init(
static git_index_reuc_entry *reuc_entry_alloc(const char *path) static git_index_reuc_entry *reuc_entry_alloc(const char *path)
{ {
size_t pathlen = strlen(path); size_t pathlen = strlen(path),
struct reuc_entry_internal *entry = structlen = sizeof(struct reuc_entry_internal);
git__calloc(sizeof(struct reuc_entry_internal) + pathlen + 1, 1); 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) if (!entry)
return NULL; return NULL;
......
...@@ -336,7 +336,7 @@ static int tree_iterator__push_frame(tree_iterator *ti) ...@@ -336,7 +336,7 @@ static int tree_iterator__push_frame(tree_iterator *ti)
{ {
int error = 0; int error = 0;
tree_iterator_frame *head = ti->head, *tf = NULL; 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) if (head->current >= head->n_entries || !head->entries[head->current]->tree)
return GIT_ITEROVER; return GIT_ITEROVER;
...@@ -344,8 +344,13 @@ static int tree_iterator__push_frame(tree_iterator *ti) ...@@ -344,8 +344,13 @@ static int tree_iterator__push_frame(tree_iterator *ti)
for (i = head->current; i < head->next; ++i) for (i = head->current; i < head->next; ++i)
n_entries += git_tree_entrycount(head->entries[i]->tree); n_entries += git_tree_entrycount(head->entries[i]->tree);
tf = git__calloc(sizeof(tree_iterator_frame) + GITERR_CHECK_ALLOC_MULTIPLY(sizeof(tree_iterator_entry *), n_entries);
n_entries * sizeof(tree_iterator_entry *), 1); 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); GITERR_CHECK_ALLOC(tf);
tf->n_entries = n_entries; tf->n_entries = n_entries;
......
...@@ -1169,6 +1169,7 @@ int git_merge_diff_list__find_renames( ...@@ -1169,6 +1169,7 @@ int git_merge_diff_list__find_renames(
goto done; goto done;
if (diff_list->conflicts.length <= opts->target_limit) { 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_size = diff_list->conflicts.length * 3;
cache = git__calloc(cache_size, sizeof(void *)); cache = git__calloc(cache_size, sizeof(void *));
GITERR_CHECK_ALLOC(cache); GITERR_CHECK_ALLOC(cache);
...@@ -2228,6 +2229,7 @@ static int merge_ancestor_head( ...@@ -2228,6 +2229,7 @@ static int merge_ancestor_head(
assert(repo && our_head && their_heads); assert(repo && our_head && their_heads);
GITERR_CHECK_ALLOC_ADD(their_heads_len, 1);
oids = git__calloc(their_heads_len + 1, sizeof(git_oid)); oids = git__calloc(their_heads_len + 1, sizeof(git_oid));
GITERR_CHECK_ALLOC(oids); GITERR_CHECK_ALLOC(oids);
......
...@@ -314,7 +314,7 @@ static int note_new( ...@@ -314,7 +314,7 @@ static int note_new(
{ {
git_note *note = NULL; git_note *note = NULL;
note = (git_note *)git__malloc(sizeof(git_note)); note = git__malloc(sizeof(git_note));
GITERR_CHECK_ALLOC(note); GITERR_CHECK_ALLOC(note);
git_oid_cpy(&note->id, note_oid); git_oid_cpy(&note->id, note_oid);
......
...@@ -233,6 +233,7 @@ int git_odb__hashlink(git_oid *out, const char *path) ...@@ -233,6 +233,7 @@ int git_odb__hashlink(git_oid *out, const char *path)
char *link_data; char *link_data;
ssize_t read_len; ssize_t read_len;
GITERR_CHECK_ALLOC_ADD(size, 1);
link_data = git__malloc((size_t)(size + 1)); link_data = git__malloc((size_t)(size + 1));
GITERR_CHECK_ALLOC(link_data); GITERR_CHECK_ALLOC(link_data);
......
...@@ -64,6 +64,8 @@ static int object_file_name( ...@@ -64,6 +64,8 @@ static int object_file_name(
git_buf *name, const loose_backend *be, const git_oid *id) git_buf *name, const loose_backend *be, const git_oid *id)
{ {
/* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */ /* 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) if (git_buf_grow(name, be->objects_dirlen + GIT_OID_HEXSZ + 3) < 0)
return -1; return -1;
...@@ -268,7 +270,8 @@ static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr) ...@@ -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 * initial sequence of inflated data from the tail of the
* head buffer, if any. * 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); inflateEnd(s);
return NULL; return NULL;
} }
...@@ -321,6 +324,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj) ...@@ -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 * allocate a buffer and inflate the data into it
*/ */
GITERR_CHECK_ALLOC_ADD(hdr.size, 1);
buf = git__malloc(hdr.size + 1); buf = git__malloc(hdr.size + 1);
GITERR_CHECK_ALLOC(buf); GITERR_CHECK_ALLOC(buf);
...@@ -520,6 +524,8 @@ static int locate_object_short_oid( ...@@ -520,6 +524,8 @@ static int locate_object_short_oid(
int error; int error;
/* prealloc memory for OBJ_DIR/xx/xx..38x..xx */ /* 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) if (git_buf_grow(object_location, dir_len + 3 + GIT_OID_HEXSZ) < 0)
return -1; return -1;
...@@ -563,6 +569,8 @@ static int locate_object_short_oid( ...@@ -563,6 +569,8 @@ static int locate_object_short_oid(
return error; return error;
/* Update the location according to the oid obtained */ /* 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); git_buf_truncate(object_location, dir_len);
if (git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2) < 0) if (git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2) < 0)
...@@ -928,6 +936,8 @@ int git_odb_backend_loose( ...@@ -928,6 +936,8 @@ int git_odb_backend_loose(
objects_dirlen = strlen(objects_dir); 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); backend = git__calloc(1, sizeof(loose_backend) + objects_dirlen + 2);
GITERR_CHECK_ALLOC(backend); GITERR_CHECK_ALLOC(backend);
......
...@@ -47,6 +47,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void ...@@ -47,6 +47,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void
if (rval == 0) if (rval == 0)
return 0; return 0;
GITERR_CHECK_ALLOC_ADD(sizeof(struct memobject), len);
obj = git__malloc(sizeof(struct memobject) + len); obj = git__malloc(sizeof(struct memobject) + len);
GITERR_CHECK_ALLOC(obj); GITERR_CHECK_ALLOC(obj);
......
...@@ -261,6 +261,7 @@ struct git_oid_shorten { ...@@ -261,6 +261,7 @@ struct git_oid_shorten {
static int resize_trie(git_oid_shorten *self, size_t new_size) 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)); self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node));
GITERR_CHECK_ALLOC(self->nodes); GITERR_CHECK_ALLOC(self->nodes);
......
...@@ -201,7 +201,11 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, ...@@ -201,7 +201,11 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
return 0; return 0;
if (pb->nr_objects >= pb->nr_alloc) { 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; 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->object_list = git__realloc(pb->object_list,
pb->nr_alloc * sizeof(*po)); pb->nr_alloc * sizeof(*po));
GITERR_CHECK_ALLOC(pb->object_list); GITERR_CHECK_ALLOC(pb->object_list);
...@@ -499,8 +503,13 @@ static int cb_tag_foreach(const char *name, git_oid *oid, void *data) ...@@ -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) static git_pobject **compute_write_order(git_packbuilder *pb)
{ {
unsigned int i, wo_end, last_untagged; 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++) { for (i = 0; i < pb->nr_objects; i++) {
git_pobject *po = pb->object_list + i; git_pobject *po = pb->object_list + i;
...@@ -770,10 +779,13 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg, ...@@ -770,10 +779,13 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
*mem_usage += sz; *mem_usage += sz;
} }
if (!src->data) { 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; return -1;
sz = (unsigned long)git_odb_object_size(obj); sz = (unsigned long)obj_sz;
src->data = git__malloc(sz); src->data = git__malloc(sz);
GITERR_CHECK_ALLOC(src->data); GITERR_CHECK_ALLOC(src->data);
memcpy(src->data, git_odb_object_data(obj), sz); memcpy(src->data, git_odb_object_data(obj), sz);
...@@ -817,7 +829,9 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg, ...@@ -817,7 +829,9 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
trg_object->delta_data = NULL; trg_object->delta_data = NULL;
} }
if (delta_cacheable(pb, src_size, trg_size, delta_size)) { 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; pb->delta_cache_size += delta_size;
git_packbuilder__cache_unlock(pb); git_packbuilder__cache_unlock(pb);
trg_object->delta_data = git__realloc(delta_buf, delta_size); 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, ...@@ -1088,6 +1102,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
return 0; return 0;
} }
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_threads, sizeof(*p));
p = git__malloc(pb->nr_threads * sizeof(*p)); p = git__malloc(pb->nr_threads * sizeof(*p));
GITERR_CHECK_ALLOC(p); GITERR_CHECK_ALLOC(p);
...@@ -1239,6 +1254,7 @@ static int prepare_pack(git_packbuilder *pb) ...@@ -1239,6 +1254,7 @@ static int prepare_pack(git_packbuilder *pb)
if (pb->progress_cb) if (pb->progress_cb)
pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload); 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)); delta_list = git__malloc(pb->nr_objects * sizeof(*delta_list));
GITERR_CHECK_ALLOC(delta_list); GITERR_CHECK_ALLOC(delta_list);
......
...@@ -683,8 +683,11 @@ int git_packfile_unpack( ...@@ -683,8 +683,11 @@ int git_packfile_unpack(
*/ */
if (cached && stack_size == 1) { if (cached && stack_size == 1) {
void *data = obj->data; void *data = obj->data;
GITERR_CHECK_ALLOC_ADD(obj->len, 1);
obj->data = git__malloc(obj->len + 1); obj->data = git__malloc(obj->len + 1);
GITERR_CHECK_ALLOC(obj->data); GITERR_CHECK_ALLOC(obj->data);
memcpy(obj->data, data, obj->len + 1); memcpy(obj->data, data, obj->len + 1);
git_atomic_dec(&cached->refcount); git_atomic_dec(&cached->refcount);
goto cleanup; goto cleanup;
...@@ -841,6 +844,7 @@ int packfile_unpack_compressed( ...@@ -841,6 +844,7 @@ int packfile_unpack_compressed(
z_stream stream; z_stream stream;
unsigned char *buffer, *in; unsigned char *buffer, *in;
GITERR_CHECK_ALLOC_ADD(size, 1);
buffer = git__calloc(1, size + 1); buffer = git__calloc(1, size + 1);
GITERR_CHECK_ALLOC(buffer); GITERR_CHECK_ALLOC(buffer);
...@@ -1092,6 +1096,9 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) ...@@ -1092,6 +1096,9 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
if (path_len < strlen(".idx")) if (path_len < strlen(".idx"))
return git_odb__error_notfound("invalid packfile path", NULL); 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); p = git__calloc(1, sizeof(*p) + path_len + 2);
GITERR_CHECK_ALLOC(p); GITERR_CHECK_ALLOC(p);
......
...@@ -622,7 +622,9 @@ static bool _check_dir_contents( ...@@ -622,7 +622,9 @@ static bool _check_dir_contents(
size_t sub_size = strlen(sub); size_t sub_size = strlen(sub);
/* leave base valid even if we could not make space for subdir */ /* 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; return false;
/* save excursion */ /* save excursion */
...@@ -822,6 +824,9 @@ int git_path_make_relative(git_buf *path, const char *parent) ...@@ -822,6 +824,9 @@ int git_path_make_relative(git_buf *path, const char *parent)
for (; (q = strchr(q, '/')) && *(q + 1); q++) for (; (q = strchr(q, '/')) && *(q + 1); q++)
depth++; 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; newlen = (depth * 3) + plen;
/* save the offset as we might realllocate the pointer */ /* 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) ...@@ -881,6 +886,7 @@ int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen)
git_buf_clear(&ic->buf); git_buf_clear(&ic->buf);
while (1) { while (1) {
GITERR_CHECK_ALLOC_ADD(wantlen, 1);
if (git_buf_grow(&ic->buf, wantlen + 1) < 0) if (git_buf_grow(&ic->buf, wantlen + 1) < 0)
return -1; return -1;
...@@ -1057,6 +1063,45 @@ int git_path_direach( ...@@ -1057,6 +1063,45 @@ int git_path_direach(
return error; 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( int git_path_dirload(
const char *path, const char *path,
size_t prefix_len, size_t prefix_len,
...@@ -1064,7 +1109,7 @@ int git_path_dirload( ...@@ -1064,7 +1109,7 @@ int git_path_dirload(
unsigned int flags, unsigned int flags,
git_vector *contents) git_vector *contents)
{ {
int error, need_slash; int error;
DIR *dir; DIR *dir;
size_t path_len; size_t path_len;
path_dirent_data de_data; path_dirent_data de_data;
...@@ -1096,11 +1141,10 @@ int git_path_dirload( ...@@ -1096,11 +1141,10 @@ int git_path_dirload(
path += prefix_len; path += prefix_len;
path_len -= 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) { while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) {
char *entry_path, *de_path = de->d_name; 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)) if (git_path_is_dot_or_dotdot(de_path))
continue; continue;
...@@ -1110,17 +1154,9 @@ int git_path_dirload( ...@@ -1110,17 +1154,9 @@ int git_path_dirload(
break; break;
#endif #endif
alloc_size = path_len + need_slash + de_len + 1 + alloc_extra; if ((error = entry_path_alloc(&entry_path,
if ((entry_path = git__calloc(alloc_size, 1)) == NULL) { path, path_len, de_path, de_len, alloc_extra)) < 0)
error = -1;
break; 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) { if ((error = git_vector_insert(contents, entry_path)) < 0) {
git__free(entry_path); git__free(entry_path);
......
...@@ -116,9 +116,11 @@ static void *pool_alloc_page(git_pool *pool, uint32_t size) ...@@ -116,9 +116,11 @@ static void *pool_alloc_page(git_pool *pool, uint32_t size)
pool->has_large_page_alloc = 1; pool->has_large_page_alloc = 1;
} }
page = git__calloc(1, alloc_size + sizeof(git_pool_page)); if (GIT_ALLOC_OVERFLOW_ADD(alloc_size, sizeof(git_pool_page)) ||
if (!page) !(page = git__calloc(1, alloc_size + sizeof(git_pool_page)))) {
giterr_set_oom();
return NULL; return NULL;
}
page->size = alloc_size; page->size = alloc_size;
page->avail = alloc_size - size; page->avail = alloc_size - size;
......
...@@ -37,10 +37,14 @@ enum { ...@@ -37,10 +37,14 @@ enum {
static git_reference *alloc_ref(const char *name) static git_reference *alloc_ref(const char *name)
{ {
git_reference *ref; 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; return NULL;
}
memcpy(ref->name, name, namelen + 1); memcpy(ref->name, name, namelen + 1);
...@@ -94,10 +98,14 @@ git_reference *git_reference__set_name( ...@@ -94,10 +98,14 @@ git_reference *git_reference__set_name(
git_reference *ref, const char *name) git_reference *ref, const char *name)
{ {
size_t namelen = strlen(name); size_t namelen = strlen(name);
git_reference *rewrite = size_t reflen = sizeof(git_reference);
git__realloc(ref, sizeof(git_reference) + namelen + 1); git_reference *rewrite = NULL;
if (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); memcpy(rewrite->name, name, namelen + 1);
return rewrite; return rewrite;
} }
......
...@@ -383,10 +383,9 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name) ...@@ -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) if ((error = git_repository_config_snapshot(&config, repo)) < 0)
return error; return error;
remote = git__malloc(sizeof(git_remote)); remote = git__calloc(1, sizeof(git_remote));
GITERR_CHECK_ALLOC(remote); GITERR_CHECK_ALLOC(remote);
memset(remote, 0x0, sizeof(git_remote));
remote->update_fetchhead = 1; remote->update_fetchhead = 1;
remote->name = git__strdup(name); remote->name = git__strdup(name);
GITERR_CHECK_ALLOC(remote->name); GITERR_CHECK_ALLOC(remote->name);
......
...@@ -503,13 +503,9 @@ static int prepare_walk(git_revwalk *walk) ...@@ -503,13 +503,9 @@ static int prepare_walk(git_revwalk *walk)
int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
{ {
git_revwalk *walk; git_revwalk *walk = git__calloc(1, sizeof(git_revwalk));
walk = git__malloc(sizeof(git_revwalk));
GITERR_CHECK_ALLOC(walk); GITERR_CHECK_ALLOC(walk);
memset(walk, 0x0, sizeof(git_revwalk));
walk->commits = git_oidmap_alloc(); walk->commits = git_oidmap_alloc();
GITERR_CHECK_ALLOC(walk->commits); GITERR_CHECK_ALLOC(walk->commits);
......
...@@ -15,7 +15,9 @@ int git_sortedcache_new( ...@@ -15,7 +15,9 @@ int git_sortedcache_new(
pathlen = path ? strlen(path) : 0; 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); GITERR_CHECK_ALLOC(sc);
if (git_pool_init(&sc->pool, 1, 0) < 0 || 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) ...@@ -117,6 +117,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
text_len = search - buffer; text_len = search - buffer;
GITERR_CHECK_ALLOC_ADD(text_len, 1);
tag->tag_name = git__malloc(text_len + 1); tag->tag_name = git__malloc(text_len + 1);
GITERR_CHECK_ALLOC(tag->tag_name); GITERR_CHECK_ALLOC(tag->tag_name);
...@@ -141,6 +142,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) ...@@ -141,6 +142,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
text_len = buffer_end - ++buffer; text_len = buffer_end - ++buffer;
GITERR_CHECK_ALLOC_ADD(text_len, 1);
tag->message = git__malloc(text_len + 1); tag->message = git__malloc(text_len + 1);
GITERR_CHECK_ALLOC(tag->message); GITERR_CHECK_ALLOC(tag->message);
......
...@@ -311,6 +311,9 @@ int git_cred_username_new(git_cred **cred, const char *username) ...@@ -311,6 +311,9 @@ int git_cred_username_new(git_cred **cred, const char *username)
assert(cred); assert(cred);
len = strlen(username); 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); c = git__malloc(sizeof(git_cred_username) + len + 1);
GITERR_CHECK_ALLOC(c); GITERR_CHECK_ALLOC(c);
......
...@@ -154,7 +154,7 @@ static int git_proto_stream_alloc( ...@@ -154,7 +154,7 @@ static int git_proto_stream_alloc(
if (!stream) if (!stream)
return -1; return -1;
s = git__calloc(sizeof(git_proto_stream), 1); s = git__calloc(1, sizeof(git_proto_stream));
GITERR_CHECK_ALLOC(s); GITERR_CHECK_ALLOC(s);
s->parent.subtransport = &t->parent; s->parent.subtransport = &t->parent;
...@@ -347,7 +347,7 @@ int git_smart_subtransport_git(git_smart_subtransport **out, git_transport *owne ...@@ -347,7 +347,7 @@ int git_smart_subtransport_git(git_smart_subtransport **out, git_transport *owne
if (!out) if (!out)
return -1; return -1;
t = git__calloc(sizeof(git_subtransport), 1); t = git__calloc(1, sizeof(git_subtransport));
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
t->owner = owner; t->owner = owner;
......
...@@ -420,7 +420,7 @@ static int local_push( ...@@ -420,7 +420,7 @@ static int local_push(
const git_error *last; const git_error *last;
char *ref = spec->refspec.dst; char *ref = spec->refspec.dst;
status = git__calloc(sizeof(push_status), 1); status = git__calloc(1, sizeof(push_status));
if (!status) if (!status)
goto on_error; goto on_error;
......
...@@ -380,7 +380,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) ...@@ -380,7 +380,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
if (!param) if (!param)
return -1; return -1;
t = git__calloc(sizeof(transport_smart), 1); t = git__calloc(1, sizeof(transport_smart));
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
t->parent.version = GIT_TRANSPORT_VERSION; t->parent.version = GIT_TRANSPORT_VERSION;
......
...@@ -103,6 +103,8 @@ static int comment_pkt(git_pkt **out, const char *line, size_t len) ...@@ -103,6 +103,8 @@ static int comment_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_comment *pkt; 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); pkt = git__malloc(sizeof(git_pkt_comment) + len + 1);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
...@@ -122,6 +124,9 @@ static int err_pkt(git_pkt **out, const char *line, size_t len) ...@@ -122,6 +124,9 @@ static int err_pkt(git_pkt **out, const char *line, size_t len)
/* Remove "ERR " from the line */ /* Remove "ERR " from the line */
line += 4; line += 4;
len -= 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); pkt = git__malloc(sizeof(git_pkt_err) + len + 1);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
...@@ -141,6 +146,8 @@ static int data_pkt(git_pkt **out, const char *line, size_t len) ...@@ -141,6 +146,8 @@ static int data_pkt(git_pkt **out, const char *line, size_t len)
line++; line++;
len--; len--;
GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_progress), len);
pkt = git__malloc(sizeof(git_pkt_data) + len); pkt = git__malloc(sizeof(git_pkt_data) + len);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
...@@ -159,6 +166,8 @@ static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len) ...@@ -159,6 +166,8 @@ static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len)
line++; line++;
len--; len--;
GITERR_CHECK_ALLOC_ADD(sizeof(git_pkt_progress), len);
pkt = git__malloc(sizeof(git_pkt_progress) + len); pkt = git__malloc(sizeof(git_pkt_progress) + len);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
...@@ -177,6 +186,9 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) ...@@ -177,6 +186,9 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len)
line++; line++;
len--; 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); pkt = git__malloc(sizeof(git_pkt_err) + len + 1);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
...@@ -220,6 +232,7 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) ...@@ -220,6 +232,7 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
if (line[len - 1] == '\n') if (line[len - 1] == '\n')
--len; --len;
GITERR_CHECK_ALLOC_ADD(len, 1);
pkt->head.name = git__malloc(len + 1); pkt->head.name = git__malloc(len + 1);
GITERR_CHECK_ALLOC(pkt->head.name); GITERR_CHECK_ALLOC(pkt->head.name);
...@@ -249,9 +262,13 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len) ...@@ -249,9 +262,13 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len)
pkt->type = GIT_PKT_OK; pkt->type = GIT_PKT_OK;
line += 3; /* skip "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; len = ptr - line;
GITERR_CHECK_ALLOC_ADD(len, 1);
pkt->ref = git__malloc(len + 1); pkt->ref = git__malloc(len + 1);
GITERR_CHECK_ALLOC(pkt->ref); GITERR_CHECK_ALLOC(pkt->ref);
...@@ -273,9 +290,13 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) ...@@ -273,9 +290,13 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len)
pkt->type = GIT_PKT_NG; pkt->type = GIT_PKT_NG;
line += 3; /* skip "ng " */ line += 3; /* skip "ng " */
ptr = strchr(line, ' '); if (!(ptr = strchr(line, ' '))) {
giterr_set(GITERR_NET, "Invalid packet line");
return -1;
}
len = ptr - line; len = ptr - line;
GITERR_CHECK_ALLOC_ADD(len, 1);
pkt->ref = git__malloc(len + 1); pkt->ref = git__malloc(len + 1);
GITERR_CHECK_ALLOC(pkt->ref); GITERR_CHECK_ALLOC(pkt->ref);
...@@ -283,9 +304,13 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) ...@@ -283,9 +304,13 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len)
pkt->ref[len] = '\0'; pkt->ref[len] = '\0';
line = ptr + 1; line = ptr + 1;
ptr = strchr(line, '\n'); if (!(ptr = strchr(line, '\n'))) {
giterr_set(GITERR_NET, "Invalid packet line");
return -1;
}
len = ptr - line; len = ptr - line;
GITERR_CHECK_ALLOC_ADD(len, 1);
pkt->msg = git__malloc(len + 1); pkt->msg = git__malloc(len + 1);
GITERR_CHECK_ALLOC(pkt->msg); GITERR_CHECK_ALLOC(pkt->msg);
......
...@@ -685,7 +685,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt) ...@@ -685,7 +685,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
switch (pkt->type) { switch (pkt->type) {
case GIT_PKT_OK: case GIT_PKT_OK:
status = git__calloc(sizeof(push_status), 1); status = git__calloc(1, sizeof(push_status));
GITERR_CHECK_ALLOC(status); GITERR_CHECK_ALLOC(status);
status->msg = NULL; status->msg = NULL;
status->ref = git__strdup(((git_pkt_ok *)pkt)->ref); 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) ...@@ -696,7 +696,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
} }
break; break;
case GIT_PKT_NG: case GIT_PKT_NG:
status = git__calloc(sizeof(push_status), 1); status = git__calloc(1, sizeof(push_status));
GITERR_CHECK_ALLOC(status); GITERR_CHECK_ALLOC(status);
status->ref = git__strdup(((git_pkt_ng *)pkt)->ref); status->ref = git__strdup(((git_pkt_ng *)pkt)->ref);
status->msg = git__strdup(((git_pkt_ng *)pkt)->msg); status->msg = git__strdup(((git_pkt_ng *)pkt)->msg);
......
...@@ -1178,7 +1178,7 @@ static int winhttp_stream_alloc(winhttp_subtransport *t, winhttp_stream **stream ...@@ -1178,7 +1178,7 @@ static int winhttp_stream_alloc(winhttp_subtransport *t, winhttp_stream **stream
if (!stream) if (!stream)
return -1; return -1;
s = git__calloc(sizeof(winhttp_stream), 1); s = git__calloc(1, sizeof(winhttp_stream));
GITERR_CHECK_ALLOC(s); GITERR_CHECK_ALLOC(s);
s->parent.subtransport = &t->parent; s->parent.subtransport = &t->parent;
...@@ -1329,7 +1329,7 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own ...@@ -1329,7 +1329,7 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own
if (!out) if (!out)
return -1; return -1;
t = git__calloc(sizeof(winhttp_subtransport), 1); t = git__calloc(1, sizeof(winhttp_subtransport));
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
t->owner = (transport_smart *)owner; t->owner = (transport_smart *)owner;
......
...@@ -84,11 +84,15 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2) ...@@ -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) static git_tree_entry *alloc_entry(const char *filename)
{ {
git_tree_entry *entry = NULL; 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 (GIT_ALLOC_OVERFLOW_ADD(tree_len, filename_len) ||
if (!entry) GIT_ALLOC_OVERFLOW_ADD(tree_len + filename_len, 1) ||
!(entry = git__malloc(tree_len + filename_len + 1))) {
giterr_set_oom();
return NULL; return NULL;
}
memset(entry, 0x0, sizeof(git_tree_entry)); memset(entry, 0x0, sizeof(git_tree_entry));
memcpy(entry->filename, filename, filename_len); memcpy(entry->filename, filename, filename_len);
...@@ -205,12 +209,16 @@ void git_tree_entry_free(git_tree_entry *entry) ...@@ -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) 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; git_tree_entry *copy;
assert(source); 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); copy = git__malloc(total_size);
GITERR_CHECK_ALLOC(copy); GITERR_CHECK_ALLOC(copy);
......
...@@ -184,7 +184,10 @@ static int check_invariant(struct tsort_run *stack, ssize_t stack_curr) ...@@ -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) static int resize(struct tsort_store *store, size_t new_size)
{ {
if (store->alloc < 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 * Do not propagate on OOM; this will abort the sort and
......
...@@ -64,7 +64,12 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n) ...@@ -64,7 +64,12 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n)
length = p_strnlen(str, 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) if (!ptr)
return NULL; return NULL;
...@@ -80,7 +85,13 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n) ...@@ -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! */ /* NOTE: This doesn't do null or '\0' checking. Watch those boundaries! */
GIT_INLINE(char *) git__substrdup(const char *start, size_t n) 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); memcpy(ptr, start, n);
ptr[n] = '\0'; ptr[n] = '\0';
return ptr; return ptr;
......
...@@ -29,12 +29,12 @@ GIT_INLINE(size_t) compute_new_size(git_vector *v) ...@@ -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) 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; void *new_contents;
/* Check for overflow */ /* Check for overflow */
if (new_bytes / sizeof(void *) != new_size) GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(void *));
GITERR_CHECK_ALLOC(NULL); new_bytes = new_size * sizeof(void *);
new_contents = git__realloc(v->contents, new_bytes); new_contents = git__realloc(v->contents, new_bytes);
GITERR_CHECK_ALLOC(new_contents); GITERR_CHECK_ALLOC(new_contents);
...@@ -51,6 +51,7 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) ...@@ -51,6 +51,7 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
assert(v && src); assert(v && src);
GITERR_CHECK_ALLOC_MULTIPLY(src->length, sizeof(void *));
bytes = src->length * sizeof(void *); bytes = src->length * sizeof(void *);
v->_alloc_size = src->length; v->_alloc_size = src->length;
......
...@@ -18,9 +18,13 @@ git__DIR *git__opendir(const char *dir) ...@@ -18,9 +18,13 @@ git__DIR *git__opendir(const char *dir)
dirlen = strlen(dir); dirlen = strlen(dir);
new = git__calloc(sizeof(*new) + dirlen + 1, 1); if (GIT_ALLOC_OVERFLOW_ADD(sizeof(*new), dirlen) ||
if (!new) GIT_ALLOC_OVERFLOW_ADD(sizeof(*new) + dirlen, 1) ||
!(new = git__calloc(1, sizeof(*new) + dirlen + 1))) {
giterr_set_oom();
return NULL; return NULL;
}
memcpy(new->dir, dir, dirlen); memcpy(new->dir, dir, dirlen);
new->h = FindFirstFileW(filter_w, &new->f); new->h = FindFirstFileW(filter_w, &new->f);
......
...@@ -99,9 +99,8 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src) ...@@ -99,9 +99,8 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
return -1; return -1;
} }
*dest = git__malloc(utf16_size * sizeof(wchar_t)); if (GIT_ALLOC_OVERFLOW_MULTIPLY(utf16_size, sizeof(wchar_t)) ||
!(*dest = git__malloc(utf16_size * sizeof(wchar_t)))) {
if (!*dest) {
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
......
...@@ -134,6 +134,7 @@ int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len) ...@@ -134,6 +134,7 @@ int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len)
while (!git_zstream_done(&zs)) { while (!git_zstream_done(&zs)) {
size_t step = git_zstream_suggest_output_len(&zs), written; 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) if ((error = git_buf_grow(out, out->size + step)) < 0)
goto done; goto done;
......
...@@ -109,3 +109,43 @@ void test_core_errors__restore(void) ...@@ -109,3 +109,43 @@ void test_core_errors__restore(void)
cl_assert_equal_i(42, giterr_last()->klass); cl_assert_equal_i(42, giterr_last()->klass);
cl_assert_equal_s("Foo: bar", giterr_last()->message); cl_assert_equal_s("Foo: bar", giterr_last()->message);
} }
static int test_arraysize_multiply(size_t nelem, size_t size)
{
GITERR_CHECK_ALLOC_MULTIPLY(nelem, size);
return 0;
}
void test_core_errors__integer_overflow_alloc_multiply(void)
{
cl_git_pass(test_arraysize_multiply(10, 10));
cl_git_pass(test_arraysize_multiply(1000, 1000));
cl_git_pass(test_arraysize_multiply(SIZE_MAX/sizeof(void *), sizeof(void *)));
cl_git_pass(test_arraysize_multiply(0, 10));
cl_git_pass(test_arraysize_multiply(10, 0));
cl_git_fail(test_arraysize_multiply(SIZE_MAX-1, sizeof(void *)));
cl_git_fail(test_arraysize_multiply((SIZE_MAX/sizeof(void *))+1, sizeof(void *)));
cl_assert_equal_i(GITERR_NOMEMORY, giterr_last()->klass);
cl_assert_equal_s("Out of memory", giterr_last()->message);
}
static int test_arraysize_add(size_t one, size_t two)
{
GITERR_CHECK_ALLOC_ADD(one, two);
return 0;
}
void test_core_errors__integer_overflow_alloc_add(void)
{
cl_git_pass(test_arraysize_add(10, 10));
cl_git_pass(test_arraysize_add(1000, 1000));
cl_git_pass(test_arraysize_add(SIZE_MAX-10, 10));
cl_git_fail(test_arraysize_multiply(SIZE_MAX-1, 2));
cl_git_fail(test_arraysize_multiply(SIZE_MAX, SIZE_MAX));
cl_assert_equal_i(GITERR_NOMEMORY, giterr_last()->klass);
cl_assert_equal_s("Out of memory", giterr_last()->message);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment