summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch69
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch213
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch141
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch150
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch95
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch187
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch158
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32020.patch114
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch89
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch65
-rw-r--r--meta/recipes-devtools/git/git/CVE-2024-32465.patch206
-rw-r--r--meta/recipes-devtools/git/git_2.35.7.bb11
12 files changed, 1498 insertions, 0 deletions
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch
new file mode 100644
index 0000000000..c424562e05
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch
@@ -0,0 +1,69 @@
1From 21496b4c60b2327417c63fc9762096037a185be3 Mon Sep 17 00:00:00 2001
2From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
3Date: Thu, 1 Sep 2022 01:17:54 +0200
4Subject: [PATCH] submodule--helper: use xstrfmt() in clone_submodule()
5
6Use xstrfmt() in clone_submodule() instead of a "struct strbuf" in two
7cases where we weren't getting anything out of using the "struct
8strbuf".
9
10This changes code that was was added along with other uses of "struct
11strbuf" in this function in ee8838d1577 (submodule: rewrite
12`module_clone` shell function in C, 2015-09-08).
13
14Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
15Reviewed-by: Glen Choo <chooglen@google.com>
16Signed-off-by: Junio C Hamano <gitster@pobox.com>
17
18CVE: CVE-2024-32002
19
20Upstream-Status: Backport [https://github.com/git/git/commit/21496b4c60b2327417c63fc9762096037a185be3]
21
22Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
23---
24 builtin/submodule--helper.c | 17 +++++++++--------
25 1 file changed, 9 insertions(+), 8 deletions(-)
26
27diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
28index c5d3fc3..79868c3 100644
29--- a/builtin/submodule--helper.c
30+++ b/builtin/submodule--helper.c
31@@ -1761,12 +1761,11 @@ static int clone_submodule(struct module_clone_data *clone_data)
32 sm_gitdir = absolute_pathdup(sb.buf);
33 strbuf_reset(&sb);
34
35- if (!is_absolute_path(clone_data->path)) {
36- strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_data->path);
37- clone_data->path = strbuf_detach(&sb, NULL);
38- } else {
39+ if (!is_absolute_path(clone_data->path))
40+ clone_data->path = xstrfmt("%s/%s", get_git_work_tree(),
41+ clone_data->path);
42+ else
43 clone_data->path = xstrdup(clone_data->path);
44- }
45
46 if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
47 die(_("refusing to create/use '%s' in another submodule's "
48@@ -1813,14 +1812,16 @@ static int clone_submodule(struct module_clone_data *clone_data)
49 die(_("clone of '%s' into submodule path '%s' failed"),
50 clone_data->url, clone_data->path);
51 } else {
52+ char *path;
53+
54 if (clone_data->require_init && !access(clone_data->path, X_OK) &&
55 !is_empty_dir(clone_data->path))
56 die(_("directory not empty: '%s'"), clone_data->path);
57 if (safe_create_leading_directories_const(clone_data->path) < 0)
58 die(_("could not create directory '%s'"), clone_data->path);
59- strbuf_addf(&sb, "%s/index", sm_gitdir);
60- unlink_or_warn(sb.buf);
61- strbuf_reset(&sb);
62+ path = xstrfmt("%s/index", sm_gitdir);
63+ unlink_or_warn(path);
64+ free(path);
65 }
66
67 connect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);
68--
692.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch
new file mode 100644
index 0000000000..36cdb746a7
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch
@@ -0,0 +1,213 @@
1From 6fac5b2f352efc8c246d6d5be63a66b7b0fc0209 Mon Sep 17 00:00:00 2001
2From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
3Date: Thu, 1 Sep 2022 01:17:56 +0200
4Subject: [PATCH] submodule--helper: add "const" to passed "module_clone_data"
5
6Add "const" to the "struct module_clone_data" that we pass to
7clone_submodule(), which makes the ownership clear, and stops us from
8clobbering the "clone_data->path".
9
10We still need to add to the "reference" member, which is a "struct
11string_list". Let's do this by having clone_submodule() create its
12own, and copy the contents over, allowing us to pass it as a
13separate parameter.
14
15This new "struct string_list" still leaks memory, just as the "struct
16module_clone_data" did before. let's not fix that for now, to fix that
17we'll need to add some "goto cleanup" to the relevant code. That will
18eventually be done in follow-up commits, this change makes it easier
19to fix the memory leak.
20
21The scope of the new "reference" variable in add_submodule() could be
22narrowed to the "else" block, but as we'll eventually free it with a
23"goto cleanup" let's declare it at the start of the function.
24
25Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
26Reviewed-by: Glen Choo <chooglen@google.com>
27Signed-off-by: Junio C Hamano <gitster@pobox.com>
28
29CVE: CVE-2024-32002
30
31Upstream-Status: Backport [https://github.com/git/git/commit/6fac5b2f352efc8c246d6d5be63a66b7b0fc0209]
32
33Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
34---
35 builtin/submodule--helper.c | 52 ++++++++++++++++++++-----------------
36 1 file changed, 28 insertions(+), 24 deletions(-)
37
38diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
39index 79868c3..d1d64db 100644
40--- a/builtin/submodule--helper.c
41+++ b/builtin/submodule--helper.c
42@@ -1630,14 +1630,13 @@ struct module_clone_data {
43 const char *name;
44 const char *url;
45 const char *depth;
46- struct string_list reference;
47 unsigned int quiet: 1;
48 unsigned int progress: 1;
49 unsigned int dissociate: 1;
50 unsigned int require_init: 1;
51 int single_branch;
52 };
53-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
54+#define MODULE_CLONE_DATA_INIT { .single_branch = -1 }
55
56 struct submodule_alternate_setup {
57 const char *submodule_name;
58@@ -1750,22 +1749,24 @@ static void prepare_possible_alternates(const char *sm_name,
59 free(error_strategy);
60 }
61
62-static int clone_submodule(struct module_clone_data *clone_data)
63+static int clone_submodule(const struct module_clone_data *clone_data,
64+ struct string_list *reference)
65 {
66 char *p, *sm_gitdir;
67 char *sm_alternate = NULL, *error_strategy = NULL;
68 struct strbuf sb = STRBUF_INIT;
69 struct child_process cp = CHILD_PROCESS_INIT;
70+ const char *clone_data_path;
71
72 submodule_name_to_gitdir(&sb, the_repository, clone_data->name);
73 sm_gitdir = absolute_pathdup(sb.buf);
74 strbuf_reset(&sb);
75
76 if (!is_absolute_path(clone_data->path))
77- clone_data->path = xstrfmt("%s/%s", get_git_work_tree(),
78- clone_data->path);
79+ clone_data_path = xstrfmt("%s/%s", get_git_work_tree(),
80+ clone_data->path);
81 else
82- clone_data->path = xstrdup(clone_data->path);
83+ clone_data_path = xstrdup(clone_data->path);
84
85 if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
86 die(_("refusing to create/use '%s' in another submodule's "
87@@ -1775,7 +1776,7 @@ static int clone_submodule(struct module_clone_data *clone_data)
88 if (safe_create_leading_directories_const(sm_gitdir) < 0)
89 die(_("could not create directory '%s'"), sm_gitdir);
90
91- prepare_possible_alternates(clone_data->name, &clone_data->reference);
92+ prepare_possible_alternates(clone_data->name, reference);
93
94 strvec_push(&cp.args, "clone");
95 strvec_push(&cp.args, "--no-checkout");
96@@ -1784,10 +1785,10 @@ static int clone_submodule(struct module_clone_data *clone_data)
97 if (clone_data->progress)
98 strvec_push(&cp.args, "--progress");
99 if (clone_data->depth && *(clone_data->depth))
100- strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
101- if (clone_data->reference.nr) {
102+ strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
103+ if (reference->nr) {
104 struct string_list_item *item;
105- for_each_string_list_item(item, &clone_data->reference)
106+ for_each_string_list_item(item, reference)
107 strvec_pushl(&cp.args, "--reference",
108 item->string, NULL);
109 }
110@@ -1802,7 +1803,7 @@ static int clone_submodule(struct module_clone_data *clone_data)
111
112 strvec_push(&cp.args, "--");
113 strvec_push(&cp.args, clone_data->url);
114- strvec_push(&cp.args, clone_data->path);
115+ strvec_push(&cp.args, clone_data_path);
116
117 cp.git_cmd = 1;
118 prepare_submodule_repo_env(&cp.env_array);
119@@ -1810,25 +1811,25 @@ static int clone_submodule(struct module_clone_data *clone_data)
120
121 if(run_command(&cp))
122 die(_("clone of '%s' into submodule path '%s' failed"),
123- clone_data->url, clone_data->path);
124+ clone_data->url, clone_data_path);
125 } else {
126 char *path;
127
128- if (clone_data->require_init && !access(clone_data->path, X_OK) &&
129- !is_empty_dir(clone_data->path))
130- die(_("directory not empty: '%s'"), clone_data->path);
131- if (safe_create_leading_directories_const(clone_data->path) < 0)
132- die(_("could not create directory '%s'"), clone_data->path);
133+ if (clone_data->require_init && !access(clone_data_path, X_OK) &&
134+ !is_empty_dir(clone_data_path))
135+ die(_("directory not empty: '%s'"), clone_data_path);
136+ if (safe_create_leading_directories_const(clone_data_path) < 0)
137+ die(_("could not create directory '%s'"), clone_data_path);
138 path = xstrfmt("%s/index", sm_gitdir);
139 unlink_or_warn(path);
140 free(path);
141 }
142
143- connect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);
144+ connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);
145
146- p = git_pathdup_submodule(clone_data->path, "config");
147+ p = git_pathdup_submodule(clone_data_path, "config");
148 if (!p)
149- die(_("could not get submodule directory for '%s'"), clone_data->path);
150+ die(_("could not get submodule directory for '%s'"), clone_data_path);
151
152 /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
153 git_config_get_string("submodule.alternateLocation", &sm_alternate);
154@@ -1853,6 +1854,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
155 {
156 int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
157 struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
158+ struct string_list reference = STRING_LIST_INIT_NODUP;
159
160 struct option module_clone_options[] = {
161 OPT_STRING(0, "prefix", &clone_data.prefix,
162@@ -1867,7 +1869,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
163 OPT_STRING(0, "url", &clone_data.url,
164 N_("string"),
165 N_("url where to clone the submodule from")),
166- OPT_STRING_LIST(0, "reference", &clone_data.reference,
167+ OPT_STRING_LIST(0, "reference", &reference,
168 N_("repo"),
169 N_("reference repository")),
170 OPT_BOOL(0, "dissociate", &dissociate,
171@@ -1905,7 +1907,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
172 usage_with_options(git_submodule_helper_usage,
173 module_clone_options);
174
175- clone_submodule(&clone_data);
176+ clone_submodule(&clone_data, &reference);
177 return 0;
178 }
179
180@@ -3029,6 +3031,7 @@ static int add_submodule(const struct add_data *add_data)
181 {
182 char *submod_gitdir_path;
183 struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
184+ struct string_list reference = STRING_LIST_INIT_NODUP;
185
186 /* perhaps the path already exists and is already a git repo, else clone it */
187 if (is_directory(add_data->sm_path)) {
188@@ -3045,6 +3048,7 @@ static int add_submodule(const struct add_data *add_data)
189 free(submod_gitdir_path);
190 } else {
191 struct child_process cp = CHILD_PROCESS_INIT;
192+
193 submod_gitdir_path = xstrfmt(".git/modules/%s", add_data->sm_name);
194
195 if (is_directory(submod_gitdir_path)) {
196@@ -3084,13 +3088,13 @@ static int add_submodule(const struct add_data *add_data)
197 clone_data.quiet = add_data->quiet;
198 clone_data.progress = add_data->progress;
199 if (add_data->reference_path)
200- string_list_append(&clone_data.reference,
201+ string_list_append(&reference,
202 xstrdup(add_data->reference_path));
203 clone_data.dissociate = add_data->dissociate;
204 if (add_data->depth >= 0)
205 clone_data.depth = xstrfmt("%d", add_data->depth);
206
207- if (clone_submodule(&clone_data))
208+ if (clone_submodule(&clone_data, &reference))
209 return -1;
210
211 prepare_submodule_repo_env(&cp.env_array);
212--
2132.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch
new file mode 100644
index 0000000000..bb5702e122
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch
@@ -0,0 +1,141 @@
1From e77b3da6bb60e9af5963c9e42442afe53af1780b Mon Sep 17 00:00:00 2001
2From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
3Date: Thu, 1 Sep 2022 01:14:08 +0200
4Subject: [PATCH] submodule--helper: fix a leak in "clone_submodule"
5
6Fix a memory leak of the "clone_data_path" variable that we copy or
7derive from the "struct module_clone_data" in clone_submodule(). This
8code was refactored in preceding commits, but the leak has been with
9us since f8eaa0ba98b (submodule--helper, module_clone: always operate
10on absolute paths, 2016-03-31).
11
12For the "else" case we don't need to xstrdup() the "clone_data->path",
13and we don't need to free our own "clone_data_path". We can therefore
14assign the "clone_data->path" to our own "clone_data_path" right away,
15and only override it (and remember to free it!) if we need to
16xstrfmt() a replacement.
17
18In the case of the module_clone() caller it's from "argv", and doesn't
19need to be free'd, and in the case of the add_submodule() caller we
20get a pointer to "sm_path", which doesn't need to be directly free'd
21either.
22
23Fixing this leak makes several tests pass, so let's mark them as
24passing with TEST_PASSES_SANITIZE_LEAK=true.
25
26Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
27Reviewed-by: Glen Choo <chooglen@google.com>
28Signed-off-by: Junio C Hamano <gitster@pobox.com>
29
30CVE: CVE-2024-32002
31
32Upstream-Status: Backport [https://github.com/git/git/commit/e77b3da6bb60e9af5963c9e42442afe53af1780b]
33
34Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
35---
36 builtin/submodule--helper.c | 10 +++++-----
37 t/t1500-rev-parse.sh | 1 +
38 t/t6008-rev-list-submodule.sh | 1 +
39 t/t7414-submodule-mistakes.sh | 2 ++
40 t/t7506-status-submodule.sh | 1 +
41 t/t7507-commit-verbose.sh | 2 ++
42 6 files changed, 12 insertions(+), 5 deletions(-)
43
44diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
45index d1d64db..1158dcc 100644
46--- a/builtin/submodule--helper.c
47+++ b/builtin/submodule--helper.c
48@@ -1756,17 +1756,16 @@ static int clone_submodule(const struct module_clone_data *clone_data,
49 char *sm_alternate = NULL, *error_strategy = NULL;
50 struct strbuf sb = STRBUF_INIT;
51 struct child_process cp = CHILD_PROCESS_INIT;
52- const char *clone_data_path;
53+ const char *clone_data_path = clone_data->path;
54+ char *to_free = NULL;;
55
56 submodule_name_to_gitdir(&sb, the_repository, clone_data->name);
57 sm_gitdir = absolute_pathdup(sb.buf);
58 strbuf_reset(&sb);
59
60 if (!is_absolute_path(clone_data->path))
61- clone_data_path = xstrfmt("%s/%s", get_git_work_tree(),
62- clone_data->path);
63- else
64- clone_data_path = xstrdup(clone_data->path);
65+ clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(),
66+ clone_data->path);
67
68 if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
69 die(_("refusing to create/use '%s' in another submodule's "
70@@ -1847,6 +1846,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
71 strbuf_release(&sb);
72 free(sm_gitdir);
73 free(p);
74+ free(to_free);
75 return 0;
76 }
77
78diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
79index 2c429f9..81de584 100755
80--- a/t/t1500-rev-parse.sh
81+++ b/t/t1500-rev-parse.sh
82@@ -4,6 +4,7 @@ test_description='test git rev-parse'
83 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
84 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
85
86+TEST_PASSES_SANITIZE_LEAK=true
87 . ./test-lib.sh
88
89 test_one () {
90diff --git a/t/t6008-rev-list-submodule.sh b/t/t6008-rev-list-submodule.sh
91index a0a070b..2cdef6f 100755
92--- a/t/t6008-rev-list-submodule.sh
93+++ b/t/t6008-rev-list-submodule.sh
94@@ -8,6 +8,7 @@ test_description='git rev-list involving submodules that this repo has'
95 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
96 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
97
98+TEST_PASSES_SANITIZE_LEAK=true
99 . ./test-lib.sh
100
101 test_expect_success 'setup' '
102diff --git a/t/t7414-submodule-mistakes.sh b/t/t7414-submodule-mistakes.sh
103index cf95603..101afff 100755
104--- a/t/t7414-submodule-mistakes.sh
105+++ b/t/t7414-submodule-mistakes.sh
106@@ -1,6 +1,8 @@
107 #!/bin/sh
108
109 test_description='handling of common mistakes people may make with submodules'
110+
111+TEST_PASSES_SANITIZE_LEAK=true
112 . ./test-lib.sh
113
114 test_expect_success 'create embedded repository' '
115diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
116index 459300c..d050091 100755
117--- a/t/t7506-status-submodule.sh
118+++ b/t/t7506-status-submodule.sh
119@@ -2,6 +2,7 @@
120
121 test_description='git status for submodule'
122
123+TEST_PASSES_SANITIZE_LEAK=true
124 . ./test-lib.sh
125
126 test_create_repo_with_commit () {
127diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh
128index bd0ae4b..916470c 100755
129--- a/t/t7507-commit-verbose.sh
130+++ b/t/t7507-commit-verbose.sh
131@@ -1,6 +1,8 @@
132 #!/bin/sh
133
134 test_description='verbose commit template'
135+
136+TEST_PASSES_SANITIZE_LEAK=true
137 . ./test-lib.sh
138
139 write_script "check-for-diff" <<\EOF &&
140--
1412.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch
new file mode 100644
index 0000000000..f2af2b48de
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch
@@ -0,0 +1,150 @@
1From 97065761333fd62db1912d81b489db938d8c991d Mon Sep 17 00:00:00 2001
2From: Johannes Schindelin <johannes.schindelin@gmx.de>
3Date: Fri, 22 Mar 2024 11:19:22 +0100
4Subject: [PATCH] submodules: submodule paths must not contain symlinks
5
6When creating a submodule path, we must be careful not to follow
7symbolic links. Otherwise we may follow a symbolic link pointing to
8a gitdir (which are valid symbolic links!) e.g. while cloning.
9
10On case-insensitive filesystems, however, we blindly replace a directory
11that has been created as part of the `clone` operation with a symlink
12when the path to the latter differs only in case from the former's path.
13
14Let's simply avoid this situation by expecting not ever having to
15overwrite any existing file/directory/symlink upon cloning. That way, we
16won't even replace a directory that we just created.
17
18This addresses CVE-2024-32002.
19
20Reported-by: Filip Hejsek <filip.hejsek@gmail.com>
21Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
22
23CVE: CVE-2024-32002
24
25Upstream-Status: Backport [https://github.com/git/git/commit/97065761333fd62db1912d81b489db938d8c991d]
26
27Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
28---
29 builtin/submodule--helper.c | 35 +++++++++++++++++++++++++++++++
30 t/t7406-submodule-update.sh | 42 +++++++++++++++++++++++++++++++++++++
31 2 files changed, 77 insertions(+)
32
33diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
34index 1158dcc..d4147d8 100644
35--- a/builtin/submodule--helper.c
36+++ b/builtin/submodule--helper.c
37@@ -1749,11 +1749,34 @@ static void prepare_possible_alternates(const char *sm_name,
38 free(error_strategy);
39 }
40
41+static int dir_contains_only_dotgit(const char *path)
42+{
43+ DIR *dir = opendir(path);
44+ struct dirent *e;
45+ int ret = 1;
46+
47+ if (!dir)
48+ return 0;
49+
50+ e = readdir_skip_dot_and_dotdot(dir);
51+ if (!e)
52+ ret = 0;
53+ else if (strcmp(DEFAULT_GIT_DIR_ENVIRONMENT, e->d_name) ||
54+ (e = readdir_skip_dot_and_dotdot(dir))) {
55+ error("unexpected item '%s' in '%s'", e->d_name, path);
56+ ret = 0;
57+ }
58+
59+ closedir(dir);
60+ return ret;
61+}
62+
63 static int clone_submodule(const struct module_clone_data *clone_data,
64 struct string_list *reference)
65 {
66 char *p, *sm_gitdir;
67 char *sm_alternate = NULL, *error_strategy = NULL;
68+ struct stat st;
69 struct strbuf sb = STRBUF_INIT;
70 struct child_process cp = CHILD_PROCESS_INIT;
71 const char *clone_data_path = clone_data->path;
72@@ -1772,6 +1795,10 @@ static int clone_submodule(const struct module_clone_data *clone_data,
73 "git dir"), sm_gitdir);
74
75 if (!file_exists(sm_gitdir)) {
76+ if (clone_data->require_init && !stat(clone_data_path, &st) &&
77+ !is_empty_dir(clone_data_path))
78+ die(_("directory not empty: '%s'"), clone_data_path);
79+
80 if (safe_create_leading_directories_const(sm_gitdir) < 0)
81 die(_("could not create directory '%s'"), sm_gitdir);
82
83@@ -1811,6 +1838,14 @@ static int clone_submodule(const struct module_clone_data *clone_data,
84 if(run_command(&cp))
85 die(_("clone of '%s' into submodule path '%s' failed"),
86 clone_data->url, clone_data_path);
87+
88+ if (clone_data->require_init && !stat(clone_data_path, &st) &&
89+ !dir_contains_only_dotgit(clone_data_path)) {
90+ char *dot_git = xstrfmt("%s/.git", clone_data_path);
91+ unlink(dot_git);
92+ free(dot_git);
93+ die(_("directory not empty: '%s'"), clone_data_path);
94+ }
95 } else {
96 char *path;
97
98diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
99index 53d419c..00ffdb6 100755
100--- a/t/t7406-submodule-update.sh
101+++ b/t/t7406-submodule-update.sh
102@@ -1062,4 +1062,46 @@ test_expect_success 'submodule update --quiet passes quietness to fetch with a s
103 )
104 '
105
106+test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \
107+ 'submodule paths must not follow symlinks' '
108+ # This is only needed because we want to run this in a self-contained
109+ # test without having to spin up an HTTP server; However, it would not
110+ # be needed in a real-world scenario where the submodule is simply
111+ # hosted on a public site.
112+ test_config_global protocol.file.allow always &&
113+ # Make sure that Git tries to use symlinks on Windows
114+ test_config_global core.symlinks true &&
115+ tell_tale_path="$PWD/tell.tale" &&
116+ git init hook &&
117+ (
118+ cd hook &&
119+ mkdir -p y/hooks &&
120+ write_script y/hooks/post-checkout <<-EOF &&
121+ echo HOOK-RUN >&2
122+ echo hook-run >"$tell_tale_path"
123+ EOF
124+ git add y/hooks/post-checkout &&
125+ test_tick &&
126+ git commit -m post-checkout
127+ ) &&
128+ hook_repo_path="$(pwd)/hook" &&
129+ git init captain &&
130+ (
131+ cd captain &&
132+ git submodule add --name x/y "$hook_repo_path" A/modules/x &&
133+ test_tick &&
134+ git commit -m add-submodule &&
135+ printf .git >dotgit.txt &&
136+ git hash-object -w --stdin <dotgit.txt >dot-git.hash &&
137+ printf "120000 %s 0\ta\n" "$(cat dot-git.hash)" >index.info &&
138+ git update-index --index-info <index.info &&
139+ test_tick &&
140+ git commit -m add-symlink
141+ ) &&
142+ test_path_is_missing "$tell_tale_path" &&
143+ test_must_fail git clone --recursive captain hooked 2>err &&
144+ grep "directory not empty" err &&
145+ test_path_is_missing "$tell_tale_path"
146+'
147+
148 test_done
149--
1502.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch b/meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch
new file mode 100644
index 0000000000..410f3bc5e1
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch
@@ -0,0 +1,95 @@
1From 5c5a4a1c05932378d259b1fdd9526cab971656a2 Mon Sep 17 00:00:00 2001
2From: Filip Hejsek <filip.hejsek@gmail.com>
3Date: Sun, 28 Jan 2024 04:29:33 +0100
4Subject: [PATCH] t0411: add tests for cloning from partial repo
5
6Cloning from a partial repository must not fetch missing objects into
7the partial repository, because that can lead to arbitrary code
8execution.
9
10Add a couple of test cases, pretending to the `upload-pack` command (and
11to that command only) that it is working on a repository owned by
12someone else.
13
14Helped-by: Jeff King <peff@peff.net>
15Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com>
16Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
17
18CVE: CVE-2024-32004
19
20Upstream-Status: Backport [https://github.com/git/git/commit/5c5a4a1c05932378d259b1fdd9526cab971656a2]
21
22Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
23---
24 t/t0411-clone-from-partial.sh | 60 +++++++++++++++++++++++++++++++++++
25 1 file changed, 60 insertions(+)
26 create mode 100755 t/t0411-clone-from-partial.sh
27
28diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
29new file mode 100755
30index 0000000..fb72a0a
31--- /dev/null
32+++ b/t/t0411-clone-from-partial.sh
33@@ -0,0 +1,60 @@
34+#!/bin/sh
35+
36+test_description='check that local clone does not fetch from promisor remotes'
37+
38+. ./test-lib.sh
39+
40+test_expect_success 'create evil repo' '
41+ git init tmp &&
42+ test_commit -C tmp a &&
43+ git -C tmp config uploadpack.allowfilter 1 &&
44+ git clone --filter=blob:none --no-local --no-checkout tmp evil &&
45+ rm -rf tmp &&
46+
47+ git -C evil config remote.origin.uploadpack \"\$TRASH_DIRECTORY/fake-upload-pack\" &&
48+ write_script fake-upload-pack <<-\EOF &&
49+ echo >&2 "fake-upload-pack running"
50+ >"$TRASH_DIRECTORY/script-executed"
51+ exit 1
52+ EOF
53+ export TRASH_DIRECTORY &&
54+
55+ # empty shallow file disables local clone optimization
56+ >evil/.git/shallow
57+'
58+
59+test_expect_failure 'local clone must not fetch from promisor remote and execute script' '
60+ rm -f script-executed &&
61+ test_must_fail git clone \
62+ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
63+ evil clone1 2>err &&
64+ ! grep "fake-upload-pack running" err &&
65+ test_path_is_missing script-executed
66+'
67+
68+test_expect_failure 'clone from file://... must not fetch from promisor remote and execute script' '
69+ rm -f script-executed &&
70+ test_must_fail git clone \
71+ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
72+ "file://$(pwd)/evil" clone2 2>err &&
73+ ! grep "fake-upload-pack running" err &&
74+ test_path_is_missing script-executed
75+'
76+
77+test_expect_failure 'fetch from file://... must not fetch from promisor remote and execute script' '
78+ rm -f script-executed &&
79+ test_must_fail git fetch \
80+ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
81+ "file://$(pwd)/evil" 2>err &&
82+ ! grep "fake-upload-pack running" err &&
83+ test_path_is_missing script-executed
84+'
85+
86+test_expect_success 'pack-objects should fetch from promisor remote and execute script' '
87+ rm -f script-executed &&
88+ echo "HEAD" | test_must_fail git -C evil pack-objects --revs --stdout >/dev/null 2>err &&
89+ grep "fake-upload-pack running" err &&
90+ test_path_is_file script-executed
91+'
92+
93+test_done
94--
952.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch b/meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch
new file mode 100644
index 0000000000..1727f81950
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch
@@ -0,0 +1,187 @@
1From 17d3883fe9c88b823002ad9fafb42313ddc3d3d5 Mon Sep 17 00:00:00 2001
2From: Johannes Schindelin <johannes.schindelin@gmx.de>
3Date: Mon, 8 Aug 2022 13:27:47 +0000
4Subject: [PATCH] setup: prepare for more detailed "dubious ownership" messages
5
6When verifying the ownership of the Git directory, we sometimes would
7like to say a bit more about it, e.g. when using a platform-dependent
8code path (think: Windows has the permission model that is so different
9from Unix'), but only when it is a appropriate to actually say
10something.
11
12To allow for that, collect that information and hand it back to the
13caller (whose responsibility it is to show it or not).
14
15Note: We do not actually fill in any platform-dependent information yet,
16this commit just adds the infrastructure to be able to do so.
17
18Based-on-an-idea-by: Junio C Hamano <gitster@pobox.com>
19Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
20Signed-off-by: Junio C Hamano <gitster@pobox.com>
21
22CVE: CVE-2024-32004
23
24Upstream-Status: Backport [https://github.com/git/git/commit/17d3883fe9c88b823002ad9fafb42313ddc3d3d5]
25
26Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
27---
28 compat/mingw.c | 2 +-
29 compat/mingw.h | 2 +-
30 git-compat-util.h | 5 ++++-
31 setup.c | 25 +++++++++++++++----------
32 4 files changed, 21 insertions(+), 13 deletions(-)
33
34diff --git a/compat/mingw.c b/compat/mingw.c
35index 41fc163..9306a0e 100644
36--- a/compat/mingw.c
37+++ b/compat/mingw.c
38@@ -2658,7 +2658,7 @@ static PSID get_current_user_sid(void)
39 return result;
40 }
41
42-int is_path_owned_by_current_sid(const char *path)
43+int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
44 {
45 WCHAR wpath[MAX_PATH];
46 PSID sid = NULL;
47diff --git a/compat/mingw.h b/compat/mingw.h
48index ffa53a4..a1a69c5 100644
49--- a/compat/mingw.h
50+++ b/compat/mingw.h
51@@ -457,7 +457,7 @@ char *mingw_query_user_email(void);
52 * Verifies that the specified path is owned by the user running the
53 * current process.
54 */
55-int is_path_owned_by_current_sid(const char *path);
56+int is_path_owned_by_current_sid(const char *path, struct strbuf *report);
57 #define is_path_owned_by_current_user is_path_owned_by_current_sid
58
59 /**
60diff --git a/git-compat-util.h b/git-compat-util.h
61index 1c651c8..27b84b8 100644
62--- a/git-compat-util.h
63+++ b/git-compat-util.h
64@@ -23,6 +23,9 @@
65 #include <crtdbg.h>
66 #endif
67
68+struct strbuf;
69+
70+
71 #define _FILE_OFFSET_BITS 64
72
73
74@@ -475,7 +478,7 @@ static inline void extract_id_from_env(const char *env, uid_t *id)
75 }
76 }
77
78-static inline int is_path_owned_by_current_uid(const char *path)
79+static inline int is_path_owned_by_current_uid(const char *path, struct strbuf *report)
80 {
81 struct stat st;
82 uid_t euid;
83diff --git a/setup.c b/setup.c
84index 8686ffe..1ad7330 100644
85--- a/setup.c
86+++ b/setup.c
87@@ -1128,16 +1128,17 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
88 * added, for bare ones their git directory.
89 */
90 static int ensure_valid_ownership(const char *gitfile,
91- const char *worktree, const char *gitdir)
92+ const char *worktree, const char *gitdir,
93+ struct strbuf *report)
94 {
95 struct safe_directory_data data = {
96 .path = worktree ? worktree : gitdir
97 };
98
99 if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
100- (!gitfile || is_path_owned_by_current_user(gitfile)) &&
101- (!worktree || is_path_owned_by_current_user(worktree)) &&
102- (!gitdir || is_path_owned_by_current_user(gitdir)))
103+ (!gitfile || is_path_owned_by_current_user(gitfile, report)) &&
104+ (!worktree || is_path_owned_by_current_user(worktree, report)) &&
105+ (!gitdir || is_path_owned_by_current_user(gitdir, report)))
106 return 1;
107
108 /*
109@@ -1177,6 +1178,7 @@ enum discovery_result {
110 */
111 static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
112 struct strbuf *gitdir,
113+ struct strbuf *report,
114 int die_on_error)
115 {
116 const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
117@@ -1264,7 +1266,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
118
119 if (ensure_valid_ownership(gitfile,
120 dir->buf,
121- (gitdir_path ? gitdir_path : gitdirenv))) {
122+ (gitdir_path ? gitdir_path : gitdirenv), report)) {
123 strbuf_addstr(gitdir, gitdirenv);
124 ret = GIT_DIR_DISCOVERED;
125 } else
126@@ -1287,7 +1289,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
127 }
128
129 if (is_git_directory(dir->buf)) {
130- if (!ensure_valid_ownership(NULL, NULL, dir->buf))
131+ if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
132 return GIT_DIR_INVALID_OWNERSHIP;
133 strbuf_addstr(gitdir, ".");
134 return GIT_DIR_BARE;
135@@ -1320,7 +1322,7 @@ int discover_git_directory(struct strbuf *commondir,
136 return -1;
137
138 cwd_len = dir.len;
139- if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
140+ if (setup_git_directory_gently_1(&dir, gitdir, NULL, 0) <= 0) {
141 strbuf_release(&dir);
142 return -1;
143 }
144@@ -1367,7 +1369,7 @@ int discover_git_directory(struct strbuf *commondir,
145 const char *setup_git_directory_gently(int *nongit_ok)
146 {
147 static struct strbuf cwd = STRBUF_INIT;
148- struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
149+ struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
150 const char *prefix = NULL;
151 struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
152
153@@ -1392,7 +1394,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
154 die_errno(_("Unable to read current working directory"));
155 strbuf_addbuf(&dir, &cwd);
156
157- switch (setup_git_directory_gently_1(&dir, &gitdir, 1)) {
158+ switch (setup_git_directory_gently_1(&dir, &gitdir, &report, 1)) {
159 case GIT_DIR_EXPLICIT:
160 prefix = setup_explicit_git_dir(gitdir.buf, &cwd, &repo_fmt, nongit_ok);
161 break;
162@@ -1424,12 +1426,14 @@ const char *setup_git_directory_gently(int *nongit_ok)
163 if (!nongit_ok) {
164 struct strbuf quoted = STRBUF_INIT;
165
166+ strbuf_complete(&report, '\n');
167 sq_quote_buf_pretty(&quoted, dir.buf);
168 die(_("detected dubious ownership in repository at '%s'\n"
169+ "%s"
170 "To add an exception for this directory, call:\n"
171 "\n"
172 "\tgit config --global --add safe.directory %s"),
173- dir.buf, quoted.buf);
174+ dir.buf, report.buf, quoted.buf);
175 }
176 *nongit_ok = 1;
177 break;
178@@ -1508,6 +1512,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
179
180 strbuf_release(&dir);
181 strbuf_release(&gitdir);
182+ strbuf_release(&report);
183 clear_repository_format(&repo_fmt);
184
185 return prefix;
186--
1872.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch b/meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch
new file mode 100644
index 0000000000..08ca1e596d
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch
@@ -0,0 +1,158 @@
1From f4aa8c8bb11dae6e769cd930565173808cbb69c8 Mon Sep 17 00:00:00 2001
2From: Johannes Schindelin <johannes.schindelin@gmx.de>
3Date: Wed, 10 Apr 2024 14:39:37 +0200
4Subject: [PATCH] fetch/clone: detect dubious ownership of local repositories
5
6When cloning from somebody else's repositories, it is possible that,
7say, the `upload-pack` command is overridden in the repository that is
8about to be cloned, which would then be run in the user's context who
9started the clone.
10
11To remind the user that this is a potentially unsafe operation, let's
12extend the ownership checks we have already established for regular
13gitdir discovery to extend also to local repositories that are about to
14be cloned.
15
16This protection extends also to file:// URLs.
17
18The fixes in this commit address CVE-2024-32004.
19
20Note: This commit does not touch the `fetch`/`clone` code directly, but
21instead the function used implicitly by both: `enter_repo()`. This
22function is also used by `git receive-pack` (i.e. pushes), by `git
23upload-archive`, by `git daemon` and by `git http-backend`. In setups
24that want to serve repositories owned by different users than the
25account running the service, this will require `safe.*` settings to be
26configured accordingly.
27
28Also note: there are tiny time windows where a time-of-check-time-of-use
29("TOCTOU") race is possible. The real solution to those would be to work
30with `fstat()` and `openat()`. However, the latter function is not
31available on Windows (and would have to be emulated with rather
32expensive low-level `NtCreateFile()` calls), and the changes would be
33quite extensive, for my taste too extensive for the little gain given
34that embargoed releases need to pay extra attention to avoid introducing
35inadvertent bugs.
36
37Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
38
39CVE: CVE-2024-32004
40
41Upstream-Status: Backport [https://github.com/git/git/commit/f4aa8c8bb11dae6e769cd930565173808cbb69c8]
42
43Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
44---
45 cache.h | 12 ++++++++++++
46 path.c | 2 ++
47 setup.c | 21 +++++++++++++++++++++
48 t/t0411-clone-from-partial.sh | 6 +++---
49 4 files changed, 38 insertions(+), 3 deletions(-)
50
51diff --git a/cache.h b/cache.h
52index 281f00a..a59bdbe 100644
53--- a/cache.h
54+++ b/cache.h
55@@ -615,6 +615,18 @@ void set_git_work_tree(const char *tree);
56
57 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
58
59+/*
60+ * Check if a repository is safe and die if it is not, by verifying the
61+ * ownership of the worktree (if any), the git directory, and the gitfile (if
62+ * any).
63+ *
64+ * Exemptions for known-safe repositories can be added via `safe.directory`
65+ * config settings; for non-bare repositories, their worktree needs to be
66+ * added, for bare ones their git directory.
67+ */
68+void die_upon_dubious_ownership(const char *gitfile, const char *worktree,
69+ const char *gitdir);
70+
71 void setup_work_tree(void);
72 /*
73 * Find the commondir and gitdir of the repository that contains the current
74diff --git a/path.c b/path.c
75index d73146b..ae1fb01 100644
76--- a/path.c
77+++ b/path.c
78@@ -840,6 +840,7 @@ const char *enter_repo(const char *path, int strict)
79 if (!suffix[i])
80 return NULL;
81 gitfile = read_gitfile(used_path.buf);
82+ die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
83 if (gitfile) {
84 strbuf_reset(&used_path);
85 strbuf_addstr(&used_path, gitfile);
86@@ -850,6 +851,7 @@ const char *enter_repo(const char *path, int strict)
87 }
88 else {
89 const char *gitfile = read_gitfile(path);
90+ die_upon_dubious_ownership(gitfile, NULL, path);
91 if (gitfile)
92 path = gitfile;
93 if (chdir(path))
94diff --git a/setup.c b/setup.c
95index 1ad7330..475c92e 100644
96--- a/setup.c
97+++ b/setup.c
98@@ -1151,6 +1151,27 @@ static int ensure_valid_ownership(const char *gitfile,
99 return data.is_safe;
100 }
101
102+void die_upon_dubious_ownership(const char *gitfile, const char *worktree,
103+ const char *gitdir)
104+{
105+ struct strbuf report = STRBUF_INIT, quoted = STRBUF_INIT;
106+ const char *path;
107+
108+ if (ensure_valid_ownership(gitfile, worktree, gitdir, &report))
109+ return;
110+
111+ strbuf_complete(&report, '\n');
112+ path = gitfile ? gitfile : gitdir;
113+ sq_quote_buf_pretty(&quoted, path);
114+
115+ die(_("detected dubious ownership in repository at '%s'\n"
116+ "%s"
117+ "To add an exception for this directory, call:\n"
118+ "\n"
119+ "\tgit config --global --add safe.directory %s"),
120+ path, report.buf, quoted.buf);
121+}
122+
123 enum discovery_result {
124 GIT_DIR_NONE = 0,
125 GIT_DIR_EXPLICIT,
126diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
127index fb72a0a..eb3360d 100755
128--- a/t/t0411-clone-from-partial.sh
129+++ b/t/t0411-clone-from-partial.sh
130@@ -23,7 +23,7 @@ test_expect_success 'create evil repo' '
131 >evil/.git/shallow
132 '
133
134-test_expect_failure 'local clone must not fetch from promisor remote and execute script' '
135+test_expect_success 'local clone must not fetch from promisor remote and execute script' '
136 rm -f script-executed &&
137 test_must_fail git clone \
138 --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
139@@ -32,7 +32,7 @@ test_expect_failure 'local clone must not fetch from promisor remote and execute
140 test_path_is_missing script-executed
141 '
142
143-test_expect_failure 'clone from file://... must not fetch from promisor remote and execute script' '
144+test_expect_success 'clone from file://... must not fetch from promisor remote and execute script' '
145 rm -f script-executed &&
146 test_must_fail git clone \
147 --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
148@@ -41,7 +41,7 @@ test_expect_failure 'clone from file://... must not fetch from promisor remote a
149 test_path_is_missing script-executed
150 '
151
152-test_expect_failure 'fetch from file://... must not fetch from promisor remote and execute script' '
153+test_expect_success 'fetch from file://... must not fetch from promisor remote and execute script' '
154 rm -f script-executed &&
155 test_must_fail git fetch \
156 --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
157--
1582.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32020.patch b/meta/recipes-devtools/git/git/CVE-2024-32020.patch
new file mode 100644
index 0000000000..4dfe742ff7
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32020.patch
@@ -0,0 +1,114 @@
1From 1204e1a824c34071019fe106348eaa6d88f9528d Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Mon, 15 Apr 2024 13:30:41 +0200
4Subject: [PATCH] builtin/clone: refuse local clones of unsafe repositories
5
6When performing a local clone of a repository we end up either copying
7or hardlinking the source repository into the target repository. This is
8significantly more performant than if we were to use git-upload-pack(1)
9and git-fetch-pack(1) to create the new repository and preserves both
10disk space and compute time.
11
12Unfortunately though, performing such a local clone of a repository that
13is not owned by the current user is inherently unsafe:
14
15 - It is possible that source files get swapped out underneath us while
16 we are copying or hardlinking them. While we do perform some checks
17 here to assert that we hardlinked the expected file, they cannot
18 reliably thwart time-of-check-time-of-use (TOCTOU) style races. It
19 is thus possible for an adversary to make us copy or hardlink
20 unexpected files into the target directory.
21
22 Ideally, we would address this by starting to use openat(3P),
23 fstatat(3P) and friends. Due to platform compatibility with Windows
24 we cannot easily do that though. Furthermore, the scope of these
25 fixes would likely be quite broad and thus not fit for an embargoed
26 security release.
27
28 - Even if we handled TOCTOU-style races perfectly, hardlinking files
29 owned by a different user into the target repository is not a good
30 idea in general. It is possible for an adversary to rewrite those
31 files to contain whatever data they want even after the clone has
32 completed.
33
34Address these issues by completely refusing local clones of a repository
35that is not owned by the current user. This reuses our existing infra we
36have in place via `ensure_valid_ownership()` and thus allows a user to
37override the safety guard by adding the source repository path to the
38"safe.directory" configuration.
39
40This addresses CVE-2024-32020.
41
42Signed-off-by: Patrick Steinhardt <ps@pks.im>
43Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
44
45CVE: CVE-2024-32020
46
47Upstream-Status: Backport [https://github.com/git/git/commit/1204e1a824c34071019fe106348eaa6d88f9528d]
48
49Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
50---
51 builtin/clone.c | 14 ++++++++++++++
52 t/t0033-safe-directory.sh | 24 ++++++++++++++++++++++++
53 2 files changed, 38 insertions(+)
54
55diff --git a/builtin/clone.c b/builtin/clone.c
56index 4541a55..11f6b4b 100644
57--- a/builtin/clone.c
58+++ b/builtin/clone.c
59@@ -312,6 +312,20 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
60 int iter_status;
61 struct strbuf realpath = STRBUF_INIT;
62
63+ /*
64+ * Refuse copying directories by default which aren't owned by us. The
65+ * code that performs either the copying or hardlinking is not prepared
66+ * to handle various edge cases where an adversary may for example
67+ * racily swap out files for symlinks. This can cause us to
68+ * inadvertently use the wrong source file.
69+ *
70+ * Furthermore, even if we were prepared to handle such races safely,
71+ * creating hardlinks across user boundaries is an inherently unsafe
72+ * operation as the hardlinked files can be rewritten at will by the
73+ * potentially-untrusted user. We thus refuse to do so by default.
74+ */
75+ die_upon_dubious_ownership(NULL, NULL, src_repo);
76+
77 mkdir_if_missing(dest->buf, 0777);
78
79 iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
80diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
81index 239d93f..751cba5 100755
82--- a/t/t0033-safe-directory.sh
83+++ b/t/t0033-safe-directory.sh
84@@ -46,4 +46,28 @@ test_expect_success 'safe.directory=*, but is reset' '
85 expect_rejected_dir
86 '
87
88+test_expect_success 'local clone of unowned repo refused in unsafe directory' '
89+ test_when_finished "rm -rf source" &&
90+ git init source &&
91+ (
92+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
93+ test_commit -C source initial
94+ ) &&
95+ test_must_fail git clone --local source target &&
96+ test_path_is_missing target
97+'
98+
99+test_expect_success 'local clone of unowned repo accepted in safe directory' '
100+ test_when_finished "rm -rf source" &&
101+ git init source &&
102+ (
103+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
104+ test_commit -C source initial
105+ ) &&
106+ test_must_fail git clone --local source target &&
107+ git config --global --add safe.directory "$(pwd)/source/.git" &&
108+ git clone --local source target &&
109+ test_path_is_dir target
110+'
111+
112 test_done
113--
1142.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch b/meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch
new file mode 100644
index 0000000000..cc33c54faa
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch
@@ -0,0 +1,89 @@
1From 150e6b0aedf57d224c3c49038c306477fa159886 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Mon, 15 Apr 2024 13:30:26 +0200
4Subject: [PATCH] builtin/clone: stop resolving symlinks when copying files
5
6When a user performs a local clone without `--no-local`, then we end up
7copying the source repository into the target repository directly. To
8optimize this even further, we try to hardlink files into place instead
9of copying data over, which helps both disk usage and speed.
10
11There is an important edge case in this context though, namely when we
12try to hardlink symlinks from the source repository into the target
13repository. Depending on both platform and filesystem the resulting
14behaviour here can be different:
15
16 - On macOS and NetBSD, calling link(3P) with a symlink target creates
17 a hardlink to the file pointed to by the symlink.
18
19 - On Linux, calling link(3P) instead creates a hardlink to the symlink
20 itself.
21
22To unify this behaviour, 36596fd2df (clone: better handle symlinked
23files at .git/objects/, 2019-07-10) introduced logic to resolve symlinks
24before we try to link(3P) files. Consequently, the new behaviour was to
25always create a hard link to the target of the symlink on all platforms.
26
27Eventually though, we figured out that following symlinks like this can
28cause havoc when performing a local clone of a malicious repository,
29which resulted in CVE-2022-39253. This issue was fixed via 6f054f9fb3
30(builtin/clone.c: disallow `--local` clones with symlinks, 2022-07-28),
31by refusing symlinks in the source repository.
32
33But even though we now shouldn't ever link symlinks anymore, the code
34that resolves symlinks still exists. In the best case the code does not
35end up doing anything because there are no symlinks anymore. In the
36worst case though this can be abused by an adversary that rewrites the
37source file after it has been checked not to be a symlink such that it
38actually is a symlink when we call link(3P). Thus, it is still possible
39to recreate CVE-2022-39253 due to this time-of-check-time-of-use bug.
40
41Remove the call to `realpath()`. This doesn't yet address the actual
42vulnerability, which will be handled in a subsequent commit.
43
44Reported-by: Apple Product Security <product-security@apple.com>
45Signed-off-by: Patrick Steinhardt <ps@pks.im>
46Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
47
48CVE: CVE-2024-32021
49
50Upstream-Status: Backport [https://github.com/git/git/commit/150e6b0aedf57d224c3c49038c306477fa159886]
51
52Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
53---
54 builtin/clone.c | 6 +-----
55 1 file changed, 1 insertion(+), 5 deletions(-)
56
57diff --git a/builtin/clone.c b/builtin/clone.c
58index 11f6b4b..2778d20 100644
59--- a/builtin/clone.c
60+++ b/builtin/clone.c
61@@ -310,7 +310,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
62 int src_len, dest_len;
63 struct dir_iterator *iter;
64 int iter_status;
65- struct strbuf realpath = STRBUF_INIT;
66
67 /*
68 * Refuse copying directories by default which aren't owned by us. The
69@@ -362,8 +361,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
70 if (unlink(dest->buf) && errno != ENOENT)
71 die_errno(_("failed to unlink '%s'"), dest->buf);
72 if (!option_no_hardlinks) {
73- strbuf_realpath(&realpath, src->buf, 1);
74- if (!link(realpath.buf, dest->buf))
75+ if (!link(src->buf, dest->buf))
76 continue;
77 if (option_local > 0)
78 die_errno(_("failed to create link '%s'"), dest->buf);
79@@ -377,8 +375,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
80 strbuf_setlen(src, src_len);
81 die(_("failed to iterate over '%s'"), src->buf);
82 }
83-
84- strbuf_release(&realpath);
85 }
86
87 static void clone_local(const char *src_repo, const char *dest_repo)
88--
892.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch b/meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch
new file mode 100644
index 0000000000..2151d3d0ea
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch
@@ -0,0 +1,65 @@
1From d1bb66a546b4bb46005d17ba711caaad26f26c1e Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Mon, 15 Apr 2024 13:30:31 +0200
4Subject: [PATCH] builtin/clone: abort when hardlinked source and target file
5 differ
6
7When performing local clones with hardlinks we refuse to copy source
8files which are symlinks as a mitigation for CVE-2022-39253. This check
9can be raced by an adversary though by changing the file to a symlink
10after we have checked it.
11
12Fix the issue by checking whether the hardlinked destination file
13matches the source file and abort in case it doesn't.
14
15This addresses CVE-2024-32021.
16
17Reported-by: Apple Product Security <product-security@apple.com>
18Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
19Signed-off-by: Patrick Steinhardt <ps@pks.im>
20Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
21
22CVE: CVE-2024-32021
23
24Upstream-Status: Backport [https://github.com/git/git/commit/d1bb66a546b4bb46005d17ba711caaad26f26c1e]
25
26Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
27---
28 builtin/clone.c | 21 ++++++++++++++++++++-
29 1 file changed, 20 insertions(+), 1 deletion(-)
30
31diff --git a/builtin/clone.c b/builtin/clone.c
32index 2778d20..54eb441 100644
33--- a/builtin/clone.c
34+++ b/builtin/clone.c
35@@ -361,8 +361,27 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
36 if (unlink(dest->buf) && errno != ENOENT)
37 die_errno(_("failed to unlink '%s'"), dest->buf);
38 if (!option_no_hardlinks) {
39- if (!link(src->buf, dest->buf))
40+ if (!link(src->buf, dest->buf)) {
41+ struct stat st;
42+
43+ /*
44+ * Sanity-check whether the created hardlink
45+ * actually links to the expected file now. This
46+ * catches time-of-check-time-of-use bugs in
47+ * case the source file was meanwhile swapped.
48+ */
49+ if (lstat(dest->buf, &st))
50+ die(_("hardlink cannot be checked at '%s'"), dest->buf);
51+ if (st.st_mode != iter->st.st_mode ||
52+ st.st_ino != iter->st.st_ino ||
53+ st.st_dev != iter->st.st_dev ||
54+ st.st_size != iter->st.st_size ||
55+ st.st_uid != iter->st.st_uid ||
56+ st.st_gid != iter->st.st_gid)
57+ die(_("hardlink different from source at '%s'"), dest->buf);
58+
59 continue;
60+ }
61 if (option_local > 0)
62 die_errno(_("failed to create link '%s'"), dest->buf);
63 option_no_hardlinks = 1;
64--
652.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32465.patch b/meta/recipes-devtools/git/git/CVE-2024-32465.patch
new file mode 100644
index 0000000000..f9e2c1dc5f
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32465.patch
@@ -0,0 +1,206 @@
1From 7b70e9efb18c2cc3f219af399bd384c5801ba1d7 Mon Sep 17 00:00:00 2001
2From: Jeff King <peff@peff.net>
3Date: Tue, 16 Apr 2024 04:35:33 -0400
4Subject: [PATCH] upload-pack: disable lazy-fetching by default
5
6The upload-pack command tries to avoid trusting the repository in which
7it's run (e.g., by not running any hooks and not using any config that
8contains arbitrary commands). But if the server side of a fetch or a
9clone is a partial clone, then either upload-pack or its child
10pack-objects may run a lazy "git fetch" under the hood. And it is very
11easy to convince fetch to run arbitrary commands.
12
13The "server" side can be a local repository owned by someone else, who
14would be able to configure commands that are run during a clone with the
15current user's permissions. This issue has been designated
16CVE-2024-32004.
17
18The fix in this commit's parent helps in this scenario, as well as in
19related scenarios using SSH to clone, where the untrusted .git directory
20is owned by a different user id. But if you received one as a zip file,
21on a USB stick, etc, it may be owned by your user but still untrusted.
22
23This has been designated CVE-2024-32465.
24
25To mitigate the issue more completely, let's disable lazy fetching
26entirely during `upload-pack`. While fetching from a partial repository
27should be relatively rare, it is certainly not an unreasonable workflow.
28And thus we need to provide an escape hatch.
29
30This commit works by respecting a GIT_NO_LAZY_FETCH environment variable
31(to skip the lazy-fetch), and setting it in upload-pack, but only when
32the user has not already done so (which gives us the escape hatch).
33
34The name of the variable is specifically chosen to match what has
35already been added in 'master' via e6d5479e7a (git: extend
36--no-lazy-fetch to work across subprocesses, 2024-02-27). Since we're
37building this fix as a backport for older versions, we could cherry-pick
38that patch and its earlier steps. However, we don't really need the
39niceties (like a "--no-lazy-fetch" option) that it offers. By using the
40same name, everything should just work when the two are eventually
41merged, but here are a few notes:
42
43 - the blocking of the fetch in e6d5479e7a is incomplete! It sets
44 fetch_if_missing to 0 when we setup the repository variable, but
45 that isn't enough. pack-objects in particular will call
46 prefetch_to_pack() even if that variable is 0. This patch by
47 contrast checks the environment variable at the lowest level before
48 we call the lazy fetch, where we can be sure to catch all code
49 paths.
50
51 Possibly the setting of fetch_if_missing from e6d5479e7a can be
52 reverted, but it may be useful to have. For example, some code may
53 want to use that flag to change behavior before it gets to the point
54 of trying to start the fetch. At any rate, that's all outside the
55 scope of this patch.
56
57 - there's documentation for GIT_NO_LAZY_FETCH in e6d5479e7a. We can
58 live without that here, because for the most part the user shouldn't
59 need to set it themselves. The exception is if they do want to
60 override upload-pack's default, and that requires a separate
61 documentation section (which is added here)
62
63 - it would be nice to use the NO_LAZY_FETCH_ENVIRONMENT macro added by
64 e6d5479e7a, but those definitions have moved from cache.h to
65 environment.h between 2.39.3 and master. I just used the raw string
66 literals, and we can replace them with the macro once this topic is
67 merged to master.
68
69At least with respect to CVE-2024-32004, this does render this commit's
70parent commit somewhat redundant. However, it is worth retaining that
71commit as defense in depth, and because it may help other issues (e.g.,
72symlink/hardlink TOCTOU races, where zip files are not really an
73interesting attack vector).
74
75The tests in t0411 still pass, but now we have _two_ mechanisms ensuring
76that the evil command is not run. Let's beef up the existing ones to
77check that they failed for the expected reason, that we refused to run
78upload-pack at all with an alternate user id. And add two new ones for
79the same-user case that both the restriction and its escape hatch.
80
81Signed-off-by: Jeff King <peff@peff.net>
82Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
83
84CVE: CVE-2024-32465
85
86Upstream-Status: Backport [https://github.com/git/git/commit/7b70e9efb18c2cc3f219af399bd384c5801ba1d7]
87
88Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
89---
90 Documentation/git-upload-pack.txt | 16 ++++++++++++++++
91 builtin/upload-pack.c | 2 ++
92 promisor-remote.c | 10 ++++++++++
93 t/t0411-clone-from-partial.sh | 18 ++++++++++++++++++
94 4 files changed, 46 insertions(+)
95
96diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
97index 8f87b23..eba0e81 100644
98--- a/Documentation/git-upload-pack.txt
99+++ b/Documentation/git-upload-pack.txt
100@@ -56,6 +56,22 @@ ENVIRONMENT
101 admins may need to configure some transports to allow this
102 variable to be passed. See the discussion in linkgit:git[1].
103
104+`GIT_NO_LAZY_FETCH`::
105+ When cloning or fetching from a partial repository (i.e., one
106+ itself cloned with `--filter`), the server-side `upload-pack`
107+ may need to fetch extra objects from its upstream in order to
108+ complete the request. By default, `upload-pack` will refuse to
109+ perform such a lazy fetch, because `git fetch` may run arbitrary
110+ commands specified in configuration and hooks of the source
111+ repository (and `upload-pack` tries to be safe to run even in
112+ untrusted `.git` directories).
113++
114+This is implemented by having `upload-pack` internally set the
115+`GIT_NO_LAZY_FETCH` variable to `1`. If you want to override it
116+(because you are fetching from a partial clone, and you are sure
117+you trust it), you can explicitly set `GIT_NO_LAZY_FETCH` to
118+`0`.
119+
120 SEE ALSO
121 --------
122 linkgit:gitnamespaces[7]
123diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
124index 125af53..9ecaafe 100644
125--- a/builtin/upload-pack.c
126+++ b/builtin/upload-pack.c
127@@ -34,6 +34,8 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
128
129 packet_trace_identity("upload-pack");
130 read_replace_refs = 0;
131+ /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
132+ xsetenv("GIT_NO_LAZY_FETCH", "1", 0);
133
134 argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
135
136diff --git a/promisor-remote.c b/promisor-remote.c
137index db2ebdc..e73df68 100644
138--- a/promisor-remote.c
139+++ b/promisor-remote.c
140@@ -19,6 +19,16 @@ static int fetch_objects(struct repository *repo,
141 int i;
142 FILE *child_in;
143
144+ /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
145+ if (git_env_bool("GIT_NO_LAZY_FETCH", 0)) {
146+ static int warning_shown;
147+ if (!warning_shown) {
148+ warning_shown = 1;
149+ warning(_("lazy fetching disabled; some objects may not be available"));
150+ }
151+ return -1;
152+ }
153+
154 child.git_cmd = 1;
155 child.in = -1;
156 if (repo != the_repository)
157diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
158index eb3360d..b3d6ddc 100755
159--- a/t/t0411-clone-from-partial.sh
160+++ b/t/t0411-clone-from-partial.sh
161@@ -28,6 +28,7 @@ test_expect_success 'local clone must not fetch from promisor remote and execute
162 test_must_fail git clone \
163 --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
164 evil clone1 2>err &&
165+ grep "detected dubious ownership" err &&
166 ! grep "fake-upload-pack running" err &&
167 test_path_is_missing script-executed
168 '
169@@ -37,6 +38,7 @@ test_expect_success 'clone from file://... must not fetch from promisor remote a
170 test_must_fail git clone \
171 --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
172 "file://$(pwd)/evil" clone2 2>err &&
173+ grep "detected dubious ownership" err &&
174 ! grep "fake-upload-pack running" err &&
175 test_path_is_missing script-executed
176 '
177@@ -46,6 +48,7 @@ test_expect_success 'fetch from file://... must not fetch from promisor remote a
178 test_must_fail git fetch \
179 --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
180 "file://$(pwd)/evil" 2>err &&
181+ grep "detected dubious ownership" err &&
182 ! grep "fake-upload-pack running" err &&
183 test_path_is_missing script-executed
184 '
185@@ -57,4 +60,19 @@ test_expect_success 'pack-objects should fetch from promisor remote and execute
186 test_path_is_file script-executed
187 '
188
189+test_expect_success 'clone from promisor remote does not lazy-fetch by default' '
190+ rm -f script-executed &&
191+ test_must_fail git clone evil no-lazy 2>err &&
192+ grep "lazy fetching disabled" err &&
193+ test_path_is_missing script-executed
194+'
195+
196+test_expect_success 'promisor lazy-fetching can be re-enabled' '
197+ rm -f script-executed &&
198+ test_must_fail env GIT_NO_LAZY_FETCH=0 \
199+ git clone evil lazy-ok 2>err &&
200+ grep "fake-upload-pack running" err &&
201+ test_path_is_file script-executed
202+'
203+
204 test_done
205--
2062.40.0
diff --git a/meta/recipes-devtools/git/git_2.35.7.bb b/meta/recipes-devtools/git/git_2.35.7.bb
index 9e7b0a8cff..94352d38ef 100644
--- a/meta/recipes-devtools/git/git_2.35.7.bb
+++ b/meta/recipes-devtools/git/git_2.35.7.bb
@@ -12,6 +12,17 @@ SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \
12 file://0001-config.mak.uname-do-not-force-RHEL-7-specific-build-.patch \ 12 file://0001-config.mak.uname-do-not-force-RHEL-7-specific-build-.patch \
13 file://CVE-2023-29007.patch \ 13 file://CVE-2023-29007.patch \
14 file://CVE-2023-25652.patch \ 14 file://CVE-2023-25652.patch \
15 file://CVE-2024-32002-0001.patch \
16 file://CVE-2024-32002-0002.patch \
17 file://CVE-2024-32002-0003.patch \
18 file://CVE-2024-32002-0004.patch \
19 file://CVE-2024-32004-0001.patch \
20 file://CVE-2024-32004-0002.patch \
21 file://CVE-2024-32004-0003.patch \
22 file://CVE-2024-32020.patch \
23 file://CVE-2024-32021-0001.patch \
24 file://CVE-2024-32021-0002.patch \
25 file://CVE-2024-32465.patch \
15 " 26 "
16 27
17S = "${WORKDIR}/git-${PV}" 28S = "${WORKDIR}/git-${PV}"