diff --git a/src/refs.c b/src/refs.c index 1b2154b46..ac13736eb 100644 --- a/src/refs.c +++ b/src/refs.c @@ -87,7 +87,7 @@ static int reference_available(git_repository *repo, const char *ref, const char /* name normalization */ 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 @@ -112,7 +112,7 @@ static int reference_create( const char *name, git_rtype type) { - char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + char normalized[GIT_REFNAME_MAX]; int error = GIT_SUCCESS, size; git_reference *reference = NULL; @@ -134,7 +134,7 @@ static int reference_create( reference->owner = repo; 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) goto cleanup; @@ -458,7 +458,7 @@ static int packed_parse_oid( int error = GIT_SUCCESS; int refname_len; - char refname[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + char refname[GIT_REFNAME_MAX]; git_oid id; refname_begin = (buffer + GIT_OID_HEXSZ + 1); @@ -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) { - char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + char normalized[GIT_REFNAME_MAX]; int error = GIT_SUCCESS, updated = 0; git_reference *ref = NULL, *old_ref = NULL; @@ -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 */ - error = normalize_name(normalized, target, 0); + error = normalize_name(normalized, sizeof(normalized), target, 0); if (error < GIT_SUCCESS) goto cleanup; @@ -1092,13 +1092,13 @@ static int reference_rename(git_reference *ref, const char *new_name, int force) { int error; 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; assert(ref); /* 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) return git__rethrow(error, "Failed to rename reference"); @@ -1216,13 +1216,13 @@ rename_loose_to_old_name: int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name) { int error; - char normalized_name[GIT_PATH_MAX]; + char normalized_name[GIT_REFNAME_MAX]; assert(ref_out && repo && name); *ref_out = NULL; - error = normalize_name(normalized_name, name, 0); + error = normalize_name(normalized_name, sizeof(normalized_name), name, 0); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to lookup reference"); @@ -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; char *current; @@ -1700,6 +1700,9 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) current = (char *)name; name_end = name + strlen(name); + /* Terminating null byte */ + out_size--; + /* A refname can not be empty */ if (name_end == name) 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) if (*(name_end - 1) == '.' || *(name_end - 1) == '/') 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)) 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) contains_a_slash = 1; *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 * for HEAD in a detached state or MERGE_HEAD if we're in the * middle of a merge */ @@ -1759,14 +1766,14 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) 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); } diff --git a/src/refs.h b/src/refs.h index b8f3e2f6d..a0159b091 100644 --- a/src/refs.h +++ b/src/refs.h @@ -14,12 +14,13 @@ #define GIT_SYMREF "ref: " #define GIT_PACKEDREFS_FILE "packed-refs" #define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled " -#define MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH 100 #define GIT_HEAD_FILE "HEAD" #define GIT_MERGE_HEAD_FILE "MERGE_HEAD" #define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master" +#define GIT_REFNAME_MAX 1024 + struct git_reference { git_repository *owner; char *name; @@ -37,7 +38,7 @@ typedef struct { void git_repository__refcache_free(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_oid(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, size_t out_size, const char *name); #endif diff --git a/src/tag.c b/src/tag.c index 4a0710fc1..c3924a1f8 100644 --- a/src/tag.c +++ b/src/tag.c @@ -237,7 +237,7 @@ static int tag_create( char *tagger_str; 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 error, should_update_ref = 0; @@ -310,7 +310,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu git_odb_stream *stream; git_reference *new_ref; - char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + char ref_name[GIT_REFNAME_MAX]; assert(oid && buffer); @@ -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) 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)); return git__throw(GIT_EEXISTS, "Tag already exists"); } - /* write the buffer */ - if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) return git__rethrow(error, "Failed to create tag"); @@ -419,7 +417,7 @@ int git_tag_delete(git_repository *repo, const char *tag_name) { int error; 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); if (error < GIT_SUCCESS) diff --git a/tests/t10-refs.c b/tests/t10-refs.c index 054991cd4..5efe80447 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -34,7 +34,7 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") git_repository *repo; git_reference *reference; 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)); @@ -718,12 +718,12 @@ END_TEST static int ensure_refname_normalized(int is_oid_ref, const char *input_refname, const char *expected_refname) { int error = GIT_SUCCESS; - char buffer_out[GIT_PATH_MAX]; + char buffer_out[GIT_REFNAME_MAX]; 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 - 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) return error; @@ -804,7 +804,7 @@ BEGIN_TEST(normalize2, "tests borrowed from JGit") /* NoAsciiControlCharacters */ { char c; - char buffer[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + char buffer[GIT_REFNAME_MAX]; for (c = '\1'; c < ' '; c++) { strncpy(buffer, "refs/heads/mast", 15); strncpy(buffer + 15, (const char *)&c, 1);