Unverified Commit dd2d5381 by Patrick Steinhardt Committed by GitHub

Merge pull request #4572 from pks-t/pks/index-secfixes

Security fixes for reading index v4
parents 3f15bf8b 182e8e5e
v0.26.2
-------
This is a security release fixing memory handling issues when reading crafted
repository index files. The issues allow for possible denial of service due to
allocation of large memory and out-of-bound reads.
As the index is never transferred via the network, exploitation requires an
attacker to have access to the local repository.
v0.26.1 v0.26.1
--------- ---------
......
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
#ifndef INCLUDE_git_version_h__ #ifndef INCLUDE_git_version_h__
#define INCLUDE_git_version_h__ #define INCLUDE_git_version_h__
#define LIBGIT2_VERSION "0.26.1" #define LIBGIT2_VERSION "0.26.2"
#define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MAJOR 0
#define LIBGIT2_VER_MINOR 26 #define LIBGIT2_VER_MINOR 26
#define LIBGIT2_VER_REVISION 1 #define LIBGIT2_VER_REVISION 2
#define LIBGIT2_VER_PATCH 0 #define LIBGIT2_VER_PATCH 0
#define LIBGIT2_SOVERSION 26 #define LIBGIT2_SOVERSION 26
......
...@@ -2295,8 +2295,9 @@ static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flag ...@@ -2295,8 +2295,9 @@ static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flag
} }
} }
static size_t read_entry( static int read_entry(
git_index_entry **out, git_index_entry **out,
size_t *out_size,
git_index *index, git_index *index,
const void *buffer, const void *buffer,
size_t buffer_size, size_t buffer_size,
...@@ -2310,7 +2311,7 @@ static size_t read_entry( ...@@ -2310,7 +2311,7 @@ static size_t read_entry(
char *tmp_path = NULL; char *tmp_path = NULL;
if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size) if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
return 0; return -1;
/* buffer is not guaranteed to be aligned */ /* buffer is not guaranteed to be aligned */
memcpy(&source, buffer, sizeof(struct entry_short)); memcpy(&source, buffer, sizeof(struct entry_short));
...@@ -2352,7 +2353,7 @@ static size_t read_entry( ...@@ -2352,7 +2353,7 @@ static size_t read_entry(
path_end = memchr(path_ptr, '\0', buffer_size); path_end = memchr(path_ptr, '\0', buffer_size);
if (path_end == NULL) if (path_end == NULL)
return 0; return -1;
path_length = path_end - path_ptr; path_length = path_end - path_ptr;
} }
...@@ -2360,19 +2361,24 @@ static size_t read_entry( ...@@ -2360,19 +2361,24 @@ static size_t read_entry(
entry_size = index_entry_size(path_length, 0, entry.flags); entry_size = index_entry_size(path_length, 0, entry.flags);
entry.path = (char *)path_ptr; entry.path = (char *)path_ptr;
} else { } else {
size_t varint_len; size_t varint_len, last_len, prefix_len, suffix_len, path_len;
size_t strip_len = git_decode_varint((const unsigned char *)path_ptr, uintmax_t strip_len;
&varint_len);
size_t last_len = strlen(last); strip_len = git_decode_varint((const unsigned char *)path_ptr, &varint_len);
size_t prefix_len = last_len - strip_len; last_len = strlen(last);
size_t suffix_len = strlen(path_ptr + varint_len);
size_t path_len; if (varint_len == 0 || last_len < strip_len)
if (varint_len == 0)
return index_error_invalid("incorrect prefix length"); return index_error_invalid("incorrect prefix length");
prefix_len = last_len - strip_len;
suffix_len = strlen(path_ptr + varint_len);
GITERR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len); GITERR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
GITERR_CHECK_ALLOC_ADD(&path_len, path_len, 1); GITERR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
if (path_len > GIT_PATH_MAX)
return index_error_invalid("unreasonable path length");
tmp_path = git__malloc(path_len); tmp_path = git__malloc(path_len);
GITERR_CHECK_ALLOC(tmp_path); GITERR_CHECK_ALLOC(tmp_path);
...@@ -2382,16 +2388,20 @@ static size_t read_entry( ...@@ -2382,16 +2388,20 @@ static size_t read_entry(
entry.path = tmp_path; entry.path = tmp_path;
} }
if (entry_size == 0)
return -1;
if (INDEX_FOOTER_SIZE + entry_size > buffer_size) if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
return 0; return -1;
if (index_entry_dup(out, index, &entry) < 0) { if (index_entry_dup(out, index, &entry) < 0) {
git__free(tmp_path); git__free(tmp_path);
return 0; return -1;
} }
git__free(tmp_path); git__free(tmp_path);
return entry_size; *out_size = entry_size;
return 0;
} }
static int read_header(struct index_header *dest, const void *buffer) static int read_header(struct index_header *dest, const void *buffer)
...@@ -2495,10 +2505,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) ...@@ -2495,10 +2505,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
/* Parse all the entries */ /* Parse all the entries */
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) { for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
git_index_entry *entry; git_index_entry *entry;
size_t entry_size = read_entry(&entry, index, buffer, buffer_size, last); size_t entry_size;
/* 0 bytes read means an object corruption */ if ((error = read_entry(&entry, &entry_size, index, buffer, buffer_size, last)) < 0) {
if (entry_size == 0) {
error = index_error_invalid("invalid entry"); error = index_error_invalid("invalid entry");
goto done; goto done;
} }
......
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