Commit 275f103d by Patrick Steinhardt

odb: reject reading and writing null OIDs

The null OID (hash with all zeroes) indicates a missing object in
upstream git and is thus not a valid object ID. Add defensive
measurements to avoid writing such a hash to the object database in the
very unlikely case where some data results in the null OID. Furthermore,
add shortcuts when reading the null OID from the ODB to avoid ever
returning an object when a faulty repository may contain the null OID.
parent c0487bde
......@@ -53,6 +53,7 @@ static git_cache *odb_cache(git_odb *odb)
static int odb_otype_fast(git_otype *type_p, git_odb *db, const git_oid *id);
static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth);
static int error_null_oid(int error, const char *message);
static git_otype odb_hardcoded_type(const git_oid *id)
{
......@@ -735,6 +736,9 @@ int git_odb_exists(git_odb *db, const git_oid *id)
assert(db && id);
if (git_oid_iszero(id))
return 0;
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
git_odb_object_free(object);
return 1;
......@@ -958,6 +962,11 @@ int git_odb__read_header_or_object(
assert(db && id && out && len_p && type_p);
*out = NULL;
if (git_oid_iszero(id))
return error_null_oid(GIT_ENOTFOUND, "cannot read object");
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
*len_p = object->cached.size;
*type_p = object->cached.type;
......@@ -965,7 +974,6 @@ int git_odb__read_header_or_object(
return 0;
}
*out = NULL;
error = odb_read_header_1(len_p, type_p, db, id, false);
if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
......@@ -1057,6 +1065,9 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
assert(out && db && id);
if (git_oid_iszero(id))
return error_null_oid(GIT_ENOTFOUND, "cannot read object");
*out = git_cache_get_raw(odb_cache(db), id);
if (*out != NULL)
return 0;
......@@ -1078,6 +1089,9 @@ static int odb_otype_fast(git_otype *type_p, git_odb *db, const git_oid *id)
size_t _unused;
int error;
if (git_oid_iszero(id))
return error_null_oid(GIT_ENOTFOUND, "cannot get object type");
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
*type_p = object->cached.type;
return 0;
......@@ -1231,6 +1245,10 @@ int git_odb_write(
assert(oid && db);
git_odb_hash(oid, data, len, type);
if (git_oid_iszero(oid))
return error_null_oid(GIT_EINVALID, "cannot write object");
if (git_odb__freshen(db, oid))
return 0;
......@@ -1484,6 +1502,12 @@ int git_odb__error_notfound(
return GIT_ENOTFOUND;
}
static int error_null_oid(int error, const char *message)
{
giterr_set(GITERR_ODB, "odb: %s: null OID cannot exist", message);
return error;
}
int git_odb__error_ambiguous(const char *message)
{
giterr_set(GITERR_ODB, "ambiguous SHA1 prefix - %s", message);
......
......@@ -230,3 +230,21 @@ void test_odb_backend_simple__exists_with_highly_ambiguous_prefix(void)
cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 40));
cl_assert(git_oid_equal(&found, &_oid));
}
void test_odb_backend_simple__null_oid_is_ignored(void)
{
const fake_object objs[] = {
{ "0000000000000000000000000000000000000000", "null oid content" },
{ NULL, NULL }
};
git_oid null_oid = {{0}};
git_odb_object *obj;
setup_backend(objs);
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
cl_assert(!git_odb_exists(_odb, &null_oid));
cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&obj, _odb, &null_oid));
cl_assert(giterr_last() && strstr(giterr_last()->message, "null OID"));
}
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