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

Skip to content

Commit 594a5d1

Browse files
committed
Merge pull request libgit2#3619 from ethomson/win32_forbidden
win32: allow us to read indexes with forbidden paths on win32
2 parents 298d1b0 + 318b825 commit 594a5d1

20 files changed

+267
-26
lines changed

src/checkout.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1226,7 +1226,7 @@ static int checkout_verify_paths(
12261226
int action,
12271227
git_diff_delta *delta)
12281228
{
1229-
unsigned int flags = GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT;
1229+
unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
12301230

12311231
if (action & CHECKOUT_ACTION__REMOVE) {
12321232
if (!git_path_isvalid(repo, delta->old_file.path, flags)) {

src/index.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -853,17 +853,31 @@ static void index_entry_adjust_namemask(
853853
entry->flags |= GIT_IDXENTRY_NAMEMASK;
854854
}
855855

856+
/* When `from_workdir` is true, we will validate the paths to avoid placing
857+
* paths that are invalid for the working directory on the current filesystem
858+
* (eg, on Windows, we will disallow `GIT~1`, `AUX`, `COM1`, etc). This
859+
* function will *always* prevent `.git` and directory traversal `../` from
860+
* being added to the index.
861+
*/
856862
static int index_entry_create(
857863
git_index_entry **out,
858864
git_repository *repo,
859-
const char *path)
865+
const char *path,
866+
bool from_workdir)
860867
{
861868
size_t pathlen = strlen(path), alloclen;
862869
struct entry_internal *entry;
870+
unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
871+
872+
/* always reject placing `.git` in the index and directory traversal.
873+
* when requested, disallow platform-specific filenames and upgrade to
874+
* the platform-specific `.git` tests (eg, `git~1`, etc).
875+
*/
876+
if (from_workdir)
877+
path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS;
863878

864-
if (!git_path_isvalid(repo, path,
865-
GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT)) {
866-
giterr_set(GITERR_INDEX, "Invalid path: '%s'", path);
879+
if (!git_path_isvalid(repo, path, path_valid_flags)) {
880+
giterr_set(GITERR_INDEX, "invalid path: '%s'", path);
867881
return -1;
868882
}
869883

@@ -895,7 +909,7 @@ static int index_entry_init(
895909
"Could not initialize index entry. "
896910
"Index is not backed up by an existing repository.");
897911

898-
if (index_entry_create(&entry, INDEX_OWNER(index), rel_path) < 0)
912+
if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, true) < 0)
899913
return -1;
900914

901915
/* write the blob to disk and get the oid and stat info */
@@ -975,7 +989,7 @@ static int index_entry_dup(
975989
git_index *index,
976990
const git_index_entry *src)
977991
{
978-
if (index_entry_create(out, INDEX_OWNER(index), src->path) < 0)
992+
if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0)
979993
return -1;
980994

981995
index_entry_cpy(*out, src);
@@ -997,7 +1011,7 @@ static int index_entry_dup_nocache(
9971011
git_index *index,
9981012
const git_index_entry *src)
9991013
{
1000-
if (index_entry_create(out, INDEX_OWNER(index), src->path) < 0)
1014+
if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0)
10011015
return -1;
10021016

10031017
index_entry_cpy_nocache(*out, src);
@@ -1402,7 +1416,7 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const
14021416
struct stat st;
14031417
int error;
14041418

1405-
if (index_entry_create(&entry, INDEX_OWNER(index), path) < 0)
1419+
if (index_entry_create(&entry, INDEX_OWNER(index), path, true) < 0)
14061420
return -1;
14071421

14081422
if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
@@ -2788,7 +2802,7 @@ static int read_tree_cb(
27882802
if (git_buf_joinpath(&path, root, tentry->filename) < 0)
27892803
return -1;
27902804

2791-
if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr) < 0)
2805+
if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, false) < 0)
27922806
return -1;
27932807

27942808
entry->mode = tentry->attr;

src/iterator.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ static bool tree_iterator__pop_frame(tree_iterator *ti, bool final)
558558
{
559559
tree_iterator_frame *tf = ti->head;
560560

561+
assert(tf);
562+
561563
if (!tf->up)
562564
return false;
563565

@@ -581,6 +583,8 @@ static void tree_iterator__pop_all(tree_iterator *ti, bool to_end, bool final)
581583
while (tree_iterator__pop_frame(ti, final)) /* pop to root */;
582584

583585
if (!final) {
586+
assert(ti->head);
587+
584588
ti->head->current = to_end ? ti->head->n_entries : 0;
585589
ti->path_ambiguities = 0;
586590
git_buf_clear(&ti->path);
@@ -773,10 +777,12 @@ static void tree_iterator__free(git_iterator *self)
773777
{
774778
tree_iterator *ti = (tree_iterator *)self;
775779

776-
tree_iterator__pop_all(ti, true, false);
780+
if (ti->head) {
781+
tree_iterator__pop_all(ti, true, false);
782+
git_tree_free(ti->head->entries[0]->tree);
783+
git__free(ti->head);
784+
}
777785

778-
git_tree_free(ti->head->entries[0]->tree);
779-
git__free(ti->head);
780786
git_pool_clear(&ti->pool);
781787
git_buf_free(&ti->path);
782788
}

src/path.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1630,9 +1630,12 @@ static bool verify_component(
16301630
!verify_dotgit_ntfs(repo, component, len))
16311631
return false;
16321632

1633+
/* don't bother rerunning the `.git` test if we ran the HFS or NTFS
1634+
* specific tests, they would have already rejected `.git`.
1635+
*/
16331636
if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 &&
16341637
(flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 &&
1635-
(flags & GIT_PATH_REJECT_DOT_GIT) &&
1638+
(flags & GIT_PATH_REJECT_DOT_GIT_LITERAL) &&
16361639
len == 4 &&
16371640
component[0] == '.' &&
16381641
(component[1] == 'g' || component[1] == 'G') &&
@@ -1649,6 +1652,8 @@ GIT_INLINE(unsigned int) dotgit_flags(
16491652
{
16501653
int protectHFS = 0, protectNTFS = 0;
16511654

1655+
flags |= GIT_PATH_REJECT_DOT_GIT_LITERAL;
1656+
16521657
#ifdef __APPLE__
16531658
protectHFS = 1;
16541659
#endif

src/path.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -564,15 +564,16 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
564564
#define GIT_PATH_REJECT_TRAILING_COLON (1 << 6)
565565
#define GIT_PATH_REJECT_DOS_PATHS (1 << 7)
566566
#define GIT_PATH_REJECT_NT_CHARS (1 << 8)
567-
#define GIT_PATH_REJECT_DOT_GIT_HFS (1 << 9)
568-
#define GIT_PATH_REJECT_DOT_GIT_NTFS (1 << 10)
567+
#define GIT_PATH_REJECT_DOT_GIT_LITERAL (1 << 9)
568+
#define GIT_PATH_REJECT_DOT_GIT_HFS (1 << 10)
569+
#define GIT_PATH_REJECT_DOT_GIT_NTFS (1 << 11)
569570

570571
/* Default path safety for writing files to disk: since we use the
571572
* Win32 "File Namespace" APIs ("\\?\") we need to protect from
572573
* paths that the normal Win32 APIs would not write.
573574
*/
574575
#ifdef GIT_WIN32
575-
# define GIT_PATH_REJECT_DEFAULTS \
576+
# define GIT_PATH_REJECT_FILESYSTEM_DEFAULTS \
576577
GIT_PATH_REJECT_TRAVERSAL | \
577578
GIT_PATH_REJECT_BACKSLASH | \
578579
GIT_PATH_REJECT_TRAILING_DOT | \
@@ -581,9 +582,18 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
581582
GIT_PATH_REJECT_DOS_PATHS | \
582583
GIT_PATH_REJECT_NT_CHARS
583584
#else
584-
# define GIT_PATH_REJECT_DEFAULTS GIT_PATH_REJECT_TRAVERSAL
585+
# define GIT_PATH_REJECT_FILESYSTEM_DEFAULTS \
586+
GIT_PATH_REJECT_TRAVERSAL
585587
#endif
586588

589+
/* Paths that should never be written into the working directory. */
590+
#define GIT_PATH_REJECT_WORKDIR_DEFAULTS \
591+
GIT_PATH_REJECT_FILESYSTEM_DEFAULTS | GIT_PATH_REJECT_DOT_GIT
592+
593+
/* Paths that should never be written to the index. */
594+
#define GIT_PATH_REJECT_INDEX_DEFAULTS \
595+
GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT
596+
587597
/*
588598
* Determine whether a path is a valid git path or not - this must not contain
589599
* a '.' or '..' component, or a component that is ".git" (in any case).

src/refdb_fs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
717717

718718
assert(file && backend && name);
719719

720-
if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_DEFAULTS)) {
720+
if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
721721
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", name);
722722
return GIT_EINVALIDSPEC;
723723
}
@@ -1672,7 +1672,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
16721672

16731673
repo = backend->repo;
16741674

1675-
if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_DEFAULTS)) {
1675+
if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
16761676
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", refname);
16771677
return GIT_EINVALIDSPEC;
16781678
}

tests/path/core.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ void test_path_core__isvalid_dot_git(void)
105105
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0));
106106
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0));
107107

108-
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT));
109-
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT));
110-
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT));
111-
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT));
112-
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT));
113-
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT));
108+
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_LITERAL));
109+
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT_LITERAL));
110+
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT_LITERAL));
111+
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL));
112+
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL));
113+
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT_LITERAL));
114114

115115
cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0));
116116
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ref: refs/heads/master
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[core]
2+
repositoryformatversion = 0
3+
filemode = true
4+
bare = false
5+
logallrefupdates = true
6+
ignorecase = true
7+
precomposeunicode = true
577 Bytes
Binary file not shown.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# git ls-files --others --exclude-from=.git/info/exclude
2+
# Lines that start with '#' are comments.
3+
# For a project mostly in C, the following would be a good set of
4+
# exclude patterns (uncomment them if you want to use them):
5+
# *.[oa]
6+
# *~

tests/resources/win32-forbidden/.gitted/objects/34/96991d72d500af36edef68bbfcccd1661d88db

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
x���
2+
!�[�w����hӢ}/�8�B*8N�~�@gu��՜S� ͡7�a�
3+
�f�2��"se.�%��Q ��ؽ��຾m[�k�j���m�G�q_N��3LBJŔFG:B���� �����VRO� ͿҖj!��=�
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
x�A
2+
� �֝�/k�.� ]`����h޾�"=� ˕�e*� ��U��+��M�%���O4�c�˱���

tests/resources/win32-forbidden/.gitted/objects/ea/c7621a652e5261ef1c1d3e7ae31b0d84fcbaba

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
x��M
2+
B!F��;BoW}BD��ۀ��
3+
>_m?�Bg�q���VJ �=F�����dJT�qD�d�B��N�'��6R�p��S+k�p�����G����rAR*Tz!�� �vVG���n5�l_��;��U�>H
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3496991d72d500af36edef68bbfcccd1661d88db

0 commit comments

Comments
 (0)