diff options
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch | 69 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch | 213 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch | 141 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch | 150 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch | 95 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch | 187 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch | 158 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32020.patch | 114 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch | 89 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch | 65 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2024-32465.patch | 206 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git_2.35.7.bb | 11 |
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 @@ | |||
1 | From 21496b4c60b2327417c63fc9762096037a185be3 Mon Sep 17 00:00:00 2001 | ||
2 | From: Ævar Arnfjörð Bjarmason <avarab@gmail.com> | ||
3 | Date: Thu, 1 Sep 2022 01:17:54 +0200 | ||
4 | Subject: [PATCH] submodule--helper: use xstrfmt() in clone_submodule() | ||
5 | |||
6 | Use xstrfmt() in clone_submodule() instead of a "struct strbuf" in two | ||
7 | cases where we weren't getting anything out of using the "struct | ||
8 | strbuf". | ||
9 | |||
10 | This changes code that was was added along with other uses of "struct | ||
11 | strbuf" in this function in ee8838d1577 (submodule: rewrite | ||
12 | `module_clone` shell function in C, 2015-09-08). | ||
13 | |||
14 | Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> | ||
15 | Reviewed-by: Glen Choo <chooglen@google.com> | ||
16 | Signed-off-by: Junio C Hamano <gitster@pobox.com> | ||
17 | |||
18 | CVE: CVE-2024-32002 | ||
19 | |||
20 | Upstream-Status: Backport [https://github.com/git/git/commit/21496b4c60b2327417c63fc9762096037a185be3] | ||
21 | |||
22 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
23 | --- | ||
24 | builtin/submodule--helper.c | 17 +++++++++-------- | ||
25 | 1 file changed, 9 insertions(+), 8 deletions(-) | ||
26 | |||
27 | diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c | ||
28 | index 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 | -- | ||
69 | 2.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 @@ | |||
1 | From 6fac5b2f352efc8c246d6d5be63a66b7b0fc0209 Mon Sep 17 00:00:00 2001 | ||
2 | From: Ævar Arnfjörð Bjarmason <avarab@gmail.com> | ||
3 | Date: Thu, 1 Sep 2022 01:17:56 +0200 | ||
4 | Subject: [PATCH] submodule--helper: add "const" to passed "module_clone_data" | ||
5 | |||
6 | Add "const" to the "struct module_clone_data" that we pass to | ||
7 | clone_submodule(), which makes the ownership clear, and stops us from | ||
8 | clobbering the "clone_data->path". | ||
9 | |||
10 | We still need to add to the "reference" member, which is a "struct | ||
11 | string_list". Let's do this by having clone_submodule() create its | ||
12 | own, and copy the contents over, allowing us to pass it as a | ||
13 | separate parameter. | ||
14 | |||
15 | This new "struct string_list" still leaks memory, just as the "struct | ||
16 | module_clone_data" did before. let's not fix that for now, to fix that | ||
17 | we'll need to add some "goto cleanup" to the relevant code. That will | ||
18 | eventually be done in follow-up commits, this change makes it easier | ||
19 | to fix the memory leak. | ||
20 | |||
21 | The scope of the new "reference" variable in add_submodule() could be | ||
22 | narrowed 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 | |||
25 | Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> | ||
26 | Reviewed-by: Glen Choo <chooglen@google.com> | ||
27 | Signed-off-by: Junio C Hamano <gitster@pobox.com> | ||
28 | |||
29 | CVE: CVE-2024-32002 | ||
30 | |||
31 | Upstream-Status: Backport [https://github.com/git/git/commit/6fac5b2f352efc8c246d6d5be63a66b7b0fc0209] | ||
32 | |||
33 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
34 | --- | ||
35 | builtin/submodule--helper.c | 52 ++++++++++++++++++++----------------- | ||
36 | 1 file changed, 28 insertions(+), 24 deletions(-) | ||
37 | |||
38 | diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c | ||
39 | index 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 | -- | ||
213 | 2.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 @@ | |||
1 | From e77b3da6bb60e9af5963c9e42442afe53af1780b Mon Sep 17 00:00:00 2001 | ||
2 | From: Ævar Arnfjörð Bjarmason <avarab@gmail.com> | ||
3 | Date: Thu, 1 Sep 2022 01:14:08 +0200 | ||
4 | Subject: [PATCH] submodule--helper: fix a leak in "clone_submodule" | ||
5 | |||
6 | Fix a memory leak of the "clone_data_path" variable that we copy or | ||
7 | derive from the "struct module_clone_data" in clone_submodule(). This | ||
8 | code was refactored in preceding commits, but the leak has been with | ||
9 | us since f8eaa0ba98b (submodule--helper, module_clone: always operate | ||
10 | on absolute paths, 2016-03-31). | ||
11 | |||
12 | For the "else" case we don't need to xstrdup() the "clone_data->path", | ||
13 | and we don't need to free our own "clone_data_path". We can therefore | ||
14 | assign the "clone_data->path" to our own "clone_data_path" right away, | ||
15 | and only override it (and remember to free it!) if we need to | ||
16 | xstrfmt() a replacement. | ||
17 | |||
18 | In the case of the module_clone() caller it's from "argv", and doesn't | ||
19 | need to be free'd, and in the case of the add_submodule() caller we | ||
20 | get a pointer to "sm_path", which doesn't need to be directly free'd | ||
21 | either. | ||
22 | |||
23 | Fixing this leak makes several tests pass, so let's mark them as | ||
24 | passing with TEST_PASSES_SANITIZE_LEAK=true. | ||
25 | |||
26 | Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> | ||
27 | Reviewed-by: Glen Choo <chooglen@google.com> | ||
28 | Signed-off-by: Junio C Hamano <gitster@pobox.com> | ||
29 | |||
30 | CVE: CVE-2024-32002 | ||
31 | |||
32 | Upstream-Status: Backport [https://github.com/git/git/commit/e77b3da6bb60e9af5963c9e42442afe53af1780b] | ||
33 | |||
34 | Signed-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 | |||
44 | diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c | ||
45 | index 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 | |||
78 | diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh | ||
79 | index 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 () { | ||
90 | diff --git a/t/t6008-rev-list-submodule.sh b/t/t6008-rev-list-submodule.sh | ||
91 | index 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' ' | ||
102 | diff --git a/t/t7414-submodule-mistakes.sh b/t/t7414-submodule-mistakes.sh | ||
103 | index 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' ' | ||
115 | diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh | ||
116 | index 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 () { | ||
127 | diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh | ||
128 | index 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 | -- | ||
141 | 2.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 @@ | |||
1 | From 97065761333fd62db1912d81b489db938d8c991d Mon Sep 17 00:00:00 2001 | ||
2 | From: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
3 | Date: Fri, 22 Mar 2024 11:19:22 +0100 | ||
4 | Subject: [PATCH] submodules: submodule paths must not contain symlinks | ||
5 | |||
6 | When creating a submodule path, we must be careful not to follow | ||
7 | symbolic links. Otherwise we may follow a symbolic link pointing to | ||
8 | a gitdir (which are valid symbolic links!) e.g. while cloning. | ||
9 | |||
10 | On case-insensitive filesystems, however, we blindly replace a directory | ||
11 | that has been created as part of the `clone` operation with a symlink | ||
12 | when the path to the latter differs only in case from the former's path. | ||
13 | |||
14 | Let's simply avoid this situation by expecting not ever having to | ||
15 | overwrite any existing file/directory/symlink upon cloning. That way, we | ||
16 | won't even replace a directory that we just created. | ||
17 | |||
18 | This addresses CVE-2024-32002. | ||
19 | |||
20 | Reported-by: Filip Hejsek <filip.hejsek@gmail.com> | ||
21 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
22 | |||
23 | CVE: CVE-2024-32002 | ||
24 | |||
25 | Upstream-Status: Backport [https://github.com/git/git/commit/97065761333fd62db1912d81b489db938d8c991d] | ||
26 | |||
27 | Signed-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 | |||
33 | diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c | ||
34 | index 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 | |||
98 | diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh | ||
99 | index 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 | -- | ||
150 | 2.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 @@ | |||
1 | From 5c5a4a1c05932378d259b1fdd9526cab971656a2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Filip Hejsek <filip.hejsek@gmail.com> | ||
3 | Date: Sun, 28 Jan 2024 04:29:33 +0100 | ||
4 | Subject: [PATCH] t0411: add tests for cloning from partial repo | ||
5 | |||
6 | Cloning from a partial repository must not fetch missing objects into | ||
7 | the partial repository, because that can lead to arbitrary code | ||
8 | execution. | ||
9 | |||
10 | Add a couple of test cases, pretending to the `upload-pack` command (and | ||
11 | to that command only) that it is working on a repository owned by | ||
12 | someone else. | ||
13 | |||
14 | Helped-by: Jeff King <peff@peff.net> | ||
15 | Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com> | ||
16 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
17 | |||
18 | CVE: CVE-2024-32004 | ||
19 | |||
20 | Upstream-Status: Backport [https://github.com/git/git/commit/5c5a4a1c05932378d259b1fdd9526cab971656a2] | ||
21 | |||
22 | Signed-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 | |||
28 | diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh | ||
29 | new file mode 100755 | ||
30 | index 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 | -- | ||
95 | 2.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 @@ | |||
1 | From 17d3883fe9c88b823002ad9fafb42313ddc3d3d5 Mon Sep 17 00:00:00 2001 | ||
2 | From: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
3 | Date: Mon, 8 Aug 2022 13:27:47 +0000 | ||
4 | Subject: [PATCH] setup: prepare for more detailed "dubious ownership" messages | ||
5 | |||
6 | When verifying the ownership of the Git directory, we sometimes would | ||
7 | like to say a bit more about it, e.g. when using a platform-dependent | ||
8 | code path (think: Windows has the permission model that is so different | ||
9 | from Unix'), but only when it is a appropriate to actually say | ||
10 | something. | ||
11 | |||
12 | To allow for that, collect that information and hand it back to the | ||
13 | caller (whose responsibility it is to show it or not). | ||
14 | |||
15 | Note: We do not actually fill in any platform-dependent information yet, | ||
16 | this commit just adds the infrastructure to be able to do so. | ||
17 | |||
18 | Based-on-an-idea-by: Junio C Hamano <gitster@pobox.com> | ||
19 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
20 | Signed-off-by: Junio C Hamano <gitster@pobox.com> | ||
21 | |||
22 | CVE: CVE-2024-32004 | ||
23 | |||
24 | Upstream-Status: Backport [https://github.com/git/git/commit/17d3883fe9c88b823002ad9fafb42313ddc3d3d5] | ||
25 | |||
26 | Signed-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 | |||
34 | diff --git a/compat/mingw.c b/compat/mingw.c | ||
35 | index 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; | ||
47 | diff --git a/compat/mingw.h b/compat/mingw.h | ||
48 | index 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 | /** | ||
60 | diff --git a/git-compat-util.h b/git-compat-util.h | ||
61 | index 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; | ||
83 | diff --git a/setup.c b/setup.c | ||
84 | index 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("ed, 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 | -- | ||
187 | 2.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 @@ | |||
1 | From f4aa8c8bb11dae6e769cd930565173808cbb69c8 Mon Sep 17 00:00:00 2001 | ||
2 | From: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
3 | Date: Wed, 10 Apr 2024 14:39:37 +0200 | ||
4 | Subject: [PATCH] fetch/clone: detect dubious ownership of local repositories | ||
5 | |||
6 | When cloning from somebody else's repositories, it is possible that, | ||
7 | say, the `upload-pack` command is overridden in the repository that is | ||
8 | about to be cloned, which would then be run in the user's context who | ||
9 | started the clone. | ||
10 | |||
11 | To remind the user that this is a potentially unsafe operation, let's | ||
12 | extend the ownership checks we have already established for regular | ||
13 | gitdir discovery to extend also to local repositories that are about to | ||
14 | be cloned. | ||
15 | |||
16 | This protection extends also to file:// URLs. | ||
17 | |||
18 | The fixes in this commit address CVE-2024-32004. | ||
19 | |||
20 | Note: This commit does not touch the `fetch`/`clone` code directly, but | ||
21 | instead the function used implicitly by both: `enter_repo()`. This | ||
22 | function is also used by `git receive-pack` (i.e. pushes), by `git | ||
23 | upload-archive`, by `git daemon` and by `git http-backend`. In setups | ||
24 | that want to serve repositories owned by different users than the | ||
25 | account running the service, this will require `safe.*` settings to be | ||
26 | configured accordingly. | ||
27 | |||
28 | Also 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 | ||
30 | with `fstat()` and `openat()`. However, the latter function is not | ||
31 | available on Windows (and would have to be emulated with rather | ||
32 | expensive low-level `NtCreateFile()` calls), and the changes would be | ||
33 | quite extensive, for my taste too extensive for the little gain given | ||
34 | that embargoed releases need to pay extra attention to avoid introducing | ||
35 | inadvertent bugs. | ||
36 | |||
37 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
38 | |||
39 | CVE: CVE-2024-32004 | ||
40 | |||
41 | Upstream-Status: Backport [https://github.com/git/git/commit/f4aa8c8bb11dae6e769cd930565173808cbb69c8] | ||
42 | |||
43 | Signed-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 | |||
51 | diff --git a/cache.h b/cache.h | ||
52 | index 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 | ||
74 | diff --git a/path.c b/path.c | ||
75 | index 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)) | ||
94 | diff --git a/setup.c b/setup.c | ||
95 | index 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("ed, 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, | ||
126 | diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh | ||
127 | index 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 | -- | ||
158 | 2.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 @@ | |||
1 | From 1204e1a824c34071019fe106348eaa6d88f9528d Mon Sep 17 00:00:00 2001 | ||
2 | From: Patrick Steinhardt <ps@pks.im> | ||
3 | Date: Mon, 15 Apr 2024 13:30:41 +0200 | ||
4 | Subject: [PATCH] builtin/clone: refuse local clones of unsafe repositories | ||
5 | |||
6 | When performing a local clone of a repository we end up either copying | ||
7 | or hardlinking the source repository into the target repository. This is | ||
8 | significantly more performant than if we were to use git-upload-pack(1) | ||
9 | and git-fetch-pack(1) to create the new repository and preserves both | ||
10 | disk space and compute time. | ||
11 | |||
12 | Unfortunately though, performing such a local clone of a repository that | ||
13 | is 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 | |||
34 | Address these issues by completely refusing local clones of a repository | ||
35 | that is not owned by the current user. This reuses our existing infra we | ||
36 | have in place via `ensure_valid_ownership()` and thus allows a user to | ||
37 | override the safety guard by adding the source repository path to the | ||
38 | "safe.directory" configuration. | ||
39 | |||
40 | This addresses CVE-2024-32020. | ||
41 | |||
42 | Signed-off-by: Patrick Steinhardt <ps@pks.im> | ||
43 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
44 | |||
45 | CVE: CVE-2024-32020 | ||
46 | |||
47 | Upstream-Status: Backport [https://github.com/git/git/commit/1204e1a824c34071019fe106348eaa6d88f9528d] | ||
48 | |||
49 | Signed-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 | |||
55 | diff --git a/builtin/clone.c b/builtin/clone.c | ||
56 | index 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); | ||
80 | diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh | ||
81 | index 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 | -- | ||
114 | 2.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 @@ | |||
1 | From 150e6b0aedf57d224c3c49038c306477fa159886 Mon Sep 17 00:00:00 2001 | ||
2 | From: Patrick Steinhardt <ps@pks.im> | ||
3 | Date: Mon, 15 Apr 2024 13:30:26 +0200 | ||
4 | Subject: [PATCH] builtin/clone: stop resolving symlinks when copying files | ||
5 | |||
6 | When a user performs a local clone without `--no-local`, then we end up | ||
7 | copying the source repository into the target repository directly. To | ||
8 | optimize this even further, we try to hardlink files into place instead | ||
9 | of copying data over, which helps both disk usage and speed. | ||
10 | |||
11 | There is an important edge case in this context though, namely when we | ||
12 | try to hardlink symlinks from the source repository into the target | ||
13 | repository. Depending on both platform and filesystem the resulting | ||
14 | behaviour 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 | |||
22 | To unify this behaviour, 36596fd2df (clone: better handle symlinked | ||
23 | files at .git/objects/, 2019-07-10) introduced logic to resolve symlinks | ||
24 | before we try to link(3P) files. Consequently, the new behaviour was to | ||
25 | always create a hard link to the target of the symlink on all platforms. | ||
26 | |||
27 | Eventually though, we figured out that following symlinks like this can | ||
28 | cause havoc when performing a local clone of a malicious repository, | ||
29 | which resulted in CVE-2022-39253. This issue was fixed via 6f054f9fb3 | ||
30 | (builtin/clone.c: disallow `--local` clones with symlinks, 2022-07-28), | ||
31 | by refusing symlinks in the source repository. | ||
32 | |||
33 | But even though we now shouldn't ever link symlinks anymore, the code | ||
34 | that resolves symlinks still exists. In the best case the code does not | ||
35 | end up doing anything because there are no symlinks anymore. In the | ||
36 | worst case though this can be abused by an adversary that rewrites the | ||
37 | source file after it has been checked not to be a symlink such that it | ||
38 | actually is a symlink when we call link(3P). Thus, it is still possible | ||
39 | to recreate CVE-2022-39253 due to this time-of-check-time-of-use bug. | ||
40 | |||
41 | Remove the call to `realpath()`. This doesn't yet address the actual | ||
42 | vulnerability, which will be handled in a subsequent commit. | ||
43 | |||
44 | Reported-by: Apple Product Security <product-security@apple.com> | ||
45 | Signed-off-by: Patrick Steinhardt <ps@pks.im> | ||
46 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
47 | |||
48 | CVE: CVE-2024-32021 | ||
49 | |||
50 | Upstream-Status: Backport [https://github.com/git/git/commit/150e6b0aedf57d224c3c49038c306477fa159886] | ||
51 | |||
52 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
53 | --- | ||
54 | builtin/clone.c | 6 +----- | ||
55 | 1 file changed, 1 insertion(+), 5 deletions(-) | ||
56 | |||
57 | diff --git a/builtin/clone.c b/builtin/clone.c | ||
58 | index 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 | -- | ||
89 | 2.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 @@ | |||
1 | From d1bb66a546b4bb46005d17ba711caaad26f26c1e Mon Sep 17 00:00:00 2001 | ||
2 | From: Patrick Steinhardt <ps@pks.im> | ||
3 | Date: Mon, 15 Apr 2024 13:30:31 +0200 | ||
4 | Subject: [PATCH] builtin/clone: abort when hardlinked source and target file | ||
5 | differ | ||
6 | |||
7 | When performing local clones with hardlinks we refuse to copy source | ||
8 | files which are symlinks as a mitigation for CVE-2022-39253. This check | ||
9 | can be raced by an adversary though by changing the file to a symlink | ||
10 | after we have checked it. | ||
11 | |||
12 | Fix the issue by checking whether the hardlinked destination file | ||
13 | matches the source file and abort in case it doesn't. | ||
14 | |||
15 | This addresses CVE-2024-32021. | ||
16 | |||
17 | Reported-by: Apple Product Security <product-security@apple.com> | ||
18 | Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org> | ||
19 | Signed-off-by: Patrick Steinhardt <ps@pks.im> | ||
20 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
21 | |||
22 | CVE: CVE-2024-32021 | ||
23 | |||
24 | Upstream-Status: Backport [https://github.com/git/git/commit/d1bb66a546b4bb46005d17ba711caaad26f26c1e] | ||
25 | |||
26 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
27 | --- | ||
28 | builtin/clone.c | 21 ++++++++++++++++++++- | ||
29 | 1 file changed, 20 insertions(+), 1 deletion(-) | ||
30 | |||
31 | diff --git a/builtin/clone.c b/builtin/clone.c | ||
32 | index 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 | -- | ||
65 | 2.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 @@ | |||
1 | From 7b70e9efb18c2cc3f219af399bd384c5801ba1d7 Mon Sep 17 00:00:00 2001 | ||
2 | From: Jeff King <peff@peff.net> | ||
3 | Date: Tue, 16 Apr 2024 04:35:33 -0400 | ||
4 | Subject: [PATCH] upload-pack: disable lazy-fetching by default | ||
5 | |||
6 | The upload-pack command tries to avoid trusting the repository in which | ||
7 | it's run (e.g., by not running any hooks and not using any config that | ||
8 | contains arbitrary commands). But if the server side of a fetch or a | ||
9 | clone is a partial clone, then either upload-pack or its child | ||
10 | pack-objects may run a lazy "git fetch" under the hood. And it is very | ||
11 | easy to convince fetch to run arbitrary commands. | ||
12 | |||
13 | The "server" side can be a local repository owned by someone else, who | ||
14 | would be able to configure commands that are run during a clone with the | ||
15 | current user's permissions. This issue has been designated | ||
16 | CVE-2024-32004. | ||
17 | |||
18 | The fix in this commit's parent helps in this scenario, as well as in | ||
19 | related scenarios using SSH to clone, where the untrusted .git directory | ||
20 | is owned by a different user id. But if you received one as a zip file, | ||
21 | on a USB stick, etc, it may be owned by your user but still untrusted. | ||
22 | |||
23 | This has been designated CVE-2024-32465. | ||
24 | |||
25 | To mitigate the issue more completely, let's disable lazy fetching | ||
26 | entirely during `upload-pack`. While fetching from a partial repository | ||
27 | should be relatively rare, it is certainly not an unreasonable workflow. | ||
28 | And thus we need to provide an escape hatch. | ||
29 | |||
30 | This 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 | ||
32 | the user has not already done so (which gives us the escape hatch). | ||
33 | |||
34 | The name of the variable is specifically chosen to match what has | ||
35 | already been added in 'master' via e6d5479e7a (git: extend | ||
36 | --no-lazy-fetch to work across subprocesses, 2024-02-27). Since we're | ||
37 | building this fix as a backport for older versions, we could cherry-pick | ||
38 | that patch and its earlier steps. However, we don't really need the | ||
39 | niceties (like a "--no-lazy-fetch" option) that it offers. By using the | ||
40 | same name, everything should just work when the two are eventually | ||
41 | merged, 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 | |||
69 | At least with respect to CVE-2024-32004, this does render this commit's | ||
70 | parent commit somewhat redundant. However, it is worth retaining that | ||
71 | commit as defense in depth, and because it may help other issues (e.g., | ||
72 | symlink/hardlink TOCTOU races, where zip files are not really an | ||
73 | interesting attack vector). | ||
74 | |||
75 | The tests in t0411 still pass, but now we have _two_ mechanisms ensuring | ||
76 | that the evil command is not run. Let's beef up the existing ones to | ||
77 | check that they failed for the expected reason, that we refused to run | ||
78 | upload-pack at all with an alternate user id. And add two new ones for | ||
79 | the same-user case that both the restriction and its escape hatch. | ||
80 | |||
81 | Signed-off-by: Jeff King <peff@peff.net> | ||
82 | Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> | ||
83 | |||
84 | CVE: CVE-2024-32465 | ||
85 | |||
86 | Upstream-Status: Backport [https://github.com/git/git/commit/7b70e9efb18c2cc3f219af399bd384c5801ba1d7] | ||
87 | |||
88 | Signed-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 | |||
96 | diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt | ||
97 | index 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] | ||
123 | diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c | ||
124 | index 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 | |||
136 | diff --git a/promisor-remote.c b/promisor-remote.c | ||
137 | index 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) | ||
157 | diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh | ||
158 | index 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 | -- | ||
206 | 2.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 | ||
17 | S = "${WORKDIR}/git-${PV}" | 28 | S = "${WORKDIR}/git-${PV}" |