Hello community,

here is the log from the commit of package git for openSUSE:Factory checked in 
at 2018-06-03 12:31:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/git (Old)
 and      /work/SRC/openSUSE:Factory/.git.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "git"

Sun Jun  3 12:31:12 2018 rev:220 rq:613093 version:2.17.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/git/git.changes  2018-05-25 21:37:44.667034750 
+0200
+++ /work/SRC/openSUSE:Factory/.git.new/git.changes     2018-06-03 
12:31:19.322916175 +0200
@@ -1,0 +2,18 @@
+Tue May 29 23:11:45 UTC 2018 - avin...@opensuse.org
+
+- git 2.17.1
+ * Submodule "names" come from the untrusted .gitmodules file, but
+   we blindly append them to $GIT_DIR/modules to create our on-disk
+   repo paths. This means you can do bad things by putting "../"
+   into the name. We now enforce some rules for submodule names
+   which will cause Git to ignore these malicious names
+   (CVE-2018-11235, bsc#1095219)
+ * It was possible to trick the code that sanity-checks paths on
+   NTFS into reading random piece of memory
+   (CVE-2018-11233, bsc#1095218)
+ * Support on the server side to reject pushes to repositories
+   that attempt to create such problematic .gitmodules file etc.
+   as tracked contents, to help hosting sites protect their
+   customers by preventing malicious contents from spreading.
+
+-------------------------------------------------------------------

Old:
----
  git-2.17.0.tar.sign
  git-2.17.0.tar.xz

New:
----
  git-2.17.1.tar.sign
  git-2.17.1.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ git.spec ++++++
--- /var/tmp/diff_new_pack.RwEJut/_old  2018-06-03 12:31:20.898858480 +0200
+++ /var/tmp/diff_new_pack.RwEJut/_new  2018-06-03 12:31:20.902858333 +0200
@@ -35,7 +35,7 @@
 %bcond_without docs
 
 Name:           git
-Version:        2.17.0
+Version:        2.17.1
 Release:        0
 Summary:        Fast, scalable, distributed revision control system
 License:        GPL-2.0-only

++++++ git-2.17.0.tar.xz -> git-2.17.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/Documentation/RelNotes/2.13.7.txt 
new/git-2.17.1/Documentation/RelNotes/2.13.7.txt
--- old/git-2.17.0/Documentation/RelNotes/2.13.7.txt    1970-01-01 
01:00:00.000000000 +0100
+++ new/git-2.17.1/Documentation/RelNotes/2.13.7.txt    2018-05-29 
10:14:06.000000000 +0200
@@ -0,0 +1,20 @@
+Git v2.13.7 Release Notes
+=========================
+
+Fixes since v2.13.6
+-------------------
+
+ * Submodule "names" come from the untrusted .gitmodules file, but we
+   blindly append them to $GIT_DIR/modules to create our on-disk repo
+   paths. This means you can do bad things by putting "../" into the
+   name. We now enforce some rules for submodule names which will cause
+   Git to ignore these malicious names (CVE-2018-11235).
+
+   Credit for finding this vulnerability and the proof of concept from
+   which the test script was adapted goes to Etienne Stalmans.
+
+ * It was possible to trick the code that sanity-checks paths on NTFS
+   into reading random piece of memory (CVE-2018-11233).
+
+Credit for fixing for these bugs goes to Jeff King, Johannes
+Schindelin and others.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/Documentation/RelNotes/2.14.4.txt 
new/git-2.17.1/Documentation/RelNotes/2.14.4.txt
--- old/git-2.17.0/Documentation/RelNotes/2.14.4.txt    1970-01-01 
01:00:00.000000000 +0100
+++ new/git-2.17.1/Documentation/RelNotes/2.14.4.txt    2018-05-29 
10:14:06.000000000 +0200
@@ -0,0 +1,5 @@
+Git v2.14.4 Release Notes
+=========================
+
+This release is to forward-port the fixes made in the v2.13.7 version
+of Git.  See its release notes for details.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/Documentation/RelNotes/2.15.2.txt 
new/git-2.17.1/Documentation/RelNotes/2.15.2.txt
--- old/git-2.17.0/Documentation/RelNotes/2.15.2.txt    2018-04-02 
19:44:04.000000000 +0200
+++ new/git-2.17.1/Documentation/RelNotes/2.15.2.txt    2018-05-29 
10:14:06.000000000 +0200
@@ -43,5 +43,8 @@
  * Clarify and enhance documentation for "merge-base --fork-point", as
    it was clear what it computed but not why/what for.
 
+ * This release also contains the fixes made in the v2.13.7 version of
+   Git.  See its release notes for details.
+
 
 Also contains various documentation updates and code clean-ups.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/Documentation/RelNotes/2.16.4.txt 
new/git-2.17.1/Documentation/RelNotes/2.16.4.txt
--- old/git-2.17.0/Documentation/RelNotes/2.16.4.txt    1970-01-01 
01:00:00.000000000 +0100
+++ new/git-2.17.1/Documentation/RelNotes/2.16.4.txt    2018-05-29 
10:14:06.000000000 +0200
@@ -0,0 +1,5 @@
+Git v2.16.4 Release Notes
+=========================
+
+This release is to forward-port the fixes made in the v2.13.7 version
+of Git.  See its release notes for details.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/Documentation/RelNotes/2.17.1.txt 
new/git-2.17.1/Documentation/RelNotes/2.17.1.txt
--- old/git-2.17.0/Documentation/RelNotes/2.17.1.txt    1970-01-01 
01:00:00.000000000 +0100
+++ new/git-2.17.1/Documentation/RelNotes/2.17.1.txt    2018-05-29 
10:14:06.000000000 +0200
@@ -0,0 +1,16 @@
+Git v2.17.1 Release Notes
+=========================
+
+Fixes since v2.17
+-----------------
+
+ * This release contains the same fixes made in the v2.13.7 version of
+   Git, covering CVE-2018-11233 and 11235, and forward-ported to
+   v2.14.4, v2.15.2 and v2.16.4 releases.  See release notes to
+   v2.13.7 for details.
+
+ * In addition to the above fixes, this release has support on the
+   server side to reject pushes to repositories that attempt to create
+   such problematic .gitmodules file etc. as tracked contents, to help
+   hosting sites protect their customers by preventing malicious
+   contents from spreading.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/GIT-VERSION-GEN 
new/git-2.17.1/GIT-VERSION-GEN
--- old/git-2.17.0/GIT-VERSION-GEN      2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/GIT-VERSION-GEN      2018-05-29 10:14:06.000000000 +0200
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.17.0
+DEF_VER=v2.17.1
 
 LF='
 '
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/RelNotes new/git-2.17.1/RelNotes
--- old/git-2.17.0/RelNotes     2018-06-03 12:31:22.734791267 +0200
+++ new/git-2.17.1/RelNotes     2018-06-03 12:31:22.810788485 +0200
@@ -1 +1 @@
-symbolic link to Documentation/RelNotes/2.17.0.txt
+symbolic link to Documentation/RelNotes/2.17.1.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/apply.c new/git-2.17.1/apply.c
--- old/git-2.17.0/apply.c      2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/apply.c      2018-05-29 10:14:06.000000000 +0200
@@ -3860,9 +3860,9 @@
        if (!patch->is_delete)
                new_name = patch->new_name;
 
-       if (old_name && !verify_path(old_name))
+       if (old_name && !verify_path(old_name, patch->old_mode))
                return error(_("invalid path '%s'"), old_name);
-       if (new_name && !verify_path(new_name))
+       if (new_name && !verify_path(new_name, patch->new_mode))
                return error(_("invalid path '%s'"), new_name);
        return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/builtin/fsck.c 
new/git-2.17.1/builtin/fsck.c
--- old/git-2.17.0/builtin/fsck.c       2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/builtin/fsck.c       2018-05-29 10:14:06.000000000 +0200
@@ -337,7 +337,7 @@
        }
 }
 
-static int fsck_obj(struct object *obj)
+static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
 {
        int err;
 
@@ -351,7 +351,7 @@
 
        if (fsck_walk(obj, NULL, &fsck_obj_options))
                objerror(obj, "broken links");
-       err = fsck_object(obj, NULL, 0, &fsck_obj_options);
+       err = fsck_object(obj, buffer, size, &fsck_obj_options);
        if (err)
                goto out;
 
@@ -396,7 +396,7 @@
        }
        obj->flags &= ~(REACHABLE | SEEN);
        obj->flags |= HAS_OBJ;
-       return fsck_obj(obj);
+       return fsck_obj(obj, buffer, size);
 }
 
 static int default_refs;
@@ -504,44 +504,42 @@
        }
 }
 
-static struct object *parse_loose_object(const struct object_id *oid,
-                                        const char *path)
+static int fsck_loose(const struct object_id *oid, const char *path, void 
*data)
 {
        struct object *obj;
-       void *contents;
        enum object_type type;
        unsigned long size;
+       void *contents;
        int eaten;
 
-       if (read_loose_object(path, oid->hash, &type, &size, &contents) < 0)
-               return NULL;
+       if (read_loose_object(path, oid->hash, &type, &size, &contents) < 0) {
+               errors_found |= ERROR_OBJECT;
+               error("%s: object corrupt or missing: %s",
+                     oid_to_hex(oid), path);
+               return 0; /* keep checking other objects */
+       }
 
        if (!contents && type != OBJ_BLOB)
-               die("BUG: read_loose_object streamed a non-blob");
+               BUG("read_loose_object streamed a non-blob");
 
        obj = parse_object_buffer(oid, type, size, contents, &eaten);
-
-       if (!eaten)
-               free(contents);
-       return obj;
-}
-
-static int fsck_loose(const struct object_id *oid, const char *path, void 
*data)
-{
-       struct object *obj = parse_loose_object(oid, path);
-
        if (!obj) {
                errors_found |= ERROR_OBJECT;
-               error("%s: object corrupt or missing: %s",
+               error("%s: object could not be parsed: %s",
                      oid_to_hex(oid), path);
+               if (!eaten)
+                       free(contents);
                return 0; /* keep checking other objects */
        }
 
        obj->flags &= ~(REACHABLE | SEEN);
        obj->flags |= HAS_OBJ;
-       if (fsck_obj(obj))
+       if (fsck_obj(obj, contents, size))
                errors_found |= ERROR_OBJECT;
-       return 0;
+
+       if (!eaten)
+               free(contents);
+       return 0; /* keep checking other objects, even if we saw an error */
 }
 
 static int fsck_cruft(const char *basename, const char *path, void *data)
@@ -750,6 +748,9 @@
                        }
                        stop_progress(&progress);
                }
+
+               if (fsck_finish(&fsck_obj_options))
+                       errors_found |= ERROR_OBJECT;
        }
 
        for (i = 0; i < argc; i++) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/builtin/index-pack.c 
new/git-2.17.1/builtin/index-pack.c
--- old/git-2.17.0/builtin/index-pack.c 2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/builtin/index-pack.c 2018-05-29 10:14:06.000000000 +0200
@@ -836,6 +836,9 @@
                                blob->object.flags |= FLAG_CHECKED;
                        else
                                die(_("invalid blob object %s"), 
oid_to_hex(oid));
+                       if (do_fsck_object &&
+                           fsck_object(&blob->object, (void *)data, size, 
&fsck_options))
+                               die(_("fsck error in packed object"));
                } else {
                        struct object *obj;
                        int eaten;
@@ -853,7 +856,7 @@
                                die(_("invalid %s"), type_name(type));
                        if (do_fsck_object &&
                            fsck_object(obj, buf, size, &fsck_options))
-                               die(_("Error in object"));
+                               die(_("fsck error in packed object"));
                        if (strict && fsck_walk(obj, NULL, &fsck_options))
                                die(_("Not all child objects of %s are 
reachable"), oid_to_hex(&obj->oid));
 
@@ -1477,6 +1480,9 @@
        } else
                chmod(final_index_name, 0444);
 
+       if (do_fsck_object)
+               add_packed_git(final_index_name, strlen(final_index_name), 0);
+
        if (!from_stdin) {
                printf("%s\n", sha1_to_hex(hash));
        } else {
@@ -1818,6 +1824,10 @@
                      pack_hash);
        else
                close(input_fd);
+
+       if (do_fsck_object && fsck_finish(&fsck_options))
+               die(_("fsck error in pack objects"));
+
        free(objects);
        strbuf_release(&index_name_buf);
        if (pack_name == NULL)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/builtin/submodule--helper.c 
new/git-2.17.1/builtin/submodule--helper.c
--- old/git-2.17.0/builtin/submodule--helper.c  2018-04-02 19:44:04.000000000 
+0200
+++ new/git-2.17.1/builtin/submodule--helper.c  2018-05-29 10:14:06.000000000 
+0200
@@ -1817,6 +1817,29 @@
        return !is_submodule_active(the_repository, argv[1]);
 }
 
+/*
+ * Exit non-zero if any of the submodule names given on the command line is
+ * invalid. If no names are given, filter stdin to print only valid names
+ * (which is primarily intended for testing).
+ */
+static int check_name(int argc, const char **argv, const char *prefix)
+{
+       if (argc > 1) {
+               while (*++argv) {
+                       if (check_submodule_name(*argv) < 0)
+                               return 1;
+               }
+       } else {
+               struct strbuf buf = STRBUF_INIT;
+               while (strbuf_getline(&buf, stdin) != EOF) {
+                       if (!check_submodule_name(buf.buf))
+                               printf("%s\n", buf.buf);
+               }
+               strbuf_release(&buf);
+       }
+       return 0;
+}
+
 #define SUPPORT_SUPER_PREFIX (1<<0)
 
 struct cmd_struct {
@@ -1842,6 +1865,7 @@
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
        {"is-active", is_active, 0},
+       {"check-name", check_name, 0},
 };
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/builtin/unpack-objects.c 
new/git-2.17.1/builtin/unpack-objects.c
--- old/git-2.17.0/builtin/unpack-objects.c     2018-04-02 19:44:04.000000000 
+0200
+++ new/git-2.17.1/builtin/unpack-objects.c     2018-05-29 10:14:06.000000000 
+0200
@@ -210,7 +210,7 @@
        if (!obj_buf)
                die("Whoops! Cannot find object '%s'", oid_to_hex(&obj->oid));
        if (fsck_object(obj, obj_buf->buffer, obj_buf->size, &fsck_options))
-               die("Error in object");
+               die("fsck error in packed object");
        fsck_options.walk = check_object;
        if (fsck_walk(obj, NULL, &fsck_options))
                die("Error on reachable objects of %s", oid_to_hex(&obj->oid));
@@ -572,8 +572,11 @@
        unpack_all();
        the_hash_algo->update_fn(&ctx, buffer, offset);
        the_hash_algo->final_fn(oid.hash, &ctx);
-       if (strict)
+       if (strict) {
                write_rest();
+               if (fsck_finish(&fsck_options))
+                       die(_("fsck error in pack objects"));
+       }
        if (hashcmp(fill(the_hash_algo->rawsz), oid.hash))
                die("final sha1 did not match");
        use(the_hash_algo->rawsz);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/builtin/update-index.c 
new/git-2.17.1/builtin/update-index.c
--- old/git-2.17.0/builtin/update-index.c       2018-04-02 19:44:04.000000000 
+0200
+++ new/git-2.17.1/builtin/update-index.c       2018-05-29 10:14:06.000000000 
+0200
@@ -364,10 +364,9 @@
        return error("%s: is a directory - add files inside instead", path);
 }
 
-static int process_path(const char *path)
+static int process_path(const char *path, struct stat *st, int stat_errno)
 {
        int pos, len;
-       struct stat st;
        const struct cache_entry *ce;
 
        len = strlen(path);
@@ -391,13 +390,13 @@
         * First things first: get the stat information, to decide
         * what to do about the pathname!
         */
-       if (lstat(path, &st) < 0)
-               return process_lstat_error(path, errno);
+       if (stat_errno)
+               return process_lstat_error(path, stat_errno);
 
-       if (S_ISDIR(st.st_mode))
-               return process_directory(path, len, &st);
+       if (S_ISDIR(st->st_mode))
+               return process_directory(path, len, st);
 
-       return add_one_path(ce, path, len, &st);
+       return add_one_path(ce, path, len, st);
 }
 
 static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
@@ -406,7 +405,7 @@
        int size, len, option;
        struct cache_entry *ce;
 
-       if (!verify_path(path))
+       if (!verify_path(path, mode))
                return error("Invalid path '%s'", path);
 
        len = strlen(path);
@@ -449,7 +448,18 @@
 
 static void update_one(const char *path)
 {
-       if (!verify_path(path)) {
+       int stat_errno = 0;
+       struct stat st;
+
+       if (mark_valid_only || mark_skip_worktree_only || force_remove ||
+           mark_fsmonitor_only)
+               st.st_mode = 0;
+       else if (lstat(path, &st) < 0) {
+               st.st_mode = 0;
+               stat_errno = errno;
+       } /* else stat is valid */
+
+       if (!verify_path(path, st.st_mode)) {
                fprintf(stderr, "Ignoring path %s\n", path);
                return;
        }
@@ -475,7 +485,7 @@
                report("remove '%s'", path);
                return;
        }
-       if (process_path(path))
+       if (process_path(path, &st, stat_errno))
                die("Unable to process path %s", path);
        report("add '%s'", path);
 }
@@ -545,7 +555,7 @@
                        path_name = uq.buf;
                }
 
-               if (!verify_path(path_name)) {
+               if (!verify_path(path_name, mode)) {
                        fprintf(stderr, "Ignoring path %s\n", path_name);
                        continue;
                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/cache.h new/git-2.17.1/cache.h
--- old/git-2.17.0/cache.h      2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/cache.h      2018-05-29 10:14:06.000000000 +0200
@@ -634,7 +634,7 @@
  */
 extern int index_has_changes(struct strbuf *sb);
 
-extern int verify_path(const char *path);
+extern int verify_path(const char *path, unsigned mode);
 extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
 extern int index_dir_exists(struct index_state *istate, const char *name, int 
namelen);
 extern void adjust_dirname_case(struct index_state *istate, char *name);
@@ -1165,7 +1165,15 @@
 int longest_ancestor_length(const char *path, struct string_list *prefixes);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-extern int is_ntfs_dotgit(const char *name);
+
+/*
+ * These functions match their is_hfs_dotgit() counterparts; see utf8.h for
+ * details.
+ */
+int is_ntfs_dotgit(const char *name);
+int is_ntfs_dotgitmodules(const char *name);
+int is_ntfs_dotgitignore(const char *name);
+int is_ntfs_dotgitattributes(const char *name);
 
 /*
  * Returns true iff "str" could be confused as a command-line option when
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/configure new/git-2.17.1/configure
--- old/git-2.17.0/configure    2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/configure    2018-05-29 10:14:06.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for git 2.17.0.
+# Generated by GNU Autoconf 2.69 for git 2.17.1.
 #
 # Report bugs to <g...@vger.kernel.org>.
 #
@@ -580,8 +580,8 @@
 # Identity of this package.
 PACKAGE_NAME='git'
 PACKAGE_TARNAME='git'
-PACKAGE_VERSION='2.17.0'
-PACKAGE_STRING='git 2.17.0'
+PACKAGE_VERSION='2.17.1'
+PACKAGE_STRING='git 2.17.1'
 PACKAGE_BUGREPORT='g...@vger.kernel.org'
 PACKAGE_URL=''
 
@@ -1265,7 +1265,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures git 2.17.0 to adapt to many kinds of systems.
+\`configure' configures git 2.17.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1327,7 +1327,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of git 2.17.0:";;
+     short | recursive ) echo "Configuration of git 2.17.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1472,7 +1472,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-git configure 2.17.0
+git configure 2.17.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1952,7 +1952,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by git $as_me 2.17.0, which was
+It was created by git $as_me 2.17.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -8247,7 +8247,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by git $as_me 2.17.0, which was
+This file was extended by git $as_me 2.17.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8304,7 +8304,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-git config.status 2.17.0
+git config.status 2.17.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/dir.c new/git-2.17.1/dir.c
--- old/git-2.17.0/dir.c        2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/dir.c        2018-05-29 10:14:06.000000000 +0200
@@ -2992,7 +2992,7 @@
 {
        if (!istate->untracked || !istate->untracked->root)
                return;
-       if (!safe_path && !verify_path(path))
+       if (!safe_path && !verify_path(path, 0))
                return;
        invalidate_one_component(istate->untracked, istate->untracked->root,
                                 path, strlen(path));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/fsck.c new/git-2.17.1/fsck.c
--- old/git-2.17.0/fsck.c       2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/fsck.c       2018-05-29 10:14:06.000000000 +0200
@@ -10,6 +10,13 @@
 #include "utf8.h"
 #include "sha1-array.h"
 #include "decorate.h"
+#include "oidset.h"
+#include "packfile.h"
+#include "submodule-config.h"
+#include "config.h"
+
+static struct oidset gitmodules_found = OIDSET_INIT;
+static struct oidset gitmodules_done = OIDSET_INIT;
 
 #define FSCK_FATAL -1
 #define FSCK_INFO -2
@@ -44,6 +51,7 @@
        FUNC(MISSING_TAG_ENTRY, ERROR) \
        FUNC(MISSING_TAG_OBJECT, ERROR) \
        FUNC(MISSING_TREE, ERROR) \
+       FUNC(MISSING_TREE_OBJECT, ERROR) \
        FUNC(MISSING_TYPE, ERROR) \
        FUNC(MISSING_TYPE_ENTRY, ERROR) \
        FUNC(MULTIPLE_AUTHORS, ERROR) \
@@ -51,6 +59,11 @@
        FUNC(TREE_NOT_SORTED, ERROR) \
        FUNC(UNKNOWN_TYPE, ERROR) \
        FUNC(ZERO_PADDED_DATE, ERROR) \
+       FUNC(GITMODULES_MISSING, ERROR) \
+       FUNC(GITMODULES_BLOB, ERROR) \
+       FUNC(GITMODULES_PARSE, ERROR) \
+       FUNC(GITMODULES_NAME, ERROR) \
+       FUNC(GITMODULES_SYMLINK, ERROR) \
        /* warnings */ \
        FUNC(BAD_FILEMODE, WARN) \
        FUNC(EMPTY_NAME, WARN) \
@@ -561,10 +574,18 @@
                has_empty_name |= !*name;
                has_dot |= !strcmp(name, ".");
                has_dotdot |= !strcmp(name, "..");
-               has_dotgit |= (!strcmp(name, ".git") ||
-                              is_hfs_dotgit(name) ||
-                              is_ntfs_dotgit(name));
+               has_dotgit |= is_hfs_dotgit(name) || is_ntfs_dotgit(name);
                has_zero_pad |= *(char *)desc.buffer == '0';
+
+               if (is_hfs_dotgitmodules(name) || is_ntfs_dotgitmodules(name)) {
+                       if (!S_ISLNK(mode))
+                               oidset_insert(&gitmodules_found, oid);
+                       else
+                               retval += report(options, &item->object,
+                                                FSCK_MSG_GITMODULES_SYMLINK,
+                                                ".gitmodules is a symbolic 
link");
+               }
+
                if (update_tree_entry_gently(&desc)) {
                        retval += report(options, &item->object, 
FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
                        break;
@@ -901,6 +922,66 @@
        return fsck_tag_buffer(tag, data, size, options);
 }
 
+struct fsck_gitmodules_data {
+       struct object *obj;
+       struct fsck_options *options;
+       int ret;
+};
+
+static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
+{
+       struct fsck_gitmodules_data *data = vdata;
+       const char *subsection, *key;
+       int subsection_len;
+       char *name;
+
+       if (parse_config_key(var, "submodule", &subsection, &subsection_len, 
&key) < 0 ||
+           !subsection)
+               return 0;
+
+       name = xmemdupz(subsection, subsection_len);
+       if (check_submodule_name(name) < 0)
+               data->ret |= report(data->options, data->obj,
+                                   FSCK_MSG_GITMODULES_NAME,
+                                   "disallowed submodule name: %s",
+                                   name);
+       free(name);
+
+       return 0;
+}
+
+static int fsck_blob(struct blob *blob, const char *buf,
+                    unsigned long size, struct fsck_options *options)
+{
+       struct fsck_gitmodules_data data;
+
+       if (!oidset_contains(&gitmodules_found, &blob->object.oid))
+               return 0;
+       oidset_insert(&gitmodules_done, &blob->object.oid);
+
+       if (!buf) {
+               /*
+                * A missing buffer here is a sign that the caller found the
+                * blob too gigantic to load into memory. Let's just consider
+                * that an error.
+                */
+               return report(options, &blob->object,
+                             FSCK_MSG_GITMODULES_PARSE,
+                             ".gitmodules too large to parse");
+       }
+
+       data.obj = &blob->object;
+       data.options = options;
+       data.ret = 0;
+       if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
+                               ".gitmodules", buf, size, &data))
+               data.ret |= report(options, &blob->object,
+                                  FSCK_MSG_GITMODULES_PARSE,
+                                  "could not parse gitmodules blob");
+
+       return data.ret;
+}
+
 int fsck_object(struct object *obj, void *data, unsigned long size,
        struct fsck_options *options)
 {
@@ -908,7 +989,7 @@
                return report(options, obj, FSCK_MSG_BAD_OBJECT_SHA1, "no valid 
object to fsck");
 
        if (obj->type == OBJ_BLOB)
-               return 0;
+               return fsck_blob((struct blob *)obj, data, size, options);
        if (obj->type == OBJ_TREE)
                return fsck_tree((struct tree *) obj, options);
        if (obj->type == OBJ_COMMIT)
@@ -932,3 +1013,52 @@
        error("object %s: %s", describe_object(o, obj), message);
        return 1;
 }
+
+int fsck_finish(struct fsck_options *options)
+{
+       int ret = 0;
+       struct oidset_iter iter;
+       const struct object_id *oid;
+
+       oidset_iter_init(&gitmodules_found, &iter);
+       while ((oid = oidset_iter_next(&iter))) {
+               struct blob *blob;
+               enum object_type type;
+               unsigned long size;
+               char *buf;
+
+               if (oidset_contains(&gitmodules_done, oid))
+                       continue;
+
+               blob = lookup_blob(oid);
+               if (!blob) {
+                       ret |= report(options, &blob->object,
+                                     FSCK_MSG_GITMODULES_BLOB,
+                                     "non-blob found at .gitmodules");
+                       continue;
+               }
+
+               buf = read_sha1_file(oid->hash, &type, &size);
+               if (!buf) {
+                       if (is_promisor_object(&blob->object.oid))
+                               continue;
+                       ret |= report(options, &blob->object,
+                                     FSCK_MSG_GITMODULES_MISSING,
+                                     "unable to read .gitmodules blob");
+                       continue;
+               }
+
+               if (type == OBJ_BLOB)
+                       ret |= fsck_blob(blob, buf, size, options);
+               else
+                       ret |= report(options, &blob->object,
+                                     FSCK_MSG_GITMODULES_BLOB,
+                                     "non-blob found at .gitmodules");
+               free(buf);
+       }
+
+
+       oidset_clear(&gitmodules_found);
+       oidset_clear(&gitmodules_done);
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/fsck.h new/git-2.17.1/fsck.h
--- old/git-2.17.0/fsck.h       2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/fsck.h       2018-05-29 10:14:06.000000000 +0200
@@ -53,4 +53,11 @@
 int fsck_object(struct object *obj, void *data, unsigned long size,
        struct fsck_options *options);
 
+/*
+ * Some fsck checks are context-dependent, and may end up queued; run this
+ * after completing all fsck_object() calls in order to resolve any remaining
+ * checks.
+ */
+int fsck_finish(struct fsck_options *options);
+
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/git-compat-util.h 
new/git-2.17.1/git-compat-util.h
--- old/git-2.17.0/git-compat-util.h    2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/git-compat-util.h    2018-05-29 10:14:06.000000000 +0200
@@ -1001,6 +1001,23 @@
                return (x & 0x20) == 0;
 }
 
+/*
+ * Like skip_prefix, but compare case-insensitively. Note that the comparison
+ * is done via tolower(), so it is strictly ASCII (no multi-byte characters or
+ * locale-specific conversions).
+ */
+static inline int skip_iprefix(const char *str, const char *prefix,
+                              const char **out)
+{
+       do {
+               if (!*prefix) {
+                       *out = str;
+                       return 1;
+               }
+       } while (tolower(*str++) == tolower(*prefix++));
+       return 0;
+}
+
 static inline int strtoul_ui(char const *s, int base, unsigned int *result)
 {
        unsigned long ul;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/git-submodule.sh 
new/git-2.17.1/git-submodule.sh
--- old/git-2.17.0/git-submodule.sh     2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/git-submodule.sh     2018-05-29 10:14:06.000000000 +0200
@@ -229,6 +229,11 @@
                sm_name="$sm_path"
        fi
 
+       if ! git submodule--helper check-name "$sm_name"
+       then
+               die "$(eval_gettext "'$sm_name' is not a valid submodule name")"
+       fi
+
        # perhaps the path exists and is already a git repo, else clone it
        if test -e "$sm_path"
        then
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/path.c new/git-2.17.1/path.c
--- old/git-2.17.0/path.c       2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/path.c       2018-05-29 10:14:06.000000000 +0200
@@ -1305,7 +1305,7 @@
 
 int is_ntfs_dotgit(const char *name)
 {
-       int len;
+       size_t len;
 
        for (len = 0; ; len++)
                if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
@@ -1322,6 +1322,90 @@
                }
 }
 
+static int is_ntfs_dot_generic(const char *name,
+                              const char *dotgit_name,
+                              size_t len,
+                              const char *dotgit_ntfs_shortname_prefix)
+{
+       int saw_tilde;
+       size_t i;
+
+       if ((name[0] == '.' && !strncasecmp(name + 1, dotgit_name, len))) {
+               i = len + 1;
+only_spaces_and_periods:
+               for (;;) {
+                       char c = name[i++];
+                       if (!c)
+                               return 1;
+                       if (c != ' ' && c != '.')
+                               return 0;
+               }
+       }
+
+       /*
+        * Is it a regular NTFS short name, i.e. shortened to 6 characters,
+        * followed by ~1, ... ~4?
+        */
+       if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' &&
+           name[7] >= '1' && name[7] <= '4') {
+               i = 8;
+               goto only_spaces_and_periods;
+       }
+
+       /*
+        * Is it a fall-back NTFS short name (for details, see
+        * https://en.wikipedia.org/wiki/8.3_filename?
+        */
+       for (i = 0, saw_tilde = 0; i < 8; i++)
+               if (name[i] == '\0')
+                       return 0;
+               else if (saw_tilde) {
+                       if (name[i] < '0' || name[i] > '9')
+                               return 0;
+               } else if (name[i] == '~') {
+                       if (name[++i] < '1' || name[i] > '9')
+                               return 0;
+                       saw_tilde = 1;
+               } else if (i >= 6)
+                       return 0;
+               else if (name[i] < 0) {
+                       /*
+                        * We know our needles contain only ASCII, so we clamp
+                        * here to make the results of tolower() sane.
+                        */
+                       return 0;
+               } else if (tolower(name[i]) != dotgit_ntfs_shortname_prefix[i])
+                       return 0;
+
+       goto only_spaces_and_periods;
+}
+
+/*
+ * Inline helper to make sure compiler resolves strlen() on literals at
+ * compile time.
+ */
+static inline int is_ntfs_dot_str(const char *name, const char *dotgit_name,
+                                 const char *dotgit_ntfs_shortname_prefix)
+{
+       return is_ntfs_dot_generic(name, dotgit_name, strlen(dotgit_name),
+                                  dotgit_ntfs_shortname_prefix);
+}
+
+int is_ntfs_dotgitmodules(const char *name)
+{
+       return is_ntfs_dot_str(name, "gitmodules", "gi7eba");
+}
+
+int is_ntfs_dotgitignore(const char *name)
+{
+       return is_ntfs_dot_str(name, "gitignore", "gi250a");
+}
+
+int is_ntfs_dotgitattributes(const char *name)
+{
+       return is_ntfs_dot_str(name, "gitattributes", "gi7d29");
+}
+
 int looks_like_command_line_option(const char *str)
 {
        return str && str[0] == '-';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/read-cache.c new/git-2.17.1/read-cache.c
--- old/git-2.17.0/read-cache.c 2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/read-cache.c 2018-05-29 10:14:06.000000000 +0200
@@ -752,7 +752,7 @@
        int size, len;
        struct cache_entry *ce, *ret;
 
-       if (!verify_path(path)) {
+       if (!verify_path(path, mode)) {
                error("Invalid path '%s'", path);
                return NULL;
        }
@@ -817,7 +817,7 @@
  * Also, we don't want double slashes or slashes at the
  * end that can make pathnames ambiguous.
  */
-static int verify_dotfile(const char *rest)
+static int verify_dotfile(const char *rest, unsigned mode)
 {
        /*
         * The first character was '.', but that
@@ -831,8 +831,13 @@
 
        switch (*rest) {
        /*
-        * ".git" followed by  NUL or slash is bad. This
-        * shares the path end test with the ".." case.
+        * ".git" followed by NUL or slash is bad. Note that we match
+        * case-insensitively here, even if ignore_case is not set.
+        * This outlaws ".GIT" everywhere out of an abundance of caution,
+        * since there's really no good reason to allow it.
+        *
+        * Once we've seen ".git", we can also find ".gitmodules", etc (also
+        * case-insensitively).
         */
        case 'g':
        case 'G':
@@ -840,8 +845,15 @@
                        break;
                if (rest[2] != 't' && rest[2] != 'T')
                        break;
-               rest += 2;
-       /* fallthrough */
+               if (rest[3] == '\0' || is_dir_sep(rest[3]))
+                       return 0;
+               if (S_ISLNK(mode)) {
+                       rest += 3;
+                       if (skip_iprefix(rest, "modules", &rest) &&
+                           (*rest == '\0' || is_dir_sep(*rest)))
+                               return 0;
+               }
+               break;
        case '.':
                if (rest[1] == '\0' || is_dir_sep(rest[1]))
                        return 0;
@@ -849,7 +861,7 @@
        return 1;
 }
 
-int verify_path(const char *path)
+int verify_path(const char *path, unsigned mode)
 {
        char c;
 
@@ -862,12 +874,25 @@
                        return 1;
                if (is_dir_sep(c)) {
 inside:
-                       if (protect_hfs && is_hfs_dotgit(path))
-                               return 0;
-                       if (protect_ntfs && is_ntfs_dotgit(path))
-                               return 0;
+                       if (protect_hfs) {
+                               if (is_hfs_dotgit(path))
+                                       return 0;
+                               if (S_ISLNK(mode)) {
+                                       if (is_hfs_dotgitmodules(path))
+                                               return 0;
+                               }
+                       }
+                       if (protect_ntfs) {
+                               if (is_ntfs_dotgit(path))
+                                       return 0;
+                               if (S_ISLNK(mode)) {
+                                       if (is_ntfs_dotgitmodules(path))
+                                               return 0;
+                               }
+                       }
+
                        c = *path++;
-                       if ((c == '.' && !verify_dotfile(path)) ||
+                       if ((c == '.' && !verify_dotfile(path, mode)) ||
                            is_dir_sep(c) || c == '\0')
                                return 0;
                }
@@ -1184,7 +1209,7 @@
 
        if (!ok_to_add)
                return -1;
-       if (!verify_path(ce->name))
+       if (!verify_path(ce->name, ce->ce_mode))
                return error("Invalid path '%s'", ce->name);
 
        if (!skip_df_check &&
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/sha1_file.c new/git-2.17.1/sha1_file.c
--- old/git-2.17.0/sha1_file.c  2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/sha1_file.c  2018-05-29 10:14:06.000000000 +0200
@@ -2209,7 +2209,7 @@
                goto out;
        }
 
-       if (*type == OBJ_BLOB) {
+       if (*type == OBJ_BLOB && *size > big_file_threshold) {
                if (check_stream_sha1(&stream, hdr, *size, path, expected_sha1) 
< 0)
                        goto out;
        } else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/submodule-config.c 
new/git-2.17.1/submodule-config.c
--- old/git-2.17.0/submodule-config.c   2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/submodule-config.c   2018-05-29 10:14:06.000000000 +0200
@@ -190,6 +190,31 @@
        return NULL;
 }
 
+int check_submodule_name(const char *name)
+{
+       /* Disallow empty names */
+       if (!*name)
+               return -1;
+
+       /*
+        * Look for '..' as a path component. Check both '/' and '\\' as
+        * separators rather than is_dir_sep(), because we want the name rules
+        * to be consistent across platforms.
+        */
+       goto in_component; /* always start inside component */
+       while (*name) {
+               char c = *name++;
+               if (c == '/' || c == '\\') {
+in_component:
+                       if (name[0] == '.' && name[1] == '.' &&
+                           (!name[2] || name[2] == '/' || name[2] == '\\'))
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
 static int name_and_item_from_var(const char *var, struct strbuf *name,
                                  struct strbuf *item)
 {
@@ -201,6 +226,12 @@
                return 0;
 
        strbuf_add(name, subsection, subsection_len);
+       if (check_submodule_name(name->buf) < 0) {
+               warning(_("ignoring suspicious submodule name: %s"), name->buf);
+               strbuf_release(name);
+               return 0;
+       }
+
        strbuf_addstr(item, key);
 
        return 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/submodule-config.h 
new/git-2.17.1/submodule-config.h
--- old/git-2.17.0/submodule-config.h   2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/submodule-config.h   2018-05-29 10:14:06.000000000 +0200
@@ -48,4 +48,11 @@
                                                    const char *key);
 extern void submodule_free(void);
 
+/*
+ * Returns 0 if the name is syntactically acceptable as a submodule "name"
+ * (e.g., that may be found in the subsection of a .gitmodules file) and -1
+ * otherwise.
+ */
+int check_submodule_name(const char *name);
+
 #endif /* SUBMODULE_CONFIG_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/t/helper/test-path-utils.c 
new/git-2.17.1/t/helper/test-path-utils.c
--- old/git-2.17.0/t/helper/test-path-utils.c   2018-04-02 19:44:04.000000000 
+0200
+++ new/git-2.17.1/t/helper/test-path-utils.c   2018-05-29 10:14:06.000000000 
+0200
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "string-list.h"
+#include "utf8.h"
 
 /*
  * A "string_list_each_func_t" function that normalizes an entry from
@@ -170,6 +171,11 @@
        { NULL,              NULL     }
 };
 
+static int is_dotgitmodules(const char *path)
+{
+       return is_hfs_dotgitmodules(path) || is_ntfs_dotgitmodules(path);
+}
+
 int cmd_main(int argc, const char **argv)
 {
        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
@@ -270,6 +276,20 @@
        if (argc == 2 && !strcmp(argv[1], "dirname"))
                return test_function(dirname_data, posix_dirname, argv[1]);
 
+       if (argc > 2 && !strcmp(argv[1], "is_dotgitmodules")) {
+               int res = 0, expect = 1, i;
+               for (i = 2; i < argc; i++)
+                       if (!strcmp("--not", argv[i]))
+                               expect = !expect;
+                       else if (expect != is_dotgitmodules(argv[i]))
+                               res = error("'%s' is %s.gitmodules", argv[i],
+                                           expect ? "not " : "");
+                       else
+                               fprintf(stderr, "ok: '%s' is %s.gitmodules\n",
+                                       argv[i], expect ? "" : "not ");
+               return !!res;
+       }
+
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/t/lib-pack.sh new/git-2.17.1/t/lib-pack.sh
--- old/git-2.17.0/t/lib-pack.sh        2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/t/lib-pack.sh        2018-05-29 10:14:06.000000000 +0200
@@ -79,6 +79,18 @@
                ;;
        esac
 
+       # If it's not a delta, we can convince pack-objects to generate a pack
+       # with just our entry, and then strip off the header (12 bytes) and
+       # trailer (20 bytes).
+       if test -z "$2"
+       then
+               echo "$1" | git pack-objects --stdout >pack_obj.tmp &&
+               size=$(wc -c <pack_obj.tmp) &&
+               dd if=pack_obj.tmp bs=1 count=$((size - 20 - 12)) skip=12 &&
+               rm -f pack_obj.tmp
+               return
+       fi
+
        echo >&2 "BUG: don't know how to print $1${2:+ (from $2)}"
        return 1
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/t/t0060-path-utils.sh 
new/git-2.17.1/t/t0060-path-utils.sh
--- old/git-2.17.0/t/t0060-path-utils.sh        2018-04-02 19:44:04.000000000 
+0200
+++ new/git-2.17.1/t/t0060-path-utils.sh        2018-05-29 10:14:06.000000000 
+0200
@@ -349,4 +349,90 @@
 test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" 
"user@host:path/to/subrepo"
 test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" 
"user@host:subrepo"
 
+test_expect_success 'match .gitmodules' '
+       test-path-utils is_dotgitmodules \
+               .gitmodules \
+               \
+               .git${u200c}modules \
+               \
+               .Gitmodules \
+               .gitmoduleS \
+               \
+               ".gitmodules " \
+               ".gitmodules." \
+               ".gitmodules  " \
+               ".gitmodules. " \
+               ".gitmodules ." \
+               ".gitmodules.." \
+               ".gitmodules   " \
+               ".gitmodules.  " \
+               ".gitmodules . " \
+               ".gitmodules  ." \
+               \
+               ".Gitmodules " \
+               ".Gitmodules." \
+               ".Gitmodules  " \
+               ".Gitmodules. " \
+               ".Gitmodules ." \
+               ".Gitmodules.." \
+               ".Gitmodules   " \
+               ".Gitmodules.  " \
+               ".Gitmodules . " \
+               ".Gitmodules  ." \
+               \
+               GITMOD~1 \
+               gitmod~1 \
+               GITMOD~2 \
+               gitmod~3 \
+               GITMOD~4 \
+               \
+               "GITMOD~1 " \
+               "gitmod~2." \
+               "GITMOD~3  " \
+               "gitmod~4. " \
+               "GITMOD~1 ." \
+               "gitmod~2   " \
+               "GITMOD~3.  " \
+               "gitmod~4 . " \
+               \
+               GI7EBA~1 \
+               gi7eba~9 \
+               \
+               GI7EB~10 \
+               GI7EB~11 \
+               GI7EB~99 \
+               GI7EB~10 \
+               GI7E~100 \
+               GI7E~101 \
+               GI7E~999 \
+               ~1000000 \
+               ~9999999 \
+               \
+               --not \
+               ".gitmodules x"  \
+               ".gitmodules .x" \
+               \
+               " .gitmodules" \
+               \
+               ..gitmodules \
+               \
+               gitmodules \
+               \
+               .gitmodule \
+               \
+               ".gitmodules x " \
+               ".gitmodules .x" \
+               \
+               GI7EBA~ \
+               GI7EBA~0 \
+               GI7EBA~~1 \
+               GI7EBA~X \
+               Gx7EBA~1 \
+               GI7EBX~1 \
+               \
+               GI7EB~1 \
+               GI7EB~01 \
+               GI7EB~1X
+'
+
 test_done
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/t/t7415-submodule-names.sh 
new/git-2.17.1/t/t7415-submodule-names.sh
--- old/git-2.17.0/t/t7415-submodule-names.sh   1970-01-01 01:00:00.000000000 
+0100
+++ new/git-2.17.1/t/t7415-submodule-names.sh   2018-05-29 10:14:06.000000000 
+0200
@@ -0,0 +1,154 @@
+#!/bin/sh
+
+test_description='check handling of .. in submodule names
+
+Exercise the name-checking function on a variety of names, and then give a
+real-world setup that confirms we catch this in practice.
+'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-pack.sh
+
+test_expect_success 'check names' '
+       cat >expect <<-\EOF &&
+       valid
+       valid/with/paths
+       EOF
+
+       git submodule--helper check-name >actual <<-\EOF &&
+       valid
+       valid/with/paths
+
+       ../foo
+       /../foo
+       ..\foo
+       \..\foo
+       foo/..
+       foo/../
+       foo\..
+       foo\..\
+       foo/../bar
+       EOF
+
+       test_cmp expect actual
+'
+
+test_expect_success 'create innocent subrepo' '
+       git init innocent &&
+       git -C innocent commit --allow-empty -m foo
+'
+
+test_expect_success 'submodule add refuses invalid names' '
+       test_must_fail \
+               git submodule add --name ../../modules/evil "$PWD/innocent" evil
+'
+
+test_expect_success 'add evil submodule' '
+       git submodule add "$PWD/innocent" evil &&
+
+       mkdir modules &&
+       cp -r .git/modules/evil modules &&
+       write_script modules/evil/hooks/post-checkout <<-\EOF &&
+       echo >&2 "RUNNING POST CHECKOUT"
+       EOF
+
+       git config -f .gitmodules submodule.evil.update checkout &&
+       git config -f .gitmodules --rename-section \
+               submodule.evil submodule.../../modules/evil &&
+       git add modules &&
+       git commit -am evil
+'
+
+# This step seems like it shouldn't be necessary, since the payload is
+# contained entirely in the evil submodule. But due to the vagaries of the
+# submodule code, checking out the evil module will fail unless ".git/modules"
+# exists. Adding another submodule (with a name that sorts before "evil") is an
+# easy way to make sure this is the case in the victim clone.
+test_expect_success 'add other submodule' '
+       git submodule add "$PWD/innocent" another-module &&
+       git add another-module &&
+       git commit -am another
+'
+
+test_expect_success 'clone evil superproject' '
+       git clone --recurse-submodules . victim >output 2>&1 &&
+       ! grep "RUNNING POST CHECKOUT" output
+'
+
+test_expect_success 'fsck detects evil superproject' '
+       test_must_fail git fsck
+'
+
+test_expect_success 'transfer.fsckObjects detects evil superproject (unpack)' '
+       rm -rf dst.git &&
+       git init --bare dst.git &&
+       git -C dst.git config transfer.fsckObjects true &&
+       test_must_fail git push dst.git HEAD
+'
+
+test_expect_success 'transfer.fsckObjects detects evil superproject (index)' '
+       rm -rf dst.git &&
+       git init --bare dst.git &&
+       git -C dst.git config transfer.fsckObjects true &&
+       git -C dst.git config transfer.unpackLimit 1 &&
+       test_must_fail git push dst.git HEAD
+'
+
+# Normally our packs contain commits followed by trees followed by blobs. This
+# reverses the order, which requires backtracking to find the context of a
+# blob. We'll start with a fresh gitmodules-only tree to make it simpler.
+test_expect_success 'create oddly ordered pack' '
+       git checkout --orphan odd &&
+       git rm -rf --cached . &&
+       git add .gitmodules &&
+       git commit -m odd &&
+       {
+               pack_header 3 &&
+               pack_obj $(git rev-parse HEAD:.gitmodules) &&
+               pack_obj $(git rev-parse HEAD^{tree}) &&
+               pack_obj $(git rev-parse HEAD)
+       } >odd.pack &&
+       pack_trailer odd.pack
+'
+
+test_expect_success 'transfer.fsckObjects handles odd pack (unpack)' '
+       rm -rf dst.git &&
+       git init --bare dst.git &&
+       test_must_fail git -C dst.git unpack-objects --strict <odd.pack
+'
+
+test_expect_success 'transfer.fsckObjects handles odd pack (index)' '
+       rm -rf dst.git &&
+       git init --bare dst.git &&
+       test_must_fail git -C dst.git index-pack --strict --stdin <odd.pack
+'
+
+test_expect_success 'fsck detects symlinked .gitmodules file' '
+       git init symlink &&
+       (
+               cd symlink &&
+
+               # Make the tree directly to avoid index restrictions.
+               #
+               # Because symlinks store the target as a blob, choose
+               # a pathname that could be parsed as a .gitmodules file
+               # to trick naive non-symlink-aware checking.
+               tricky="[foo]bar=true" &&
+               content=$(git hash-object -w ../.gitmodules) &&
+               target=$(printf "$tricky" | git hash-object -w --stdin) &&
+               tree=$(
+                       {
+                               printf "100644 blob $content\t$tricky\n" &&
+                               printf "120000 blob $target\t.gitmodules\n"
+                       } | git mktree
+               ) &&
+               commit=$(git commit-tree $tree) &&
+
+               # Check not only that we fail, but that it is due to the
+               # symlink detector; this grep string comes from the config
+               # variable name and will not be translated.
+               test_must_fail git fsck 2>output &&
+               grep gitmodulesSymlink output
+       )
+'
+
+test_done
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/utf8.c new/git-2.17.1/utf8.c
--- old/git-2.17.0/utf8.c       2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/utf8.c       2018-05-29 10:14:06.000000000 +0200
@@ -620,28 +620,33 @@
        }
 }
 
-int is_hfs_dotgit(const char *path)
+static int is_hfs_dot_generic(const char *path,
+                             const char *needle, size_t needle_len)
 {
        ucs_char_t c;
 
        c = next_hfs_char(&path);
        if (c != '.')
                return 0;
-       c = next_hfs_char(&path);
 
        /*
         * there's a great deal of other case-folding that occurs
-        * in HFS+, but this is enough to catch anything that will
-        * convert to ".git"
+        * in HFS+, but this is enough to catch our fairly vanilla
+        * hard-coded needles.
         */
-       if (c != 'g' && c != 'G')
-               return 0;
-       c = next_hfs_char(&path);
-       if (c != 'i' && c != 'I')
-               return 0;
-       c = next_hfs_char(&path);
-       if (c != 't' && c != 'T')
-               return 0;
+       for (; needle_len > 0; needle++, needle_len--) {
+               c = next_hfs_char(&path);
+
+               /*
+                * We know our needles contain only ASCII, so we clamp here to
+                * make the results of tolower() sane.
+                */
+               if (c > 127)
+                       return 0;
+               if (tolower(c) != *needle)
+                       return 0;
+       }
+
        c = next_hfs_char(&path);
        if (c && !is_dir_sep(c))
                return 0;
@@ -649,6 +654,35 @@
        return 1;
 }
 
+/*
+ * Inline wrapper to make sure the compiler resolves strlen() on literals at
+ * compile time.
+ */
+static inline int is_hfs_dot_str(const char *path, const char *needle)
+{
+       return is_hfs_dot_generic(path, needle, strlen(needle));
+}
+
+int is_hfs_dotgit(const char *path)
+{
+       return is_hfs_dot_str(path, "git");
+}
+
+int is_hfs_dotgitmodules(const char *path)
+{
+       return is_hfs_dot_str(path, "gitmodules");
+}
+
+int is_hfs_dotgitignore(const char *path)
+{
+       return is_hfs_dot_str(path, "gitignore");
+}
+
+int is_hfs_dotgitattributes(const char *path)
+{
+       return is_hfs_dot_str(path, "gitattributes");
+}
+
 const char utf8_bom[] = "\357\273\277";
 
 int skip_utf8_bom(char **text, size_t len)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/utf8.h new/git-2.17.1/utf8.h
--- old/git-2.17.0/utf8.h       2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/utf8.h       2018-05-29 10:14:06.000000000 +0200
@@ -52,8 +52,13 @@
  * The path should be NUL-terminated, but we will match variants of both 
".git\0"
  * and ".git/..." (but _not_ ".../.git"). This makes it suitable for both fsck
  * and verify_path().
+ *
+ * Likewise, the is_hfs_dotgitfoo() variants look for ".gitfoo".
  */
 int is_hfs_dotgit(const char *path);
+int is_hfs_dotgitmodules(const char *path);
+int is_hfs_dotgitignore(const char *path);
+int is_hfs_dotgitattributes(const char *path);
 
 typedef enum {
        ALIGN_LEFT,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/git-2.17.0/version new/git-2.17.1/version
--- old/git-2.17.0/version      2018-04-02 19:44:04.000000000 +0200
+++ new/git-2.17.1/version      2018-05-29 10:14:06.000000000 +0200
@@ -1 +1 @@
-2.17.0
+2.17.1



Reply via email to