Commit 1e4976cb by Russell Belfer

Be more careful with user-supplied buffers

This adds in missing calls to `git_buf_sanitize` and fixes a
number of places where `git_buf` APIs could inadvertently write
NUL terminator bytes into invalid buffers.  This also changes the
behavior of `git_buf_sanitize` to NUL terminate a buffer if it can
and of `git_buf_shorten` to do nothing if it can.

Adds tests of filtering code with zeroed (i.e. unsanitized) buffer
which was previously triggering a segfault.
parent ed476c23
...@@ -104,17 +104,20 @@ void git_buf_free(git_buf *buf) ...@@ -104,17 +104,20 @@ void git_buf_free(git_buf *buf)
void git_buf_sanitize(git_buf *buf) void git_buf_sanitize(git_buf *buf)
{ {
if (buf->ptr == NULL) { if (buf->ptr == NULL) {
assert (buf->size == 0 && buf->asize == 0); assert(buf->size == 0 && buf->asize == 0);
buf->ptr = git_buf__initbuf; buf->ptr = git_buf__initbuf;
} } else if (buf->asize > buf->size)
buf->ptr[buf->size] = '\0';
} }
void git_buf_clear(git_buf *buf) void git_buf_clear(git_buf *buf)
{ {
buf->size = 0; buf->size = 0;
if (!buf->ptr) if (!buf->ptr) {
buf->ptr = git_buf__initbuf; buf->ptr = git_buf__initbuf;
buf->asize = 0;
}
if (buf->asize > 0) if (buf->asize > 0)
buf->ptr[0] = '\0'; buf->ptr[0] = '\0';
...@@ -129,8 +132,11 @@ int git_buf_set(git_buf *buf, const void *data, size_t len) ...@@ -129,8 +132,11 @@ int git_buf_set(git_buf *buf, const void *data, size_t len)
ENSURE_SIZE(buf, len + 1); ENSURE_SIZE(buf, len + 1);
memmove(buf->ptr, data, len); memmove(buf->ptr, data, len);
} }
buf->size = len; buf->size = len;
buf->ptr[buf->size] = '\0'; if (buf->asize > buf->size)
buf->ptr[buf->size] = '\0';
} }
return 0; return 0;
} }
...@@ -326,19 +332,20 @@ void git_buf_consume(git_buf *buf, const char *end) ...@@ -326,19 +332,20 @@ void git_buf_consume(git_buf *buf, const char *end)
void git_buf_truncate(git_buf *buf, size_t len) void git_buf_truncate(git_buf *buf, size_t len)
{ {
if (len < buf->size) { if (len >= buf->size)
buf->size = len; return;
buf->size = len;
if (buf->size < buf->asize)
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
}
} }
void git_buf_shorten(git_buf *buf, size_t amount) void git_buf_shorten(git_buf *buf, size_t amount)
{ {
if (amount > buf->size) if (buf->size > amount)
amount = buf->size; git_buf_truncate(buf, buf->size - amount);
else
buf->size = buf->size - amount; git_buf_clear(buf);
buf->ptr[buf->size] = '\0';
} }
void git_buf_rtruncate_at_char(git_buf *buf, char separator) void git_buf_rtruncate_at_char(git_buf *buf, char separator)
...@@ -574,7 +581,8 @@ void git_buf_rtrim(git_buf *buf) ...@@ -574,7 +581,8 @@ void git_buf_rtrim(git_buf *buf)
buf->size--; buf->size--;
} }
buf->ptr[buf->size] = '\0'; if (buf->asize > buf->size)
buf->ptr[buf->size] = '\0';
} }
int git_buf_cmp(const git_buf *a, const git_buf *b) int git_buf_cmp(const git_buf *a, const git_buf *b)
...@@ -598,8 +606,7 @@ int git_buf_splice( ...@@ -598,8 +606,7 @@ 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
*/ */
if (git_buf_grow(buf, git_buf_len(buf) + nb_to_insert - nb_to_remove) < 0) ENSURE_SIZE(buf, buf->size + nb_to_insert - nb_to_insert + 1);
return -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,
......
...@@ -967,16 +967,19 @@ void git_config_iterator_free(git_config_iterator *iter) ...@@ -967,16 +967,19 @@ void git_config_iterator_free(git_config_iterator *iter)
int git_config_find_global(git_buf *path) int git_config_find_global(git_buf *path)
{ {
git_buf_sanitize(path);
return git_sysdir_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL); return git_sysdir_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL);
} }
int git_config_find_xdg(git_buf *path) int git_config_find_xdg(git_buf *path)
{ {
git_buf_sanitize(path);
return git_sysdir_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG); return git_sysdir_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG);
} }
int git_config_find_system(git_buf *path) int git_config_find_system(git_buf *path)
{ {
git_buf_sanitize(path);
return git_sysdir_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); return git_sysdir_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM);
} }
......
...@@ -597,9 +597,9 @@ int git_diff_print_callback__to_file_handle( ...@@ -597,9 +597,9 @@ int git_diff_print_callback__to_file_handle(
} }
/* print a git_patch to a git_buf */ /* print a git_patch to a git_buf */
int git_patch_to_buf( int git_patch_to_buf(git_buf *out, git_patch *patch)
git_buf *out,
git_patch *patch)
{ {
assert(out && patch);
git_buf_sanitize(out);
return git_patch_print(patch, git_diff_print_callback__to_buf, out); return git_patch_print(patch, git_diff_print_callback__to_buf, out);
} }
...@@ -578,6 +578,9 @@ int git_filter_list_apply_to_data( ...@@ -578,6 +578,9 @@ int git_filter_list_apply_to_data(
git_buf *dbuffer[2], local = GIT_BUF_INIT; git_buf *dbuffer[2], local = GIT_BUF_INIT;
unsigned int si = 0; unsigned int si = 0;
git_buf_sanitize(tgt);
git_buf_sanitize(src);
if (!fl) if (!fl)
return filter_list_out_buffer_from_raw(tgt, src->ptr, src->size); return filter_list_out_buffer_from_raw(tgt, src->ptr, src->size);
...@@ -613,7 +616,7 @@ int git_filter_list_apply_to_data( ...@@ -613,7 +616,7 @@ int git_filter_list_apply_to_data(
/* PASSTHROUGH means filter decided not to process the buffer */ /* PASSTHROUGH means filter decided not to process the buffer */
error = 0; error = 0;
} else if (!error) { } else if (!error) {
git_buf_shorten(dbuffer[di], 0); /* force NUL termination */ git_buf_sanitize(dbuffer[di]); /* force NUL termination */
si = di; /* swap buffers */ si = di; /* swap buffers */
} else { } else {
tgt->size = 0; tgt->size = 0;
......
...@@ -1276,6 +1276,7 @@ int git_packbuilder_foreach(git_packbuilder *pb, int (*cb)(void *buf, size_t siz ...@@ -1276,6 +1276,7 @@ int git_packbuilder_foreach(git_packbuilder *pb, int (*cb)(void *buf, size_t siz
int git_packbuilder_write_buf(git_buf *buf, git_packbuilder *pb) int git_packbuilder_write_buf(git_buf *buf, git_packbuilder *pb)
{ {
PREPARE_PACK; PREPARE_PACK;
git_buf_sanitize(buf);
return write_pack(pb, &write_pack_buf, buf); return write_pack(pb, &write_pack_buf, buf);
} }
......
...@@ -641,7 +641,9 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur ...@@ -641,7 +641,9 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur
{ {
int error = 0; int error = 0;
assert(url); assert(out && repo && url);
git_buf_sanitize(out);
if (git_path_is_relative(url)) { if (git_path_is_relative(url)) {
if (!(error = get_url_base(out, repo))) if (!(error = get_url_base(out, repo)))
......
...@@ -112,7 +112,7 @@ void test_object_blob_filter__to_odb(void) ...@@ -112,7 +112,7 @@ void test_object_blob_filter__to_odb(void)
git_config *cfg; git_config *cfg;
int i; int i;
git_blob *blob; git_blob *blob;
git_buf out = GIT_BUF_INIT; git_buf out = GIT_BUF_INIT, zeroed;
cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_repository_config(&cfg, g_repo));
cl_assert(cfg); cl_assert(cfg);
...@@ -127,13 +127,20 @@ void test_object_blob_filter__to_odb(void) ...@@ -127,13 +127,20 @@ void test_object_blob_filter__to_odb(void)
for (i = 0; i < CRLF_NUM_TEST_OBJECTS; i++) { for (i = 0; i < CRLF_NUM_TEST_OBJECTS; i++) {
cl_git_pass(git_blob_lookup(&blob, g_repo, &g_crlf_oids[i])); cl_git_pass(git_blob_lookup(&blob, g_repo, &g_crlf_oids[i]));
/* try once with allocated blob */
cl_git_pass(git_filter_list_apply_to_blob(&out, fl, blob)); cl_git_pass(git_filter_list_apply_to_blob(&out, fl, blob));
cl_assert_equal_sz(g_crlf_filtered[i].size, out.size); cl_assert_equal_sz(g_crlf_filtered[i].size, out.size);
cl_assert_equal_i( cl_assert_equal_i(
0, memcmp(out.ptr, g_crlf_filtered[i].ptr, out.size)); 0, memcmp(out.ptr, g_crlf_filtered[i].ptr, out.size));
/* try again with zeroed blob */
memset(&zeroed, 0, sizeof(zeroed));
cl_git_pass(git_filter_list_apply_to_blob(&zeroed, fl, blob));
cl_assert_equal_sz(g_crlf_filtered[i].size, zeroed.size);
cl_assert_equal_i(
0, memcmp(zeroed.ptr, g_crlf_filtered[i].ptr, zeroed.size));
git_buf_free(&zeroed);
git_blob_free(blob); git_blob_free(blob);
} }
......
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