diff options
author | Soumya Sambu <soumya.sambu@windriver.com> | 2024-05-30 11:32:12 +0000 |
---|---|---|
committer | Steve Sakoman <steve@sakoman.com> | 2024-06-01 19:07:52 -0700 |
commit | d08e8d726d95925e5d4b7b705e562ce55297ddd9 (patch) | |
tree | 785a8868ac474300a7ce858589e00eb0f27726a4 | |
parent | ec87d3ca28273d5bb0d38d82566e4d1bca93e31a (diff) | |
download | poky-d08e8d726d95925e5d4b7b705e562ce55297ddd9.tar.gz |
git: Fix multiple CVEs
CVE-2024-32002:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, repositories with submodules can be
crafted in a way that exploits a bug in Git whereby it can be fooled into
writing files not into the submodule's worktree but into a `.git/` directory.
This allows writing a hook that will be executed while the clone operation
is still running, giving the user no opportunity to inspect the code that is
being executed. The problem has been patched in versions 2.45.1, 2.44.1,
2.43.4, 2.42.2, 2.41.1, 2.40.2, and 2.39.4. If symbolic link support is
disabled in Git (e.g. via `git config --global core.symlinks false`), the
described attack won't work. As always, it is best to avoid cloning
repositories from untrusted sources.
CVE-2024-32004:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, an attacker can prepare a local repository
in such a way that, when cloned, will execute arbitrary code during the
operation. The problem has been patched in versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4. As a workaround, avoid cloning repositories
from untrusted sources.
CVE-2024-32020:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, local clones may end up hardlinking files
into the target repository's object database when source and target repository
reside on the same disk. If the source repository is owned by a different user,
then those hardlinked files may be rewritten at any point in time by the
untrusted user. Cloning local repositories will cause Git to either copy or
hardlink files of the source repository into the target repository. This
significantly speeds up such local clones compared to doing a "proper" clone and
saves both disk space and compute time. When cloning a repository located on the
same disk that is owned by a different user than the current user we also end up
creating such hardlinks. These files will continue to be owned and controlled by
the potentially-untrusted user and can be rewritten by them at will in the
future. The problem has been patched in versions 2.45.1, 2.44.1, 2.43.4, 2.42.2,
2.41.1, 2.40.2, and 2.39.4.
CVE-2024-32021:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, when cloning a local source repository that
contains symlinks via the filesystem, Git may create hardlinks to arbitrary
user-readable files on the same filesystem as the target repository in the
`objects/` directory. Cloning a local repository over the filesystem may
creating hardlinks to arbitrary user-owned files on the same filesystem in the
target Git repository's `objects/` directory. When cloning a repository over the
filesystem (without explicitly specifying the `file://` protocol or `--no-local`),
the optimizations for local cloning will be used, which include attempting to
hard link the object files instead of copying them. While the code includes checks
against symbolic links in the source repository, which were added during the fix
for CVE-2022-39253, these checks can still be raced because the hard link
operation ultimately follows symlinks. If the object on the filesystem appears as
a file during the check, and then a symlink during the operation, this will allow
the adversary to bypass the check and create hardlinks in the destination objects
directory to arbitrary, user-readable files. The problem has been patched in
versions 2.45.1, 2.44.1, 2.43.4, 2.42.2, 2.41.1, 2.40.2, and 2.39.4.
CVE-2024-32465:
Git is a revision control system. The Git project recommends to avoid working in
untrusted repositories, and instead to clone it first with `git clone --no-local`
to obtain a clean copy. Git has specific protections to make that a safe
operation even with an untrusted source repository, but vulnerabilities allow
those protections to be bypassed. In the context of cloning local repositories
owned by other users, this vulnerability has been covered in CVE-2024-32004. But
there are circumstances where the fixes for CVE-2024-32004 are not enough: For
example, when obtaining a `.zip` file containing a full copy of a Git repository,
it should not be trusted by default to be safe, as e.g. hooks could be configured
to run within the context of that repository. The problem has been patched in
versions 2.45.1, 2.44.1, 2.43.4, 2.42.2, 2.41.1, 2.40.2, and 2.39.4. As a
workaround, avoid using Git in repositories that have been obtained via archives
from untrusted sources.
References:
https://nvd.nist.gov/vuln/detail/CVE-2024-32002
https://nvd.nist.gov/vuln/detail/CVE-2024-32004
https://nvd.nist.gov/vuln/detail/CVE-2024-32020
https://nvd.nist.gov/vuln/detail/CVE-2024-32021
https://nvd.nist.gov/vuln/detail/CVE-2024-32465
(From OE-Core rev: 209c41377abf6853455b00af3923f1b244a3766b)
Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
-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}" |