Commit c6cac733 by Edward Thomson

blob: validate that blob sizes fit in a size_t

Our blob size is a `git_off_t`, which is a signed 64 bit int.  This may
be erroneously negative or larger than `SIZE_MAX`.  Ensure that the blob
size fits into a `size_t` before casting.
parent 3aa6d96a
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "attrcache.h" #include "attrcache.h"
#include "git2/blob.h" #include "git2/blob.h"
#include "git2/tree.h" #include "git2/tree.h"
#include "blob.h"
#include "index.h" #include "index.h"
#include <ctype.h> #include <ctype.h>
...@@ -119,6 +120,7 @@ int git_attr_file__load( ...@@ -119,6 +120,7 @@ int git_attr_file__load(
break; break;
case GIT_ATTR_FILE__FROM_INDEX: { case GIT_ATTR_FILE__FROM_INDEX: {
git_oid id; git_oid id;
git_off_t blobsize;
if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 || if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
(error = git_blob_lookup(&blob, repo, &id)) < 0) (error = git_blob_lookup(&blob, repo, &id)) < 0)
...@@ -126,7 +128,10 @@ int git_attr_file__load( ...@@ -126,7 +128,10 @@ int git_attr_file__load(
/* Do not assume that data straight from the ODB is NULL-terminated; /* Do not assume that data straight from the ODB is NULL-terminated;
* copy the contents of a file to a buffer to work on */ * copy the contents of a file to a buffer to work on */
git_buf_put(&content, git_blob_rawcontent(blob), git_blob_rawsize(blob)); blobsize = git_blob_rawsize(blob);
GIT_ERROR_CHECK_BLOBSIZE(blobsize);
git_buf_put(&content, git_blob_rawcontent(blob), (size_t)blobsize);
break; break;
} }
case GIT_ATTR_FILE__FROM_FILE: { case GIT_ATTR_FILE__FROM_FILE: {
......
...@@ -36,10 +36,10 @@ git_off_t git_blob_rawsize(const git_blob *blob) ...@@ -36,10 +36,10 @@ git_off_t git_blob_rawsize(const git_blob *blob)
int git_blob__getbuf(git_buf *buffer, git_blob *blob) int git_blob__getbuf(git_buf *buffer, git_blob *blob)
{ {
return git_buf_set( git_off_t size = git_blob_rawsize(blob);
buffer,
git_blob_rawcontent(blob), GIT_ERROR_CHECK_BLOBSIZE(size);
git_blob_rawsize(blob)); return git_buf_set(buffer, git_blob_rawcontent(blob), (size_t)size);
} }
void git_blob__free(void *_blob) void git_blob__free(void *_blob)
...@@ -389,12 +389,14 @@ cleanup: ...@@ -389,12 +389,14 @@ cleanup:
int git_blob_is_binary(const git_blob *blob) int git_blob_is_binary(const git_blob *blob)
{ {
git_buf content = GIT_BUF_INIT; git_buf content = GIT_BUF_INIT;
git_off_t size;
assert(blob); assert(blob);
size = git_blob_rawsize(blob);
git_buf_attach_notowned(&content, git_blob_rawcontent(blob), git_buf_attach_notowned(&content, git_blob_rawcontent(blob),
min(git_blob_rawsize(blob), (size_t)min(size, GIT_FILTER_BYTES_TO_CHECK_NUL));
GIT_FILTER_BYTES_TO_CHECK_NUL));
return git_buf_text_is_binary(&content); return git_buf_text_is_binary(&content);
} }
......
...@@ -27,6 +27,14 @@ struct git_blob { ...@@ -27,6 +27,14 @@ struct git_blob {
unsigned int raw:1; unsigned int raw:1;
}; };
#define GIT_ERROR_CHECK_BLOBSIZE(n) \
do { \
if (!git__is_sizet(n)) { \
git_error_set(GIT_ERROR_NOMEMORY, "blob contents too large to fit in memory"); \
return -1; \
} \
} while(0)
void git_blob__free(void *blob); void git_blob__free(void *blob);
int git_blob__parse(void *blob, git_odb_object *obj); int git_blob__parse(void *blob, git_odb_object *obj);
int git_blob__parse_raw(void *blob, const char *data, size_t size); int git_blob__parse_raw(void *blob, const char *data, size_t size);
......
...@@ -564,9 +564,14 @@ int git_diff__oid_for_file( ...@@ -564,9 +564,14 @@ int git_diff__oid_for_file(
{ {
git_index_entry entry; git_index_entry entry;
if (!git__is_sizet(size)) {
git_error_set(GIT_ERROR_NOMEMORY, "file size overflow (for 32-bits) on '%s'", path);
return -1;
}
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
entry.mode = mode; entry.mode = mode;
entry.file_size = size; entry.file_size = (size_t)size;
entry.path = (char *)path; entry.path = (char *)path;
return git_diff__oid_for_entry(out, diff, &entry, mode, NULL); return git_diff__oid_for_entry(out, diff, &entry, mode, NULL);
...@@ -628,7 +633,7 @@ int git_diff__oid_for_entry( ...@@ -628,7 +633,7 @@ int git_diff__oid_for_entry(
error = git_odb__hashlink(out, full_path.ptr); error = git_odb__hashlink(out, full_path.ptr);
diff->base.perf.oid_calculations++; diff->base.perf.oid_calculations++;
} else if (!git__is_sizet(entry.file_size)) { } else if (!git__is_sizet(entry.file_size)) {
git_error_set(GIT_ERROR_OS, "file size overflow (for 32-bits) on '%s'", git_error_set(GIT_ERROR_NOMEMORY, "file size overflow (for 32-bits) on '%s'",
entry.path); entry.path);
error = -1; error = -1;
} else if (!(error = git_filter_list_load(&fl, } else if (!(error = git_filter_list_load(&fl,
......
...@@ -54,7 +54,8 @@ int git_diff_file_stats__full_to_buf( ...@@ -54,7 +54,8 @@ int git_diff_file_stats__full_to_buf(
size_t width) size_t width)
{ {
const char *old_path = NULL, *new_path = NULL; const char *old_path = NULL, *new_path = NULL;
size_t padding, old_size, new_size; size_t padding;
git_off_t old_size, new_size;
old_path = delta->old_file.path; old_path = delta->old_file.path;
new_path = delta->new_file.path; new_path = delta->new_file.path;
...@@ -96,7 +97,7 @@ int git_diff_file_stats__full_to_buf( ...@@ -96,7 +97,7 @@ int git_diff_file_stats__full_to_buf(
if (delta->flags & GIT_DIFF_FLAG_BINARY) { if (delta->flags & GIT_DIFF_FLAG_BINARY) {
if (git_buf_printf(out, if (git_buf_printf(out,
"Bin %" PRIuZ " -> %" PRIuZ " bytes", old_size, new_size) < 0) "Bin %" PRId64 " -> %" PRId64 " bytes", old_size, new_size) < 0)
goto on_error; goto on_error;
} }
else { else {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "config.h" #include "config.h"
#include "iterator.h" #include "iterator.h"
#include "signature.h" #include "signature.h"
#include "blob.h"
static int note_error_notfound(void) static int note_error_notfound(void)
{ {
...@@ -319,6 +320,7 @@ static int note_new( ...@@ -319,6 +320,7 @@ static int note_new(
git_blob *blob) git_blob *blob)
{ {
git_note *note = NULL; git_note *note = NULL;
git_off_t blobsize;
note = git__malloc(sizeof(git_note)); note = git__malloc(sizeof(git_note));
GIT_ERROR_CHECK_ALLOC(note); GIT_ERROR_CHECK_ALLOC(note);
...@@ -329,7 +331,10 @@ static int note_new( ...@@ -329,7 +331,10 @@ static int note_new(
git_signature_dup(&note->committer, git_commit_committer(commit)) < 0) git_signature_dup(&note->committer, git_commit_committer(commit)) < 0)
return -1; return -1;
note->message = git__strndup(git_blob_rawcontent(blob), git_blob_rawsize(blob)); blobsize = git_blob_rawsize(blob);
GIT_ERROR_CHECK_BLOBSIZE(blobsize);
note->message = git__strndup(git_blob_rawcontent(blob), (size_t)blobsize);
GIT_ERROR_CHECK_ALLOC(note->message); GIT_ERROR_CHECK_ALLOC(note->message);
*out = note; *out = note;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "delta.h" #include "delta.h"
#include "filter.h" #include "filter.h"
#include "repository.h" #include "repository.h"
#include "blob.h"
#include "git2/odb_backend.h" #include "git2/odb_backend.h"
#include "git2/oid.h" #include "git2/oid.h"
...@@ -387,18 +388,17 @@ static void fake_wstream__free(git_odb_stream *_stream) ...@@ -387,18 +388,17 @@ static void fake_wstream__free(git_odb_stream *_stream)
static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_off_t size, git_object_t type) static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_off_t size, git_object_t type)
{ {
fake_wstream *stream; fake_wstream *stream;
size_t blobsize;
if (!git__is_ssizet(size)) { GIT_ERROR_CHECK_BLOBSIZE(size);
git_error_set(GIT_ERROR_ODB, "object size too large to keep in memory"); blobsize = (size_t)size;
return -1;
}
stream = git__calloc(1, sizeof(fake_wstream)); stream = git__calloc(1, sizeof(fake_wstream));
GIT_ERROR_CHECK_ALLOC(stream); GIT_ERROR_CHECK_ALLOC(stream);
stream->size = size; stream->size = blobsize;
stream->type = type; stream->type = type;
stream->buffer = git__malloc(size); stream->buffer = git__malloc(blobsize);
if (stream->buffer == NULL) { if (stream->buffer == NULL) {
git__free(stream); git__free(stream);
return -1; return -1;
......
...@@ -32,11 +32,17 @@ static int tree_reader_read( ...@@ -32,11 +32,17 @@ static int tree_reader_read(
tree_reader *reader = (tree_reader *)_reader; tree_reader *reader = (tree_reader *)_reader;
git_tree_entry *tree_entry = NULL; git_tree_entry *tree_entry = NULL;
git_blob *blob = NULL; git_blob *blob = NULL;
git_off_t blobsize;
int error; int error;
if ((error = git_tree_entry_bypath(&tree_entry, reader->tree, filename)) < 0 || if ((error = git_tree_entry_bypath(&tree_entry, reader->tree, filename)) < 0 ||
(error = git_blob_lookup(&blob, git_tree_owner(reader->tree), git_tree_entry_id(tree_entry))) < 0 || (error = git_blob_lookup(&blob, git_tree_owner(reader->tree), git_tree_entry_id(tree_entry))) < 0)
(error = git_buf_set(out, git_blob_rawcontent(blob), git_blob_rawsize(blob))) < 0) goto done;
blobsize = git_blob_rawsize(blob);
GIT_ERROR_CHECK_BLOBSIZE(blobsize);
if ((error = git_buf_set(out, git_blob_rawcontent(blob), (size_t)blobsize)) < 0)
goto done; goto done;
if (out_id) if (out_id)
......
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