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
/* 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);
}
......@@ -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
......@@ -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)
......
......@@ -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);
......
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