Skip to content

Commit 275f103

Browse files
committed
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.
1 parent c0487bd commit 275f103

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

src/odb.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ static git_cache *odb_cache(git_odb *odb)
5353

5454
static int odb_otype_fast(git_otype *type_p, git_odb *db, const git_oid *id);
5555
static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth);
56+
static int error_null_oid(int error, const char *message);
5657

5758
static git_otype odb_hardcoded_type(const git_oid *id)
5859
{
@@ -735,6 +736,9 @@ int git_odb_exists(git_odb *db, const git_oid *id)
735736

736737
assert(db && id);
737738

739+
if (git_oid_iszero(id))
740+
return 0;
741+
738742
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
739743
git_odb_object_free(object);
740744
return 1;
@@ -958,14 +962,18 @@ int git_odb__read_header_or_object(
958962

959963
assert(db && id && out && len_p && type_p);
960964

965+
*out = NULL;
966+
967+
if (git_oid_iszero(id))
968+
return error_null_oid(GIT_ENOTFOUND, "cannot read object");
969+
961970
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
962971
*len_p = object->cached.size;
963972
*type_p = object->cached.type;
964973
*out = object;
965974
return 0;
966975
}
967976

968-
*out = NULL;
969977
error = odb_read_header_1(len_p, type_p, db, id, false);
970978

971979
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)
10571065

10581066
assert(out && db && id);
10591067

1068+
if (git_oid_iszero(id))
1069+
return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1070+
10601071
*out = git_cache_get_raw(odb_cache(db), id);
10611072
if (*out != NULL)
10621073
return 0;
@@ -1078,6 +1089,9 @@ static int odb_otype_fast(git_otype *type_p, git_odb *db, const git_oid *id)
10781089
size_t _unused;
10791090
int error;
10801091

1092+
if (git_oid_iszero(id))
1093+
return error_null_oid(GIT_ENOTFOUND, "cannot get object type");
1094+
10811095
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
10821096
*type_p = object->cached.type;
10831097
return 0;
@@ -1231,6 +1245,10 @@ int git_odb_write(
12311245
assert(oid && db);
12321246

12331247
git_odb_hash(oid, data, len, type);
1248+
1249+
if (git_oid_iszero(oid))
1250+
return error_null_oid(GIT_EINVALID, "cannot write object");
1251+
12341252
if (git_odb__freshen(db, oid))
12351253
return 0;
12361254

@@ -1484,6 +1502,12 @@ int git_odb__error_notfound(
14841502
return GIT_ENOTFOUND;
14851503
}
14861504

1505+
static int error_null_oid(int error, const char *message)
1506+
{
1507+
giterr_set(GITERR_ODB, "odb: %s: null OID cannot exist", message);
1508+
return error;
1509+
}
1510+
14871511
int git_odb__error_ambiguous(const char *message)
14881512
{
14891513
giterr_set(GITERR_ODB, "ambiguous SHA1 prefix - %s", message);

tests/odb/backend/simple.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,21 @@ void test_odb_backend_simple__exists_with_highly_ambiguous_prefix(void)
230230
cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 40));
231231
cl_assert(git_oid_equal(&found, &_oid));
232232
}
233+
234+
void test_odb_backend_simple__null_oid_is_ignored(void)
235+
{
236+
const fake_object objs[] = {
237+
{ "0000000000000000000000000000000000000000", "null oid content" },
238+
{ NULL, NULL }
239+
};
240+
git_oid null_oid = {{0}};
241+
git_odb_object *obj;
242+
243+
setup_backend(objs);
244+
245+
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
246+
cl_assert(!git_odb_exists(_odb, &null_oid));
247+
248+
cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&obj, _odb, &null_oid));
249+
cl_assert(giterr_last() && strstr(giterr_last()->message, "null OID"));
250+
}

0 commit comments

Comments
 (0)