Skip to content
Snippets Groups Projects
Commit 7913f53b authored by Junio C Hamano's avatar Junio C Hamano
Browse files

Sync with Git 2.17.1

* maint: (25 commits)
  Git 2.17.1
  Git 2.16.4
  Git 2.15.2
  Git 2.14.4
  Git 2.13.7
  fsck: complain when .gitmodules is a symlink
  index-pack: check .gitmodules files with --strict
  unpack-objects: call fsck_finish() after fscking objects
  fsck: call fsck_finish() after fscking objects
  fsck: check .gitmodules content
  fsck: handle promisor objects in .gitmodules check
  fsck: detect gitmodules files
  fsck: actually fsck blob data
  fsck: simplify ".git" check
  index-pack: make fsck error message more specific
  verify_path: disallow symlinks in .gitmodules
  update-index: stat updated files earlier
  verify_dotfile: mention case-insensitivity in comment
  verify_path: drop clever fallthrough
  skip_prefix: add case-insensitive variant
  ...
parents e144d126 fc54c1af
No related branches found
No related tags found
No related merge requests found
Showing with 433 additions and 60 deletions
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.
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.
Loading
Loading
@@ -43,5 +43,8 @@ Fixes since v2.15.1
* 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.
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.
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.
Loading
Loading
@@ -3860,9 +3860,9 @@ static int check_unsafe_path(struct patch *patch)
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;
}
Loading
Loading
Loading
Loading
@@ -340,7 +340,7 @@ static void check_connectivity(void)
}
}
 
static int fsck_obj(struct object *obj)
static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
{
int err;
 
Loading
Loading
@@ -354,7 +354,7 @@ static int fsck_obj(struct object *obj)
 
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;
 
Loading
Loading
@@ -399,7 +399,7 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
}
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
return fsck_obj(obj);
return fsck_obj(obj, buffer, size);
}
 
static int default_refs;
Loading
Loading
@@ -507,44 +507,42 @@ static void get_default_heads(void)
}
}
 
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, &type, &size, &contents) < 0)
return NULL;
if (read_loose_object(path, oid, &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)
Loading
Loading
@@ -756,6 +754,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
stop_progress(&progress);
}
if (fsck_finish(&fsck_obj_options))
errors_found |= ERROR_OBJECT;
}
 
for (i = 0; i < argc; i++) {
Loading
Loading
Loading
Loading
@@ -837,6 +837,9 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
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;
Loading
Loading
@@ -854,7 +857,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
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));
 
Loading
Loading
@@ -1479,6 +1482,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
} 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 {
Loading
Loading
@@ -1820,6 +1826,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
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)
Loading
Loading
Loading
Loading
@@ -1825,6 +1825,29 @@ static int is_active(int argc, const char **argv, const char *prefix)
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 {
Loading
Loading
@@ -1850,6 +1873,7 @@ static struct cmd_struct commands[] = {
{"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)
Loading
Loading
Loading
Loading
@@ -210,7 +210,7 @@ static int check_object(struct object *obj, int type, void *data, struct fsck_op
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));
Loading
Loading
@@ -572,8 +572,11 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
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);
Loading
Loading
Loading
Loading
@@ -364,10 +364,9 @@ static int process_directory(const char *path, int len, struct stat *st)
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);
Loading
Loading
@@ -391,13 +390,13 @@ static int process_path(const char *path)
* 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,
Loading
Loading
@@ -406,7 +405,7 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
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);
Loading
Loading
@@ -449,7 +448,18 @@ static void chmod_path(char flip, const char *path)
 
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;
}
Loading
Loading
@@ -475,7 +485,7 @@ static void update_one(const char *path)
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);
}
Loading
Loading
@@ -545,7 +555,7 @@ static void read_index_info(int nul_term_line)
path_name = uq.buf;
}
 
if (!verify_path(path_name)) {
if (!verify_path(path_name, mode)) {
fprintf(stderr, "Ignoring path %s\n", path_name);
continue;
}
Loading
Loading
Loading
Loading
@@ -642,7 +642,7 @@ extern int unmerged_index(const struct index_state *);
*/
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);
Loading
Loading
@@ -1168,7 +1168,15 @@ int normalize_path_copy(char *dst, const char *src);
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
Loading
Loading
Loading
Loading
@@ -2993,7 +2993,7 @@ void untracked_cache_invalidate_path(struct index_state *istate,
{
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));
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
@@ -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) \
Loading
Loading
@@ -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) \
Loading
Loading
@@ -563,10 +576,18 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
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;
Loading
Loading
@@ -903,6 +924,66 @@ static int fsck_tag(struct tag *tag, const char *data,
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)
{
Loading
Loading
@@ -910,7 +991,7 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
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)
Loading
Loading
@@ -934,3 +1015,52 @@ int fsck_error_function(struct fsck_options *o,
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_object_file(oid, &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;
}
Loading
Loading
@@ -53,4 +53,11 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options);
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
Loading
Loading
@@ -1006,6 +1006,23 @@ static inline int sane_iscase(int x, int is_lower)
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;
Loading
Loading
Loading
Loading
@@ -229,6 +229,11 @@ Use -f if you really want to add it." >&2
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
Loading
Loading
Loading
Loading
@@ -1306,7 +1306,7 @@ static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
 
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])) {
Loading
Loading
@@ -1323,6 +1323,90 @@ int is_ntfs_dotgit(const char *name)
}
}
 
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] == '-';
Loading
Loading
Loading
Loading
@@ -752,7 +752,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,
int size, len;
struct cache_entry *ce, *ret;
 
if (!verify_path(path)) {
if (!verify_path(path, mode)) {
error("Invalid path '%s'", path);
return NULL;
}
Loading
Loading
@@ -817,7 +817,7 @@ int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
* 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
Loading
Loading
@@ -831,8 +831,13 @@ static int verify_dotfile(const char *rest)
 
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':
Loading
Loading
@@ -840,8 +845,15 @@ static int verify_dotfile(const char *rest)
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;
Loading
Loading
@@ -849,7 +861,7 @@ static int verify_dotfile(const char *rest)
return 1;
}
 
int verify_path(const char *path)
int verify_path(const char *path, unsigned mode)
{
char c;
 
Loading
Loading
@@ -862,12 +874,25 @@ int verify_path(const char *path)
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;
}
Loading
Loading
@@ -1184,7 +1209,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
 
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 &&
Loading
Loading
Loading
Loading
@@ -2232,7 +2232,7 @@ int read_loose_object(const char *path,
goto out;
}
 
if (*type == OBJ_BLOB) {
if (*type == OBJ_BLOB && *size > big_file_threshold) {
if (check_stream_sha1(&stream, hdr, *size, path, expected_oid->hash) < 0)
goto out;
} else {
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment