summaryrefslogtreecommitdiff
path: root/fsck.c
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2021-03-03 15:16:41 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2021-03-03 15:16:41 +0900
commit63b33047c1428dbf4f480b384962c6c8c0e841dd (patch)
treebc75044387e94c2fa3d82befc040f59dfa0046fb /fsck.c
parent2c3df790165c3c9177ce55f1a3732f2442be3315 (diff)
downloadgit-63b33047c1428dbf4f480b384962c6c8c0e841dd.tar.gz
git-63b33047c1428dbf4f480b384962c6c8c0e841dd.tar.bz2
git-63b33047c1428dbf4f480b384962c6c8c0e841dd.zip
Imported Upstream version 2.19.0upstream/2.19.0
Diffstat (limited to 'fsck.c')
-rw-r--r--fsck.c286
1 files changed, 76 insertions, 210 deletions
diff --git a/fsck.c b/fsck.c
index ad493c70..a0cee0be 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1,4 +1,6 @@
#include "cache.h"
+#include "object-store.h"
+#include "repository.h"
#include "object.h"
#include "blob.h"
#include "tree.h"
@@ -7,7 +9,6 @@
#include "tag.h"
#include "fsck.h"
#include "refs.h"
-#include "url.h"
#include "utf8.h"
#include "sha1-array.h"
#include "decorate.h"
@@ -15,7 +16,7 @@
#include "packfile.h"
#include "submodule-config.h"
#include "config.h"
-#include "credential.h"
+#include "help.h"
static struct oidset gitmodules_found = OIDSET_INIT;
static struct oidset gitmodules_done = OIDSET_INIT;
@@ -63,12 +64,9 @@ static struct oidset gitmodules_done = OIDSET_INIT;
FUNC(ZERO_PADDED_DATE, ERROR) \
FUNC(GITMODULES_MISSING, ERROR) \
FUNC(GITMODULES_BLOB, ERROR) \
- FUNC(GITMODULES_PARSE, ERROR) \
+ FUNC(GITMODULES_LARGE, ERROR) \
FUNC(GITMODULES_NAME, ERROR) \
FUNC(GITMODULES_SYMLINK, ERROR) \
- FUNC(GITMODULES_URL, ERROR) \
- FUNC(GITMODULES_PATH, ERROR) \
- FUNC(GITMODULES_UPDATE, ERROR) \
/* warnings */ \
FUNC(BAD_FILEMODE, WARN) \
FUNC(EMPTY_NAME, WARN) \
@@ -80,6 +78,7 @@ static struct oidset gitmodules_done = OIDSET_INIT;
FUNC(ZERO_PADDED_FILEMODE, WARN) \
FUNC(NUL_IN_COMMIT, WARN) \
/* infos (reported as warnings, but ignored by default) */ \
+ FUNC(GITMODULES_PARSE, INFO) \
FUNC(BAD_TAG_NAME, INFO) \
FUNC(MISSING_TAGGER_ENTRY, INFO)
@@ -91,37 +90,60 @@ enum fsck_msg_id {
#undef MSG_ID
#define STR(x) #x
-#define MSG_ID(id, msg_type) { STR(id), NULL, FSCK_##msg_type },
+#define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },
static struct {
const char *id_string;
const char *downcased;
+ const char *camelcased;
int msg_type;
} msg_id_info[FSCK_MSG_MAX + 1] = {
FOREACH_MSG_ID(MSG_ID)
- { NULL, NULL, -1 }
+ { NULL, NULL, NULL, -1 }
};
#undef MSG_ID
-static int parse_msg_id(const char *text)
+static void prepare_msg_ids(void)
{
int i;
- if (!msg_id_info[0].downcased) {
- /* convert id_string to lower case, without underscores. */
- for (i = 0; i < FSCK_MSG_MAX; i++) {
- const char *p = msg_id_info[i].id_string;
- int len = strlen(p);
- char *q = xmalloc(len);
-
- msg_id_info[i].downcased = q;
- while (*p)
- if (*p == '_')
- p++;
- else
- *(q)++ = tolower(*(p)++);
- *q = '\0';
+ if (msg_id_info[0].downcased)
+ return;
+
+ /* convert id_string to lower case, without underscores. */
+ for (i = 0; i < FSCK_MSG_MAX; i++) {
+ const char *p = msg_id_info[i].id_string;
+ int len = strlen(p);
+ char *q = xmalloc(len);
+
+ msg_id_info[i].downcased = q;
+ while (*p)
+ if (*p == '_')
+ p++;
+ else
+ *(q)++ = tolower(*(p)++);
+ *q = '\0';
+
+ p = msg_id_info[i].id_string;
+ q = xmalloc(len);
+ msg_id_info[i].camelcased = q;
+ while (*p) {
+ if (*p == '_') {
+ p++;
+ if (*p)
+ *q++ = *p++;
+ } else {
+ *q++ = tolower(*p++);
+ }
}
+ *q = '\0';
}
+}
+
+static int parse_msg_id(const char *text)
+{
+ int i;
+
+ prepare_msg_ids();
for (i = 0; i < FSCK_MSG_MAX; i++)
if (!strcmp(text, msg_id_info[i].downcased))
@@ -130,6 +152,16 @@ static int parse_msg_id(const char *text)
return -1;
}
+void list_config_fsck_msg_ids(struct string_list *list, const char *prefix)
+{
+ int i;
+
+ prepare_msg_ids();
+
+ for (i = 0; i < FSCK_MSG_MAX; i++)
+ list_config_item(list, prefix, msg_id_info[i].camelcased);
+}
+
static int fsck_msg_type(enum fsck_msg_id msg_id,
struct fsck_options *options)
{
@@ -286,6 +318,13 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id)
strbuf_addstr(sb, ": ");
}
+static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
+{
+ if (opts && opts->skiplist && obj)
+ return oid_array_lookup(opts->skiplist, &obj->oid) >= 0;
+ return 0;
+}
+
__attribute__((format (printf, 4, 5)))
static int report(struct fsck_options *options, struct object *object,
enum fsck_msg_id id, const char *fmt, ...)
@@ -297,8 +336,7 @@ static int report(struct fsck_options *options, struct object *object,
if (msg_type == FSCK_IGNORE)
return 0;
- if (options->skiplist && object &&
- oid_array_lookup(options->skiplist, &object->oid) >= 0)
+ if (object_on_skiplist(options, object))
return 0;
if (msg_type == FSCK_FATAL)
@@ -376,14 +414,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
continue;
if (S_ISDIR(entry.mode)) {
- obj = (struct object *)lookup_tree(entry.oid);
+ obj = (struct object *)lookup_tree(the_repository, entry.oid);
if (name && obj)
put_object_name(options, obj, "%s%s/", name,
entry.path);
result = options->walk(obj, OBJ_TREE, data, options);
}
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
- obj = (struct object *)lookup_blob(entry.oid);
+ obj = (struct object *)lookup_blob(the_repository, entry.oid);
if (name && obj)
put_object_name(options, obj, "%s%s", name,
entry.path);
@@ -481,7 +519,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
return -1;
if (obj->type == OBJ_NONE)
- parse_object(&obj->oid);
+ parse_object(the_repository, &obj->oid);
switch (obj->type) {
case OBJ_BLOB:
@@ -571,7 +609,7 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
while (desc.size) {
unsigned mode;
- const char *name, *backslash;
+ const char *name;
const struct object_id *oid;
oid = tree_entry_extract(&desc, &name, &mode);
@@ -593,22 +631,6 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
".gitmodules is a symbolic link");
}
- if ((backslash = strchr(name, '\\'))) {
- while (backslash) {
- backslash++;
- has_dotgit |= is_ntfs_dotgit(backslash);
- if (is_ntfs_dotgitmodules(backslash)) {
- if (!S_ISLNK(mode))
- oidset_insert(&gitmodules_found, oid);
- else
- retval += report(options, &item->object,
- FSCK_MSG_GITMODULES_SYMLINK,
- ".gitmodules is a symbolic link");
- }
- backslash = strchr(backslash, '\\');
- }
- }
-
if (update_tree_entry_gently(&desc)) {
retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
break;
@@ -782,7 +804,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
buffer = p + 1;
parent_line_count++;
}
- graft = lookup_commit_graft(&commit->object.oid);
+ graft = lookup_commit_graft(the_repository, &commit->object.oid);
parent_count = commit_list_count(commit->parents);
if (graft) {
if (graft->nr_parent == -1 && !parent_count)
@@ -947,149 +969,6 @@ static int fsck_tag(struct tag *tag, const char *data,
return fsck_tag_buffer(tag, data, size, options);
}
-/*
- * Like builtin/submodule--helper.c's starts_with_dot_slash, but without
- * relying on the platform-dependent is_dir_sep helper.
- *
- * This is for use in checking whether a submodule URL is interpreted as
- * relative to the current directory on any platform, since \ is a
- * directory separator on Windows but not on other platforms.
- */
-static int starts_with_dot_slash(const char *str)
-{
- return str[0] == '.' && (str[1] == '/' || str[1] == '\\');
-}
-
-/*
- * Like starts_with_dot_slash, this is a variant of submodule--helper's
- * helper of the same name with the twist that it accepts backslash as a
- * directory separator even on non-Windows platforms.
- */
-static int starts_with_dot_dot_slash(const char *str)
-{
- return str[0] == '.' && starts_with_dot_slash(str + 1);
-}
-
-static int submodule_url_is_relative(const char *url)
-{
- return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
-}
-
-/*
- * Count directory components that a relative submodule URL should chop
- * from the remote_url it is to be resolved against.
- *
- * In other words, this counts "../" components at the start of a
- * submodule URL.
- *
- * Returns the number of directory components to chop and writes a
- * pointer to the next character of url after all leading "./" and
- * "../" components to out.
- */
-static int count_leading_dotdots(const char *url, const char **out)
-{
- int result = 0;
- while (1) {
- if (starts_with_dot_dot_slash(url)) {
- result++;
- url += strlen("../");
- continue;
- }
- if (starts_with_dot_slash(url)) {
- url += strlen("./");
- continue;
- }
- *out = url;
- return result;
- }
-}
-/*
- * Check whether a transport is implemented by git-remote-curl.
- *
- * If it is, returns 1 and writes the URL that would be passed to
- * git-remote-curl to the "out" parameter.
- *
- * Otherwise, returns 0 and leaves "out" untouched.
- *
- * Examples:
- * http::https://example.com/repo.git -> 1, https://example.com/repo.git
- * https://example.com/repo.git -> 1, https://example.com/repo.git
- * git://example.com/repo.git -> 0
- *
- * This is for use in checking for previously exploitable bugs that
- * required a submodule URL to be passed to git-remote-curl.
- */
-static int url_to_curl_url(const char *url, const char **out)
-{
- /*
- * We don't need to check for case-aliases, "http.exe", and so
- * on because in the default configuration, is_transport_allowed
- * prevents URLs with those schemes from being cloned
- * automatically.
- */
- if (skip_prefix(url, "http::", out) ||
- skip_prefix(url, "https::", out) ||
- skip_prefix(url, "ftp::", out) ||
- skip_prefix(url, "ftps::", out))
- return 1;
- if (starts_with(url, "http://") ||
- starts_with(url, "https://") ||
- starts_with(url, "ftp://") ||
- starts_with(url, "ftps://")) {
- *out = url;
- return 1;
- }
- return 0;
-}
-
-static int check_submodule_url(const char *url)
-{
- const char *curl_url;
-
- if (looks_like_command_line_option(url))
- return -1;
-
- if (submodule_url_is_relative(url)) {
- char *decoded;
- const char *next;
- int has_nl;
-
- /*
- * This could be appended to an http URL and url-decoded;
- * check for malicious characters.
- */
- decoded = url_decode(url);
- has_nl = !!strchr(decoded, '\n');
-
- free(decoded);
- if (has_nl)
- return -1;
-
- /*
- * URLs which escape their root via "../" can overwrite
- * the host field and previous components, resolving to
- * URLs like https::example.com/submodule.git and
- * https:///example.com/submodule.git that were
- * susceptible to CVE-2020-11008.
- */
- if (count_leading_dotdots(url, &next) > 0 &&
- (*next == ':' || *next == '/'))
- return -1;
- }
-
- else if (url_to_curl_url(url, &curl_url)) {
- struct credential c = CREDENTIAL_INIT;
- int ret = 0;
- if (credential_from_url_gently(&c, curl_url, 1) ||
- !*c.host)
- ret = -1;
- credential_clear(&c);
- return ret;
- }
-
- return 0;
-}
-
struct fsck_gitmodules_data {
struct object *obj;
struct fsck_options *options;
@@ -1113,24 +992,6 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
FSCK_MSG_GITMODULES_NAME,
"disallowed submodule name: %s",
name);
- if (!strcmp(key, "url") && value &&
- check_submodule_url(value) < 0)
- data->ret |= report(data->options, data->obj,
- FSCK_MSG_GITMODULES_URL,
- "disallowed submodule url: %s",
- value);
- if (!strcmp(key, "path") && value &&
- looks_like_command_line_option(value))
- data->ret |= report(data->options, data->obj,
- FSCK_MSG_GITMODULES_PATH,
- "disallowed submodule path: %s",
- value);
- if (!strcmp(key, "update") && value &&
- parse_submodule_update_type(value) == SM_UPDATE_COMMAND)
- data->ret |= report(data->options, data->obj,
- FSCK_MSG_GITMODULES_UPDATE,
- "disallowed submodule update setting: %s",
- value);
free(name);
return 0;
@@ -1140,11 +1001,15 @@ static int fsck_blob(struct blob *blob, const char *buf,
unsigned long size, struct fsck_options *options)
{
struct fsck_gitmodules_data data;
+ struct config_options config_opts = { 0 };
if (!oidset_contains(&gitmodules_found, &blob->object.oid))
return 0;
oidset_insert(&gitmodules_done, &blob->object.oid);
+ if (object_on_skiplist(options, &blob->object))
+ return 0;
+
if (!buf) {
/*
* A missing buffer here is a sign that the caller found the
@@ -1152,15 +1017,16 @@ static int fsck_blob(struct blob *blob, const char *buf,
* that an error.
*/
return report(options, &blob->object,
- FSCK_MSG_GITMODULES_PARSE,
+ FSCK_MSG_GITMODULES_LARGE,
".gitmodules too large to parse");
}
data.obj = &blob->object;
data.options = options;
data.ret = 0;
+ config_opts.error_action = CONFIG_ERROR_SILENT;
if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
- ".gitmodules", buf, size, &data))
+ ".gitmodules", buf, size, &data, &config_opts))
data.ret |= report(options, &blob->object,
FSCK_MSG_GITMODULES_PARSE,
"could not parse gitmodules blob");
@@ -1216,7 +1082,7 @@ int fsck_finish(struct fsck_options *options)
if (oidset_contains(&gitmodules_done, oid))
continue;
- blob = lookup_blob(oid);
+ blob = lookup_blob(the_repository, oid);
if (!blob) {
struct object *obj = lookup_unknown_object(oid->hash);
ret |= report(options, obj,