7
#include "tag.h"
8
#include "fsck.h"
9
#include "refs.h"
10
+#include "url.h"
11
#include "utf8.h"
12
#include "sha1-array.h"
13
#include "decorate.h"
943
return fsck_tag_buffer(tag, data, size, options);
944
}
945
946
+/*
947
+ * Like builtin/submodule--helper.c's starts_with_dot_slash, but without
948
+ * relying on the platform-dependent is_dir_sep helper.
949
+ *
950
+ * This is for use in checking whether a submodule URL is interpreted as
951
+ * relative to the current directory on any platform, since \ is a
952
+ * directory separator on Windows but not on other platforms.
953
+ */
954
+static int starts_with_dot_slash(const char *str)
955
+{
956
+ return str[0] == '.' && (str[1] == '/' || str[1] == '\\');
957
+}
958
+
959
+/*
960
+ * Like starts_with_dot_slash, this is a variant of submodule--helper's
961
+ * helper of the same name with the twist that it accepts backslash as a
962
+ * directory separator even on non-Windows platforms.
963
+ */
964
+static int starts_with_dot_dot_slash(const char *str)
965
+{
966
+ return str[0] == '.' && starts_with_dot_slash(str + 1);
967
+}
968
+
969
+static int submodule_url_is_relative(const char *url)
970
+{
971
+ return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
972
+}
973
+
974
+/*
975
+ * Check whether a transport is implemented by git-remote-curl.
976
+ *
977
+ * If it is, returns 1 and writes the URL that would be passed to
978
+ * git-remote-curl to the "out" parameter.
979
+ *
980
+ * Otherwise, returns 0 and leaves "out" untouched.
981
+ *
982
+ * Examples:
983
+ * http::https://example.com/repo.git -> 1, https://example.com/repo.git
984
+ * https://example.com/repo.git -> 1, https://example.com/repo.git
985
+ * git://example.com/repo.git -> 0
986
+ *
987
+ * This is for use in checking for previously exploitable bugs that
988
+ * required a submodule URL to be passed to git-remote-curl.
989
+ */
990
+static int url_to_curl_url(const char *url, const char **out)
991
+{
992
+ /*
993
+ * We don't need to check for case-aliases, "http.exe", and so
994
+ * on because in the default configuration, is_transport_allowed
995
+ * prevents URLs with those schemes from being cloned
996
+ * automatically.
997
+ */
998
+ if (skip_prefix(url, "http::", out) ||
999
+ skip_prefix(url, "https::", out) ||
1000
+ skip_prefix(url, "ftp::", out) ||
1001
+ skip_prefix(url, "ftps::", out))
1002
+ return 1;
1003
+ if (starts_with(url, "http://") ||
1004
+ starts_with(url, "https://") ||
1005
+ starts_with(url, "ftp://") ||
1006
+ starts_with(url, "ftps://")) {
1007
+ *out = url;
1008
+ return 1;
1009
+ }
1010
+ return 0;
1011
+}
1012
+
1013
static int check_submodule_url(const char *url)
1014
{
947
- struct credential c = CREDENTIAL_INIT;
948
- int ret;
1015
+ const char *curl_url;
1016
1017
if (looks_like_command_line_option(url))
1018
return -1;
1019
953
- ret = credential_from_url_gently(&c, url, 1);
954
- credential_clear(&c);
955
- return ret;
1020
+ if (submodule_url_is_relative(url)) {
1021
+ /*
1022
+ * This could be appended to an http URL and url-decoded;
1023
+ * check for malicious characters.
1024
+ */
1025
+ char *decoded = url_decode(url);
1026
+ int has_nl = !!strchr(decoded, '\n');
1027
+ free(decoded);
1028
+ if (has_nl)
1029
+ return -1;
1030
+ }
1031
+
1032
+ else if (url_to_curl_url(url, &curl_url)) {
1033
+ struct credential c = CREDENTIAL_INIT;
1034
+ int ret = credential_from_url_gently(&c, curl_url, 1);
1035
+ credential_clear(&c);
1036
+ return ret;
1037
+ }
1038
+
1039
+ return 0;
1040
}
1041
1042
struct fsck_gitmodules_data {