list-objects-filter: disable 'sparse:path' filters
authorChristian Couder <christian.couder@gmail.com>
Wed, 29 May 2019 12:44:32 +0000 (14:44 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 29 May 2019 18:05:34 +0000 (11:05 -0700)
If someone wants to use as a filter a sparse file that is in the
repository, something like "--filter=sparse:oid=<ref>:<path>"
already works.

So 'sparse:path' is only interesting if the sparse file is not in
the repository. In this case though the current implementation has
a big security issue, as it makes it possible to ask the server to
read any file, like for example /etc/password, and to explore the
filesystem, as well as individual lines of files.

If someone is interested in using a sparse file that is not in the
repository as a filter, then at the minimum a config option, such
as "uploadpack.sparsePathFilter", should be implemented first to
restrict the directory from which the files specified by
'sparse:path' can be read.

For now though, let's just disable 'sparse:path' filters.

Helped-by: Matthew DeVore <matvore@google.com>
Helped-by: Jeff Hostetler <git@jeffhostetler.com>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/rev-list-options.txt
contrib/completion/git-completion.bash
list-objects-filter-options.c
list-objects-filter-options.h
list-objects-filter.c
t/t5317-pack-objects-filter-objects.sh
t/t6112-rev-list-filters-objects.sh
index ddbc1de43f87539b8be945ebfd42e6562ff097a6..71a1fcc0939f791fe7f0423f15faf458dd0598f5 100644 (file)
@@ -725,9 +725,6 @@ specification contained in the blob (or blob-expression) '<blob-ish>'
 to omit blobs that would not be not required for a sparse checkout on
 the requested refs.
 +
-The form '--filter=sparse:path=<path>' similarly uses a sparse-checkout
-specification contained in <path>.
-+
 The form '--filter=tree:<depth>' omits all blobs and trees whose depth
 from the root tree is >= <depth> (minimum depth if an object is located
 at multiple depths in the commits traversed). <depth>=0 will not include
@@ -737,6 +734,10 @@ tree and blobs which are referenced directly by a commit reachable from
 <commit> or an explicitly-given object. <depth>=2 is like <depth>=1
 while also including trees and blobs one more level removed from an
 explicitly-given commit or tree.
++
+Note that the form '--filter=sparse:path=<path>' that wants to read
+from an arbitrary path on the filesystem has been dropped for security
+reasons.
 
 --no-filter::
        Turn off any previous `--filter=` argument.
index 3eefbabdb12266cd94729bdeacc088785d917967..9f71bcde967bc50915b90eaef72061f8c6a56315 100644 (file)
@@ -1536,7 +1536,7 @@ _git_fetch ()
                return
                ;;
        --filter=*)
-               __gitcomp "blob:none blob:limit= sparse:oid= sparse:path=" "" "${cur##--filter=}"
+               __gitcomp "blob:none blob:limit= sparse:oid=" "" "${cur##--filter=}"
                return
                ;;
        --*)
index c0036f73789d1a6a3ff88a76c3838241e65ca868..a15d0f782923f6bbb0aa9534c80f53c2942e7a79 100644 (file)
@@ -78,9 +78,12 @@ static int gently_parse_list_objects_filter(
                return 0;
 
        } else if (skip_prefix(arg, "sparse:path=", &v0)) {
-               filter_options->choice = LOFC_SPARSE_PATH;
-               filter_options->sparse_path_value = strdup(v0);
-               return 0;
+               if (errbuf) {
+                       strbuf_addstr(
+                               errbuf,
+                               _("sparse:path filters support has been dropped"));
+               }
+               return 1;
        }
        /*
         * Please update _git_fetch() in git-completion.bash when you
@@ -136,7 +139,6 @@ void list_objects_filter_release(
 {
        free(filter_options->filter_spec);
        free(filter_options->sparse_oid_value);
-       free(filter_options->sparse_path_value);
        memset(filter_options, 0, sizeof(*filter_options));
 }
 
index e3adc78ebf74717d3b4e544c5bbb5215d9402a92..c54f0000fbade5608e81345a9c5dbd54137d352d 100644 (file)
@@ -13,7 +13,6 @@ enum list_objects_filter_choice {
        LOFC_BLOB_LIMIT,
        LOFC_TREE_DEPTH,
        LOFC_SPARSE_OID,
-       LOFC_SPARSE_PATH,
        LOFC__COUNT /* must be last */
 };
 
@@ -44,7 +43,6 @@ struct list_objects_filter_options {
         * choice.
         */
        struct object_id *sparse_oid_value;
-       char *sparse_path_value;
        unsigned long blob_limit_value;
        unsigned long tree_exclude_depth;
 };
index ee449de3f77e2b8663d1ae2d43da049f15269249..53f90442c5da992808f09f6d764fcefc44d70ee0 100644 (file)
@@ -478,27 +478,6 @@ static void *filter_sparse_oid__init(
        return d;
 }
 
-static void *filter_sparse_path__init(
-       struct oidset *omitted,
-       struct list_objects_filter_options *filter_options,
-       filter_object_fn *filter_fn,
-       filter_free_fn *filter_free_fn)
-{
-       struct filter_sparse_data *d = xcalloc(1, sizeof(*d));
-       d->omits = omitted;
-       if (add_excludes_from_file_to_list(filter_options->sparse_path_value,
-                                          NULL, 0, &d->el, NULL) < 0)
-               die("could not load filter specification");
-
-       ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc);
-       d->array_frame[d->nr].defval = 0; /* default to include */
-       d->array_frame[d->nr].child_prov_omit = 0;
-
-       *filter_fn = filter_sparse;
-       *filter_free_fn = filter_sparse_free;
-       return d;
-}
-
 typedef void *(*filter_init_fn)(
        struct oidset *omitted,
        struct list_objects_filter_options *filter_options,
@@ -514,7 +493,6 @@ static filter_init_fn s_filters[] = {
        filter_blobs_limit__init,
        filter_trees_depth__init,
        filter_sparse_oid__init,
-       filter_sparse_path__init,
 };
 
 void *list_objects_filter__init(
index 4c0201c34be59715f352ac2e5d1a9422311eedb5..2d2f5d0229ced56b1536e42103dd7b6da66c6d46 100755 (executable)
@@ -277,6 +277,10 @@ test_expect_success 'verify normal and blob:limit packfiles have same commits/tr
 '
 
 # Test sparse:path=<path> filter.
+# !!!!
+# NOTE: sparse:path filter support has been dropped for security reasons,
+# so the tests have been changed to make sure that using it fails.
+# !!!!
 # Use a local file containing a sparse-checkout specification to filter
 # out blobs not required for the corresponding sparse-checkout.  We do not
 # require sparse-checkout to actually be enabled.
@@ -315,73 +319,24 @@ test_expect_success 'verify blob count in normal packfile' '
        test_cmp expected observed
 '
 
-test_expect_success 'verify sparse:path=pattern1' '
-       git -C r3 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
-       awk -f print_2.awk ls_files_result |
-       sort >expected &&
-
-       git -C r3 pack-objects --revs --stdout --filter=sparse:path=../pattern1 >filter.pack <<-EOF &&
+test_expect_success 'verify sparse:path=pattern1 fails' '
+       test_must_fail git -C r3 pack-objects --revs --stdout \
+               --filter=sparse:path=../pattern1 <<-EOF
        HEAD
        EOF
-       git -C r3 index-pack ../filter.pack &&
-
-       git -C r3 verify-pack -v ../filter.pack >verify_result &&
-       grep blob verify_result |
-       awk -f print_1.awk |
-       sort >observed &&
-
-       test_cmp expected observed
-'
-
-test_expect_success 'verify normal and sparse:path=pattern1 packfiles have same commits/trees' '
-       git -C r3 verify-pack -v ../all.pack >verify_result &&
-       grep -E "commit|tree" verify_result |
-       awk -f print_1.awk |
-       sort >expected &&
-
-       git -C r3 verify-pack -v ../filter.pack >verify_result &&
-       grep -E "commit|tree" verify_result |
-       awk -f print_1.awk |
-       sort >observed &&
-
-       test_cmp expected observed
 '
 
-test_expect_success 'verify sparse:path=pattern2' '
-       git -C r3 ls-files -s sparse1 dir1/sparse1 >ls_files_result &&
-       awk -f print_2.awk ls_files_result |
-       sort >expected &&
-
-       git -C r3 pack-objects --revs --stdout --filter=sparse:path=../pattern2 >filter.pack <<-EOF &&
+test_expect_success 'verify sparse:path=pattern2 fails' '
+       test_must_fail git -C r3 pack-objects --revs --stdout \
+               --filter=sparse:path=../pattern2 <<-EOF
        HEAD
        EOF
-       git -C r3 index-pack ../filter.pack &&
-
-       git -C r3 verify-pack -v ../filter.pack >verify_result &&
-       grep blob verify_result |
-       awk -f print_1.awk |
-       sort >observed &&
-
-       test_cmp expected observed
-'
-
-test_expect_success 'verify normal and sparse:path=pattern2 packfiles have same commits/trees' '
-       git -C r3 verify-pack -v ../all.pack >verify_result &&
-       grep -E "commit|tree" verify_result |
-       awk -f print_1.awk |
-       sort >expected &&
-
-       git -C r3 verify-pack -v ../filter.pack >verify_result &&
-       grep -E "commit|tree" verify_result |
-       awk -f print_1.awk |
-       sort >observed &&
-
-       test_cmp expected observed
 '
 
 # Test sparse:oid=<oid-ish> filter.
-# Like sparse:path, but we get the sparse-checkout specification from
-# a blob rather than a file on disk.
+# Use a blob containing a sparse-checkout specification to filter
+# out blobs not required for the corresponding sparse-checkout.  We do not
+# require sparse-checkout to actually be enabled.
 
 test_expect_success 'setup r4' '
        git init r4 &&
index 9c114277196e5c231869dbfe51f88760c40ae0b8..acd7f5ab80d9c8a78c915ec9b868e704237841c5 100755 (executable)
@@ -157,6 +157,10 @@ test_expect_success 'verify blob:limit=1m' '
 '
 
 # Test sparse:path=<path> filter.
+# !!!!
+# NOTE: sparse:path filter support has been dropped for security reasons,
+# so the tests have been changed to make sure that using it fails.
+# !!!!
 # Use a local file containing a sparse-checkout specification to filter
 # out blobs not required for the corresponding sparse-checkout.  We do not
 # require sparse-checkout to actually be enabled.
@@ -176,37 +180,20 @@ test_expect_success 'setup r3' '
        echo sparse1 >pattern2
 '
 
-test_expect_success 'verify sparse:path=pattern1 omits top-level files' '
-       git -C r3 ls-files -s sparse1 sparse2 >ls_files_result &&
-       awk -f print_2.awk ls_files_result |
-       sort >expected &&
-
-       git -C r3 rev-list --quiet --objects --filter-print-omitted \
-               --filter=sparse:path=../pattern1 HEAD >revs &&
-       awk -f print_1.awk revs |
-       sed "s/~//" |
-       sort >observed &&
-
-       test_cmp expected observed
+test_expect_success 'verify sparse:path=pattern1 fails' '
+       test_must_fail git -C r3 rev-list --quiet --objects \
+               --filter-print-omitted --filter=sparse:path=../pattern1 HEAD
 '
 
-test_expect_success 'verify sparse:path=pattern2 omits both sparse2 files' '
-       git -C r3 ls-files -s sparse2 dir1/sparse2 >ls_files_result &&
-       awk -f print_2.awk ls_files_result |
-       sort >expected &&
-
-       git -C r3 rev-list --quiet --objects --filter-print-omitted \
-               --filter=sparse:path=../pattern2 HEAD >revs &&
-       awk -f print_1.awk revs |
-       sed "s/~//" |
-       sort >observed &&
-
-       test_cmp expected observed
+test_expect_success 'verify sparse:path=pattern2 fails' '
+       test_must_fail git -C r3 rev-list --quiet --objects \
+               --filter-print-omitted --filter=sparse:path=../pattern2 HEAD
 '
 
 # Test sparse:oid=<oid-ish> filter.
-# Like sparse:path, but we get the sparse-checkout specification from
-# a blob rather than a file on disk.
+# Use a blob containing a sparse-checkout specification to filter
+# out blobs not required for the corresponding sparse-checkout.  We do not
+# require sparse-checkout to actually be enabled.
 
 test_expect_success 'setup r3 part 2' '
        echo dir1/ >r3/pattern &&