diff options
Diffstat (limited to 'fsck.c')
-rw-r--r-- | fsck.c | 94 |
1 files changed, 89 insertions, 5 deletions
@@ -7,6 +7,7 @@ #include "tag.h" #include "fsck.h" #include "refs.h" +#include "url.h" #include "utf8.h" #include "sha1-array.h" #include "decorate.h" @@ -942,17 +943,100 @@ 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); +} + +/* + * 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) { - struct credential c = CREDENTIAL_INIT; - int ret; + const char *curl_url; if (looks_like_command_line_option(url)) return -1; - ret = credential_from_url_gently(&c, url, 1); - credential_clear(&c); - return ret; + if (submodule_url_is_relative(url)) { + /* + * This could be appended to an http URL and url-decoded; + * check for malicious characters. + */ + char *decoded = url_decode(url); + int has_nl = !!strchr(decoded, '\n'); + free(decoded); + if (has_nl) + return -1; + } + + else if (url_to_curl_url(url, &curl_url)) { + struct credential c = CREDENTIAL_INIT; + int ret = credential_from_url_gently(&c, curl_url, 1); + credential_clear(&c); + return ret; + } + + return 0; } struct fsck_gitmodules_data { |