Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6ddf533

Browse files
author
Edward Thomson
committed
git_index_add: validate objects in index entries (optionally)
When `GIT_OPT_ENABLE_STRICT_OBJECT_CREATION` is turned on, validate the index entries given to `git_index_add`.
1 parent 2bbc7d3 commit 6ddf533

File tree

3 files changed

+120
-6
lines changed

3 files changed

+120
-6
lines changed

src/index.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,17 +1245,22 @@ static void index_existing_and_best(
12451245
* it, then it will return an error **and also free the entry**. When
12461246
* it replaces an existing entry, it will update the entry_ptr with the
12471247
* actual entry in the index (and free the passed in one).
1248+
*
12481249
* trust_path is whether we use the given path, or whether (on case
12491250
* insensitive systems only) we try to canonicalize the given path to
12501251
* be within an existing directory.
1252+
*
12511253
* trust_mode is whether we trust the mode in entry_ptr.
1254+
*
1255+
* trust_id is whether we trust the id or it should be validated.
12521256
*/
12531257
static int index_insert(
12541258
git_index *index,
12551259
git_index_entry **entry_ptr,
12561260
int replace,
12571261
bool trust_path,
1258-
bool trust_mode)
1262+
bool trust_mode,
1263+
bool trust_id)
12591264
{
12601265
int error = 0;
12611266
size_t path_length, position;
@@ -1288,6 +1293,15 @@ static int index_insert(
12881293
if (!trust_path)
12891294
error = canonicalize_directory_path(index, entry, best);
12901295

1296+
/* ensure that the given id exists (unless it's a submodule) */
1297+
if (!error && !trust_id && INDEX_OWNER(index) &&
1298+
(entry->mode & GIT_FILEMODE_COMMIT) != GIT_FILEMODE_COMMIT) {
1299+
1300+
if (!git_object__is_valid(INDEX_OWNER(index), &entry->id,
1301+
git_object__type_from_filemode(entry->mode)))
1302+
error = -1;
1303+
}
1304+
12911305
/* look for tree / blob name collisions, removing conflicts if requested */
12921306
if (!error)
12931307
error = check_file_directory_collision(index, entry, position, replace);
@@ -1395,7 +1409,7 @@ int git_index_add_frombuffer(
13951409
git_oid_cpy(&entry->id, &id);
13961410
entry->file_size = len;
13971411

1398-
if ((error = index_insert(index, &entry, 1, true, true)) < 0)
1412+
if ((error = index_insert(index, &entry, 1, true, true, true)) < 0)
13991413
return error;
14001414

14011415
/* Adding implies conflict was resolved, move conflict entries to REUC */
@@ -1454,7 +1468,7 @@ int git_index_add_bypath(git_index *index, const char *path)
14541468
assert(index && path);
14551469

14561470
if ((ret = index_entry_init(&entry, index, path)) == 0)
1457-
ret = index_insert(index, &entry, 1, false, false);
1471+
ret = index_insert(index, &entry, 1, false, false, true);
14581472

14591473
/* If we were given a directory, let's see if it's a submodule */
14601474
if (ret < 0 && ret != GIT_EDIRECTORY)
@@ -1480,7 +1494,7 @@ int git_index_add_bypath(git_index *index, const char *path)
14801494
if ((ret = add_repo_as_submodule(&entry, index, path)) < 0)
14811495
return ret;
14821496

1483-
if ((ret = index_insert(index, &entry, 1, false, false)) < 0)
1497+
if ((ret = index_insert(index, &entry, 1, false, false, true)) < 0)
14841498
return ret;
14851499
} else if (ret < 0) {
14861500
return ret;
@@ -1569,7 +1583,7 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
15691583
}
15701584

15711585
if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 ||
1572-
(ret = index_insert(index, &entry, 1, true, true)) < 0)
1586+
(ret = index_insert(index, &entry, 1, true, true, false)) < 0)
15731587
return ret;
15741588

15751589
git_tree_cache_invalidate_path(index->tree, entry->path);
@@ -1731,7 +1745,7 @@ int git_index_conflict_add(git_index *index,
17311745
/* Make sure stage is correct */
17321746
GIT_IDXENTRY_STAGE_SET(entries[i], i + 1);
17331747

1734-
if ((ret = index_insert(index, &entries[i], 1, true, true)) < 0)
1748+
if ((ret = index_insert(index, &entries[i], 1, true, true, false)) < 0)
17351749
goto on_error;
17361750

17371751
entries[i] = NULL; /* don't free if later entry fails */

src/object.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,20 @@ GIT_INLINE(bool) git_object__is_valid(
4646
return valid;
4747
}
4848

49+
GIT_INLINE(git_otype) git_object__type_from_filemode(git_filemode_t mode)
50+
{
51+
switch (mode) {
52+
case GIT_FILEMODE_TREE:
53+
return GIT_OBJ_TREE;
54+
case GIT_FILEMODE_COMMIT:
55+
return GIT_OBJ_COMMIT;
56+
case GIT_FILEMODE_BLOB:
57+
case GIT_FILEMODE_BLOB_EXECUTABLE:
58+
case GIT_FILEMODE_LINK:
59+
return GIT_OBJ_BLOB;
60+
default:
61+
return GIT_OBJ_BAD;
62+
}
63+
}
64+
4965
#endif

tests/index/add.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include "clar_libgit2.h"
2+
3+
static git_repository *g_repo = NULL;
4+
static git_index *g_index = NULL;
5+
6+
static const char *valid_blob_id = "fa49b077972391ad58037050f2a75f74e3671e92";
7+
static const char *valid_tree_id = "181037049a54a1eb5fab404658a3a250b44335d7";
8+
static const char *valid_commit_id = "763d71aadf09a7951596c9746c024e7eece7c7af";
9+
static const char *invalid_id = "1234567890123456789012345678901234567890";
10+
11+
void test_index_add__initialize(void)
12+
{
13+
g_repo = cl_git_sandbox_init("testrepo");
14+
cl_git_pass(git_repository_index(&g_index, g_repo));
15+
}
16+
17+
void test_index_add__cleanup(void)
18+
{
19+
git_index_free(g_index);
20+
cl_git_sandbox_cleanup();
21+
g_repo = NULL;
22+
23+
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0));
24+
}
25+
26+
static void test_add_entry(
27+
bool should_succeed, const char *idstr, git_filemode_t mode)
28+
{
29+
git_index_entry entry = {{0}};
30+
31+
cl_git_pass(git_oid_fromstr(&entry.id, idstr));
32+
33+
entry.path = mode == GIT_FILEMODE_TREE ? "test_folder" : "test_file";
34+
entry.mode = mode;
35+
36+
if (should_succeed)
37+
cl_git_pass(git_index_add(g_index, &entry));
38+
else
39+
cl_git_fail(git_index_add(g_index, &entry));
40+
}
41+
42+
void test_index_add__invalid_entries_succeeds_by_default(void)
43+
{
44+
/*
45+
* Ensure that there is no validation on ids by default
46+
*/
47+
48+
/* ensure that we can add some actually good entries */
49+
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB);
50+
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB_EXECUTABLE);
51+
test_add_entry(true, valid_blob_id, GIT_FILEMODE_LINK);
52+
53+
/* test that we fail to add some invalid (missing) blobs and trees */
54+
test_add_entry(true, invalid_id, GIT_FILEMODE_BLOB);
55+
test_add_entry(true, invalid_id, GIT_FILEMODE_BLOB_EXECUTABLE);
56+
test_add_entry(true, invalid_id, GIT_FILEMODE_LINK);
57+
58+
/* test that we validate the types of objects */
59+
test_add_entry(true, valid_commit_id, GIT_FILEMODE_BLOB);
60+
test_add_entry(true, valid_tree_id, GIT_FILEMODE_BLOB_EXECUTABLE);
61+
test_add_entry(true, valid_commit_id, GIT_FILEMODE_LINK);
62+
63+
/*
64+
* Ensure that strict object references will fail the `index_add`
65+
*/
66+
67+
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1));
68+
69+
/* ensure that we can add some actually good entries */
70+
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB);
71+
test_add_entry(true, valid_blob_id, GIT_FILEMODE_BLOB_EXECUTABLE);
72+
test_add_entry(true, valid_blob_id, GIT_FILEMODE_LINK);
73+
74+
/* test that we fail to add some invalid (missing) blobs and trees */
75+
test_add_entry(false, invalid_id, GIT_FILEMODE_BLOB);
76+
test_add_entry(false, invalid_id, GIT_FILEMODE_BLOB_EXECUTABLE);
77+
test_add_entry(false, invalid_id, GIT_FILEMODE_LINK);
78+
79+
/* test that we validate the types of objects */
80+
test_add_entry(false, valid_commit_id, GIT_FILEMODE_BLOB);
81+
test_add_entry(false, valid_tree_id, GIT_FILEMODE_BLOB_EXECUTABLE);
82+
test_add_entry(false, valid_commit_id, GIT_FILEMODE_LINK);
83+
}
84+

0 commit comments

Comments
 (0)