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

Skip to content

Commit 9db49cc

Browse files
author
Edward Thomson
committed
checkout: disallow bad paths on win32
Disallow: 1. paths with trailing dot 2. paths with trailing space 3. paths with trailing colon 4. paths that are 8.3 short names of .git folders ("GIT~1") 5. paths that are reserved path names (COM1, LPT1, etc). 6. paths with reserved DOS characters (colons, asterisks, etc) These paths would (without \\?\ syntax) be elided to other paths - for example, ".git." would be written as ".git". As a result, writing these paths literally (using \\?\ syntax) makes them hard to operate with from the shell, Windows Explorer or other tools. Disallow these.
1 parent a4bb75a commit 9db49cc

File tree

94 files changed

+898
-90
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+898
-90
lines changed

src/checkout.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,30 @@ static int checkout_get_conflicts(
11031103
return error;
11041104
}
11051105

1106+
static int checkout_verify_paths(
1107+
git_repository *repo,
1108+
int action,
1109+
git_diff_delta *delta)
1110+
{
1111+
unsigned int flags = GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT;
1112+
1113+
if (action & CHECKOUT_ACTION__REMOVE) {
1114+
if (!git_path_isvalid(repo, delta->old_file.path, flags)) {
1115+
giterr_set(GITERR_CHECKOUT, "Cannot remove invalid path '%s'", delta->old_file.path);
1116+
return -1;
1117+
}
1118+
}
1119+
1120+
if (action & ~CHECKOUT_ACTION__REMOVE) {
1121+
if (!git_path_isvalid(repo, delta->new_file.path, flags)) {
1122+
giterr_set(GITERR_CHECKOUT, "Cannot checkout to invalid path '%s'", delta->old_file.path);
1123+
return -1;
1124+
}
1125+
}
1126+
1127+
return 0;
1128+
}
1129+
11061130
static int checkout_get_actions(
11071131
uint32_t **actions_ptr,
11081132
size_t **counts_ptr,
@@ -1136,7 +1160,9 @@ static int checkout_get_actions(
11361160
}
11371161

11381162
git_vector_foreach(deltas, i, delta) {
1139-
error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec);
1163+
if ((error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec)) == 0)
1164+
error = checkout_verify_paths(data->repo, act, delta);
1165+
11401166
if (error != 0)
11411167
goto fail;
11421168

src/index.c

Lines changed: 31 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -762,86 +762,19 @@ void git_index_entry__init_from_stat(
762762
entry->file_size = st->st_size;
763763
}
764764

765-
/*
766-
* We fundamentally don't like some paths: we don't want
767-
* dot or dot-dot anywhere, and for obvious reasons don't
768-
* want to recurse into ".git" either.
769-
*
770-
* Also, we don't want double slashes or slashes at the
771-
* end that can make pathnames ambiguous.
772-
*/
773-
static int verify_dotfile(const char *rest)
774-
{
775-
/*
776-
* The first character was '.', but that
777-
* has already been discarded, we now test
778-
* the rest.
779-
*/
780-
781-
/* "." is not allowed */
782-
if (*rest == '\0' || *rest == '/')
783-
return -1;
784-
785-
switch (*rest) {
786-
/*
787-
* ".git" followed by NUL or slash is bad. This
788-
* shares the path end test with the ".." case.
789-
*/
790-
case 'g':
791-
case 'G':
792-
if (rest[1] != 'i' && rest[1] != 'I')
793-
break;
794-
if (rest[2] != 't' && rest[2] != 'T')
795-
break;
796-
rest += 2;
797-
/* fallthrough */
798-
case '.':
799-
if (rest[1] == '\0' || rest[1] == '/')
800-
return -1;
801-
}
802-
return 0;
803-
}
804-
805-
static int verify_component(char c, const char *rest)
806-
{
807-
if ((c == '.' && verify_dotfile(rest)) < 0 || c == '/' || c == '\0') {
808-
giterr_set(GITERR_INDEX, "Invalid path component in index: '%c%s'", c, rest);
809-
return -1;
810-
}
811-
return 0;
812-
}
813-
814-
static int verify_path(const char *path)
815-
{
816-
char c;
817-
818-
/* TODO: should we check this? */
819-
/*
820-
if (has_dos_drive_prefix(path))
821-
return -1;
822-
*/
823-
824-
c = *path++;
825-
if (verify_component(c, path) < 0)
826-
return -1;
827-
828-
while ((c = *path++) != '\0') {
829-
if (c == '/') {
830-
c = *path++;
831-
if (verify_component(c, path) < 0)
832-
return -1;
833-
}
834-
}
835-
return 0;
836-
}
837-
838-
static int index_entry_create(git_index_entry **out, const char *path)
765+
static int index_entry_create(
766+
git_index_entry **out,
767+
git_repository *repo,
768+
const char *path)
839769
{
840770
size_t pathlen = strlen(path);
841771
struct entry_internal *entry;
842772

843-
if (verify_path(path) < 0)
773+
if (!git_path_isvalid(repo, path,
774+
GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT)) {
775+
giterr_set(GITERR_INDEX, "Invalid path: '%s'", path);
844776
return -1;
777+
}
845778

846779
entry = git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1);
847780
GITERR_CHECK_ALLOC(entry);
@@ -855,7 +788,9 @@ static int index_entry_create(git_index_entry **out, const char *path)
855788
}
856789

857790
static int index_entry_init(
858-
git_index_entry **entry_out, git_index *index, const char *rel_path)
791+
git_index_entry **entry_out,
792+
git_index *index,
793+
const char *rel_path)
859794
{
860795
int error = 0;
861796
git_index_entry *entry = NULL;
@@ -867,7 +802,7 @@ static int index_entry_init(
867802
"Could not initialize index entry. "
868803
"Index is not backed up by an existing repository.");
869804

870-
if (index_entry_create(&entry, rel_path) < 0)
805+
if (index_entry_create(&entry, INDEX_OWNER(index), rel_path) < 0)
871806
return -1;
872807

873808
/* write the blob to disk and get the oid and stat info */
@@ -933,7 +868,10 @@ static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src)
933868
tgt->path = tgt_path; /* reset to existing path data */
934869
}
935870

936-
static int index_entry_dup(git_index_entry **out, const git_index_entry *src)
871+
static int index_entry_dup(
872+
git_index_entry **out,
873+
git_repository *repo,
874+
const git_index_entry *src)
937875
{
938876
git_index_entry *entry;
939877

@@ -942,7 +880,7 @@ static int index_entry_dup(git_index_entry **out, const git_index_entry *src)
942880
return 0;
943881
}
944882

945-
if (index_entry_create(&entry, src->path) < 0)
883+
if (index_entry_create(&entry, repo, src->path) < 0)
946884
return -1;
947885

948886
index_entry_cpy(entry, src);
@@ -1211,7 +1149,7 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
12111149
return -1;
12121150
}
12131151

1214-
if ((ret = index_entry_dup(&entry, source_entry)) < 0 ||
1152+
if ((ret = index_entry_dup(&entry, INDEX_OWNER(index), source_entry)) < 0 ||
12151153
(ret = index_insert(index, &entry, 1)) < 0)
12161154
return ret;
12171155

@@ -1331,9 +1269,9 @@ int git_index_conflict_add(git_index *index,
13311269

13321270
assert (index);
13331271

1334-
if ((ret = index_entry_dup(&entries[0], ancestor_entry)) < 0 ||
1335-
(ret = index_entry_dup(&entries[1], our_entry)) < 0 ||
1336-
(ret = index_entry_dup(&entries[2], their_entry)) < 0)
1272+
if ((ret = index_entry_dup(&entries[0], INDEX_OWNER(index), ancestor_entry)) < 0 ||
1273+
(ret = index_entry_dup(&entries[1], INDEX_OWNER(index), our_entry)) < 0 ||
1274+
(ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
13371275
goto on_error;
13381276

13391277
for (i = 0; i < 3; i++) {
@@ -1850,7 +1788,10 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
18501788
}
18511789

18521790
static size_t read_entry(
1853-
git_index_entry **out, const void *buffer, size_t buffer_size)
1791+
git_index_entry **out,
1792+
git_index *index,
1793+
const void *buffer,
1794+
size_t buffer_size)
18541795
{
18551796
size_t path_length, entry_size;
18561797
const char *path_ptr;
@@ -1914,7 +1855,7 @@ static size_t read_entry(
19141855

19151856
entry.path = (char *)path_ptr;
19161857

1917-
if (index_entry_dup(out, &entry) < 0)
1858+
if (index_entry_dup(out, INDEX_OWNER(index), &entry) < 0)
19181859
return 0;
19191860

19201861
return entry_size;
@@ -2015,7 +1956,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
20151956
/* Parse all the entries */
20161957
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
20171958
git_index_entry *entry;
2018-
size_t entry_size = read_entry(&entry, buffer, buffer_size);
1959+
size_t entry_size = read_entry(&entry, index, buffer, buffer_size);
20191960

20201961
/* 0 bytes read means an object corruption */
20211962
if (entry_size == 0) {
@@ -2376,6 +2317,7 @@ int git_index_entry_stage(const git_index_entry *entry)
23762317
}
23772318

23782319
typedef struct read_tree_data {
2320+
git_index *index;
23792321
git_vector *old_entries;
23802322
git_vector *new_entries;
23812323
git_vector_cmp entry_cmp;
@@ -2396,7 +2338,7 @@ static int read_tree_cb(
23962338
if (git_buf_joinpath(&path, root, tentry->filename) < 0)
23972339
return -1;
23982340

2399-
if (index_entry_create(&entry, path.ptr) < 0)
2341+
if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr) < 0)
24002342
return -1;
24012343

24022344
entry->mode = tentry->attr;
@@ -2437,6 +2379,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
24372379

24382380
git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
24392381

2382+
data.index = index;
24402383
data.old_entries = &index->entries;
24412384
data.new_entries = &entries;
24422385
data.entry_cmp = index->entries_search;
@@ -2556,7 +2499,7 @@ int git_index_add_all(
25562499
break;
25572500

25582501
/* make the new entry to insert */
2559-
if ((error = index_entry_dup(&entry, wd)) < 0)
2502+
if ((error = index_entry_dup(&entry, INDEX_OWNER(index), wd)) < 0)
25602503
break;
25612504

25622505
entry->id = blobid;

0 commit comments

Comments
 (0)