Commit 3101a3e5 by Vicent Marti

refs: Do not overflow when normalizing refnames

parent 3bf3ad9f
...@@ -87,7 +87,7 @@ static int reference_available(git_repository *repo, const char *ref, const char ...@@ -87,7 +87,7 @@ static int reference_available(git_repository *repo, const char *ref, const char
/* name normalization */ /* name normalization */
static int check_valid_ref_char(char ch); static int check_valid_ref_char(char ch);
static int normalize_name(char *buffer_out, const char *name, int is_oid_ref); static int normalize_name(char *buffer_out, size_t out_size, const char *name, int is_oid_ref);
/***************************************** /*****************************************
* Internal methods - Constructor/destructor * Internal methods - Constructor/destructor
...@@ -112,7 +112,7 @@ static int reference_create( ...@@ -112,7 +112,7 @@ static int reference_create(
const char *name, const char *name,
git_rtype type) git_rtype type)
{ {
char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char normalized[GIT_REFNAME_MAX];
int error = GIT_SUCCESS, size; int error = GIT_SUCCESS, size;
git_reference *reference = NULL; git_reference *reference = NULL;
...@@ -134,7 +134,7 @@ static int reference_create( ...@@ -134,7 +134,7 @@ static int reference_create(
reference->owner = repo; reference->owner = repo;
reference->type = type; reference->type = type;
error = normalize_name(normalized, name, (type & GIT_REF_OID)); error = normalize_name(normalized, sizeof(normalized), name, (type & GIT_REF_OID));
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -458,7 +458,7 @@ static int packed_parse_oid( ...@@ -458,7 +458,7 @@ static int packed_parse_oid(
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
int refname_len; int refname_len;
char refname[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char refname[GIT_REFNAME_MAX];
git_oid id; git_oid id;
refname_begin = (buffer + GIT_OID_HEXSZ + 1); refname_begin = (buffer + GIT_OID_HEXSZ + 1);
...@@ -926,7 +926,7 @@ cleanup: ...@@ -926,7 +926,7 @@ cleanup:
static int reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force) static int reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force)
{ {
char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char normalized[GIT_REFNAME_MAX];
int error = GIT_SUCCESS, updated = 0; int error = GIT_SUCCESS, updated = 0;
git_reference *ref = NULL, *old_ref = NULL; git_reference *ref = NULL, *old_ref = NULL;
...@@ -950,7 +950,7 @@ static int reference_create_symbolic(git_reference **ref_out, git_repository *re ...@@ -950,7 +950,7 @@ static int reference_create_symbolic(git_reference **ref_out, git_repository *re
} }
/* The target can aither be the name of an object id reference or the name of another symbolic reference */ /* The target can aither be the name of an object id reference or the name of another symbolic reference */
error = normalize_name(normalized, target, 0); error = normalize_name(normalized, sizeof(normalized), target, 0);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -1092,13 +1092,13 @@ static int reference_rename(git_reference *ref, const char *new_name, int force) ...@@ -1092,13 +1092,13 @@ static int reference_rename(git_reference *ref, const char *new_name, int force)
{ {
int error; int error;
char *old_name; char *old_name;
char old_path[GIT_PATH_MAX], new_path[GIT_PATH_MAX], normalized_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char old_path[GIT_PATH_MAX], new_path[GIT_PATH_MAX], normalized_name[GIT_REFNAME_MAX];
git_reference *looked_up_ref, *old_ref = NULL; git_reference *looked_up_ref, *old_ref = NULL;
assert(ref); assert(ref);
/* Ensure the name is valid */ /* Ensure the name is valid */
error = normalize_name(normalized_name, new_name, ref->type & GIT_REF_OID); error = normalize_name(normalized_name, sizeof(normalized_name), new_name, ref->type & GIT_REF_OID);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to rename reference"); return git__rethrow(error, "Failed to rename reference");
...@@ -1216,13 +1216,13 @@ rename_loose_to_old_name: ...@@ -1216,13 +1216,13 @@ rename_loose_to_old_name:
int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name) int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name)
{ {
int error; int error;
char normalized_name[GIT_PATH_MAX]; char normalized_name[GIT_REFNAME_MAX];
assert(ref_out && repo && name); assert(ref_out && repo && name);
*ref_out = NULL; *ref_out = NULL;
error = normalize_name(normalized_name, name, 0); error = normalize_name(normalized_name, sizeof(normalized_name), name, 0);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to lookup reference"); return git__rethrow(error, "Failed to lookup reference");
...@@ -1688,7 +1688,7 @@ static int check_valid_ref_char(char ch) ...@@ -1688,7 +1688,7 @@ static int check_valid_ref_char(char ch)
} }
} }
static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) static int normalize_name(char *buffer_out, size_t out_size, const char *name, int is_oid_ref)
{ {
const char *name_end, *buffer_out_start; const char *name_end, *buffer_out_start;
char *current; char *current;
...@@ -1700,6 +1700,9 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) ...@@ -1700,6 +1700,9 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
current = (char *)name; current = (char *)name;
name_end = name + strlen(name); name_end = name + strlen(name);
/* Terminating null byte */
out_size--;
/* A refname can not be empty */ /* A refname can not be empty */
if (name_end == name) if (name_end == name)
return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name is empty"); return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name is empty");
...@@ -1708,7 +1711,7 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) ...@@ -1708,7 +1711,7 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
if (*(name_end - 1) == '.' || *(name_end - 1) == '/') if (*(name_end - 1) == '.' || *(name_end - 1) == '/')
return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name ends with dot or slash"); return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name ends with dot or slash");
while (current < name_end) { while (current < name_end && out_size) {
if (check_valid_ref_char(*current)) if (check_valid_ref_char(*current))
return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains invalid characters"); return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains invalid characters");
...@@ -1734,8 +1737,12 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) ...@@ -1734,8 +1737,12 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
contains_a_slash = 1; contains_a_slash = 1;
*buffer_out++ = *current++; *buffer_out++ = *current++;
out_size--;
} }
if (!out_size)
return git__throw(GIT_EINVALIDREFNAME, "Reference name is too long");
/* Object id refname have to contain at least one slash, except /* Object id refname have to contain at least one slash, except
* for HEAD in a detached state or MERGE_HEAD if we're in the * for HEAD in a detached state or MERGE_HEAD if we're in the
* middle of a merge */ * middle of a merge */
...@@ -1759,14 +1766,14 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) ...@@ -1759,14 +1766,14 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_reference__normalize_name(char *buffer_out, const char *name) int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name)
{ {
return normalize_name(buffer_out, name, 0); return normalize_name(buffer_out, out_size, name, 0);
} }
int git_reference__normalize_name_oid(char *buffer_out, const char *name) int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name)
{ {
return normalize_name(buffer_out, name, 1); return normalize_name(buffer_out, out_size, name, 1);
} }
...@@ -14,12 +14,13 @@ ...@@ -14,12 +14,13 @@
#define GIT_SYMREF "ref: " #define GIT_SYMREF "ref: "
#define GIT_PACKEDREFS_FILE "packed-refs" #define GIT_PACKEDREFS_FILE "packed-refs"
#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled " #define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled "
#define MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH 100
#define GIT_HEAD_FILE "HEAD" #define GIT_HEAD_FILE "HEAD"
#define GIT_MERGE_HEAD_FILE "MERGE_HEAD" #define GIT_MERGE_HEAD_FILE "MERGE_HEAD"
#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master" #define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"
#define GIT_REFNAME_MAX 1024
struct git_reference { struct git_reference {
git_repository *owner; git_repository *owner;
char *name; char *name;
...@@ -37,7 +38,7 @@ typedef struct { ...@@ -37,7 +38,7 @@ typedef struct {
void git_repository__refcache_free(git_refcache *refs); void git_repository__refcache_free(git_refcache *refs);
int git_repository__refcache_init(git_refcache *refs); int git_repository__refcache_init(git_refcache *refs);
int git_reference__normalize_name(char *buffer_out, const char *name); int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name);
int git_reference__normalize_name_oid(char *buffer_out, const char *name); int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name);
#endif #endif
...@@ -237,7 +237,7 @@ static int tag_create( ...@@ -237,7 +237,7 @@ static int tag_create(
char *tagger_str; char *tagger_str;
git_reference *new_ref; git_reference *new_ref;
char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char ref_name[GIT_REFNAME_MAX];
int type_str_len, tag_name_len, tagger_str_len, message_len; int type_str_len, tag_name_len, tagger_str_len, message_len;
int error, should_update_ref = 0; int error, should_update_ref = 0;
...@@ -310,7 +310,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu ...@@ -310,7 +310,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
git_odb_stream *stream; git_odb_stream *stream;
git_reference *new_ref; git_reference *new_ref;
char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char ref_name[GIT_REFNAME_MAX];
assert(oid && buffer); assert(oid && buffer);
...@@ -324,14 +324,12 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu ...@@ -324,14 +324,12 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
if ((error = tag_valid_in_odb(&new_ref, ref_name, &tag.target, tag.type, repo, tag.tag_name)) < GIT_SUCCESS) if ((error = tag_valid_in_odb(&new_ref, ref_name, &tag.target, tag.type, repo, tag.tag_name)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag"); return git__rethrow(error, "Failed to create tag");
if(new_ref != NULL) { if (new_ref != NULL) {
git_oid_cpy(oid, git_reference_oid(new_ref)); git_oid_cpy(oid, git_reference_oid(new_ref));
return git__throw(GIT_EEXISTS, "Tag already exists"); return git__throw(GIT_EEXISTS, "Tag already exists");
} }
/* write the buffer */ /* write the buffer */
if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag"); return git__rethrow(error, "Failed to create tag");
...@@ -419,7 +417,7 @@ int git_tag_delete(git_repository *repo, const char *tag_name) ...@@ -419,7 +417,7 @@ int git_tag_delete(git_repository *repo, const char *tag_name)
{ {
int error; int error;
git_reference *tag_ref; git_reference *tag_ref;
char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char ref_name[GIT_REFNAME_MAX];
error = retreive_tag_reference(&tag_ref, ref_name, repo, tag_name); error = retreive_tag_reference(&tag_ref, ref_name, repo, tag_name);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
......
...@@ -34,7 +34,7 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") ...@@ -34,7 +34,7 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference")
git_repository *repo; git_repository *repo;
git_reference *reference; git_reference *reference;
git_object *object; git_object *object;
char ref_name_from_tag_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char ref_name_from_tag_name[GIT_REFNAME_MAX];
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
...@@ -718,12 +718,12 @@ END_TEST ...@@ -718,12 +718,12 @@ END_TEST
static int ensure_refname_normalized(int is_oid_ref, const char *input_refname, const char *expected_refname) static int ensure_refname_normalized(int is_oid_ref, const char *input_refname, const char *expected_refname)
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
char buffer_out[GIT_PATH_MAX]; char buffer_out[GIT_REFNAME_MAX];
if (is_oid_ref) if (is_oid_ref)
error = git_reference__normalize_name_oid(buffer_out, input_refname); error = git_reference__normalize_name_oid(buffer_out, sizeof(buffer_out), input_refname);
else else
error = git_reference__normalize_name(buffer_out, input_refname); error = git_reference__normalize_name(buffer_out, sizeof(buffer_out), input_refname);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
...@@ -804,7 +804,7 @@ BEGIN_TEST(normalize2, "tests borrowed from JGit") ...@@ -804,7 +804,7 @@ BEGIN_TEST(normalize2, "tests borrowed from JGit")
/* NoAsciiControlCharacters */ /* NoAsciiControlCharacters */
{ {
char c; char c;
char buffer[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char buffer[GIT_REFNAME_MAX];
for (c = '\1'; c < ' '; c++) { for (c = '\1'; c < ' '; c++) {
strncpy(buffer, "refs/heads/mast", 15); strncpy(buffer, "refs/heads/mast", 15);
strncpy(buffer + 15, (const char *)&c, 1); strncpy(buffer + 15, (const char *)&c, 1);
......
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