summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools
diff options
context:
space:
mode:
authorVijay Anusuri <vanusuri@mvista.com>2023-03-20 14:41:51 +0530
committerSteve Sakoman <steve@sakoman.com>2023-04-14 05:44:12 -1000
commit8064d53745efcae97df6199abc54765c3b2f54f6 (patch)
tree9192c820be7e0092b4953c275d3944296553d2c3 /meta/recipes-devtools
parent8ed92cf2b331781d15d12d02cb882698c6844803 (diff)
downloadpoky-8064d53745efcae97df6199abc54765c3b2f54f6.tar.gz
git: Security fix for CVE-2023-22490 and CVE-2023-23946
Upstream-Status: Backport from https://github.com/git/git/commit/58325b93c5b6212697b088371809e9948fee8052 & https://github.com/git/git/commit/cf8f6ce02a13f4d1979a53241afbee15a293fce9 & https://github.com/git/git/commit/bffc762f87ae8d18c6001bf0044a76004245754c (From OE-Core rev: 071fb3b177bcbdd02ae2c28aad97af681c091e42) Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
Diffstat (limited to 'meta/recipes-devtools')
-rw-r--r--meta/recipes-devtools/git/files/CVE-2023-22490-1.patch179
-rw-r--r--meta/recipes-devtools/git/files/CVE-2023-22490-2.patch122
-rw-r--r--meta/recipes-devtools/git/files/CVE-2023-22490-3.patch154
-rw-r--r--meta/recipes-devtools/git/files/CVE-2023-23946.patch184
-rw-r--r--meta/recipes-devtools/git/git.inc4
5 files changed, 643 insertions, 0 deletions
diff --git a/meta/recipes-devtools/git/files/CVE-2023-22490-1.patch b/meta/recipes-devtools/git/files/CVE-2023-22490-1.patch
new file mode 100644
index 0000000000..cc9b448c5c
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2023-22490-1.patch
@@ -0,0 +1,179 @@
1From 58325b93c5b6212697b088371809e9948fee8052 Mon Sep 17 00:00:00 2001
2From: Taylor Blau <me@ttaylorr.com>
3Date: Tue, 24 Jan 2023 19:43:45 -0500
4Subject: [PATCH 1/3] t5619: demonstrate clone_local() with ambiguous transport
5
6When cloning a repository, Git must determine (a) what transport
7mechanism to use, and (b) whether or not the clone is local.
8
9Since f38aa83 (use local cloning if insteadOf makes a local URL,
102014-07-17), the latter check happens after the remote has been
11initialized, and references the remote's URL instead of the local path.
12This is done to make it possible for a `url.<base>.insteadOf` rule to
13convert a remote URL into a local one, in which case the `clone_local()`
14mechanism should be used.
15
16However, with a specially crafted repository, Git can be tricked into
17using a non-local transport while still setting `is_local` to "1" and
18using the `clone_local()` optimization. The below test case
19demonstrates such an instance, and shows that it can be used to include
20arbitrary (known) paths in the working copy of a cloned repository on a
21victim's machine[^1], even if local file clones are forbidden by
22`protocol.file.allow`.
23
24This happens in a few parts:
25
26 1. We first call `get_repo_path()` to see if the remote is a local
27 path. If it is, we replace the repo name with its absolute path.
28
29 2. We then call `transport_get()` on the repo name and decide how to
30 access it. If it was turned into an absolute path in the previous
31 step, then we should always treat it like a file.
32
33 3. We use `get_repo_path()` again, and set `is_local` as appropriate.
34 But it's already too late to rewrite the repo name as an absolute
35 path, since we've already fed it to the transport code.
36
37The attack works by including a submodule whose URL corresponds to a
38path on disk. In the below example, the repository "sub" is reachable
39via the dumb HTTP protocol at (something like):
40
41 http://127.0.0.1:NNNN/dumb/sub.git
42
43However, the path "http:/127.0.0.1:NNNN/dumb" (that is, a top-level
44directory called "http:", then nested directories "127.0.0.1:NNNN", and
45"dumb") exists within the repository, too.
46
47To determine this, it first picks the appropriate transport, which is
48dumb HTTP. It then uses the remote's URL in order to determine whether
49the repository exists locally on disk. However, the malicious repository
50also contains an embedded stub repository which is the target of a
51symbolic link at the local path corresponding to the "sub" repository on
52disk (i.e., there is a symbolic link at "http:/127.0.0.1/dumb/sub.git",
53pointing to the stub repository via ".git/modules/sub/../../../repo").
54
55This stub repository fools Git into thinking that a local repository
56exists at that URL and thus can be cloned locally. The affected call is
57in `get_repo_path()`, which in turn calls `get_repo_path_1()`, which
58locates a valid repository at that target.
59
60This then causes Git to set the `is_local` variable to "1", and in turn
61instructs Git to clone the repository using its local clone optimization
62via the `clone_local()` function.
63
64The exploit comes into play because the stub repository's top-level
65"$GIT_DIR/objects" directory is a symbolic link which can point to an
66arbitrary path on the victim's machine. `clone_local()` resolves the
67top-level "objects" directory through a `stat(2)` call, meaning that we
68read through the symbolic link and copy or hardlink the directory
69contents at the destination of the link.
70
71In other words, we can get steps (1) and (3) to disagree by leveraging
72the dangling symlink to pick a non-local transport in the first step,
73and then set is_local to "1" in the third step when cloning with
74`--separate-git-dir`, which makes the symlink non-dangling.
75
76This can result in data-exfiltration on the victim's machine when
77sensitive data is at a known path (e.g., "/home/$USER/.ssh").
78
79The appropriate fix is two-fold:
80
81 - Resolve the transport later on (to avoid using the local
82 clone optimization with a non-local transport).
83
84 - Avoid reading through the top-level "objects" directory when
85 (correctly) using the clone_local() optimization.
86
87This patch merely demonstrates the issue. The following two patches will
88implement each part of the above fix, respectively.
89
90[^1]: Provided that any target directory does not contain symbolic
91 links, in which case the changes from 6f054f9 (builtin/clone.c:
92 disallow `--local` clones with symlinks, 2022-07-28) will abort the
93 clone.
94
95Reported-by: yvvdwf <yvvdwf@gmail.com>
96Signed-off-by: Taylor Blau <me@ttaylorr.com>
97Signed-off-by: Junio C Hamano <gitster@pobox.com>
98
99Upstream-Status: Backport
100[https://github.com/git/git/commit/58325b93c5b6212697b088371809e9948fee8052]
101CVE: CVE-2023-22490
102Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
103---
104 t/t5619-clone-local-ambiguous-transport.sh | 63 ++++++++++++++++++++++
105 1 file changed, 63 insertions(+)
106 create mode 100644 t/t5619-clone-local-ambiguous-transport.sh
107
108diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh
109new file mode 100644
110index 0000000..7ebd31a
111--- /dev/null
112+++ b/t/t5619-clone-local-ambiguous-transport.sh
113@@ -0,0 +1,63 @@
114+#!/bin/sh
115+
116+test_description='test local clone with ambiguous transport'
117+
118+. ./test-lib.sh
119+. "$TEST_DIRECTORY/lib-httpd.sh"
120+
121+if ! test_have_prereq SYMLINKS
122+then
123+ skip_all='skipping test, symlink support unavailable'
124+ test_done
125+fi
126+
127+start_httpd
128+
129+REPO="$HTTPD_DOCUMENT_ROOT_PATH/sub.git"
130+URI="$HTTPD_URL/dumb/sub.git"
131+
132+test_expect_success 'setup' '
133+ mkdir -p sensitive &&
134+ echo "secret" >sensitive/secret &&
135+
136+ git init --bare "$REPO" &&
137+ test_commit_bulk -C "$REPO" --ref=main 1 &&
138+
139+ git -C "$REPO" update-ref HEAD main &&
140+ git -C "$REPO" update-server-info &&
141+
142+ git init malicious &&
143+ (
144+ cd malicious &&
145+
146+ git submodule add "$URI" &&
147+
148+ mkdir -p repo/refs &&
149+ touch repo/refs/.gitkeep &&
150+ printf "ref: refs/heads/a" >repo/HEAD &&
151+ ln -s "$(cd .. && pwd)/sensitive" repo/objects &&
152+
153+ mkdir -p "$HTTPD_URL/dumb" &&
154+ ln -s "../../../.git/modules/sub/../../../repo/" "$URI" &&
155+
156+ git add . &&
157+ git commit -m "initial commit"
158+ ) &&
159+
160+ # Delete all of the references in our malicious submodule to
161+ # avoid the client attempting to checkout any objects (which
162+ # will be missing, and thus will cause the clone to fail before
163+ # we can trigger the exploit).
164+ git -C "$REPO" for-each-ref --format="delete %(refname)" >in &&
165+ git -C "$REPO" update-ref --stdin <in &&
166+ git -C "$REPO" update-server-info
167+'
168+
169+test_expect_failure 'ambiguous transport does not lead to arbitrary file-inclusion' '
170+ git clone malicious clone &&
171+ git -C clone submodule update --init &&
172+
173+ test_path_is_missing clone/.git/modules/sub/objects/secret
174+'
175+
176+test_done
177--
1782.25.1
179
diff --git a/meta/recipes-devtools/git/files/CVE-2023-22490-2.patch b/meta/recipes-devtools/git/files/CVE-2023-22490-2.patch
new file mode 100644
index 0000000000..0b5b40f827
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2023-22490-2.patch
@@ -0,0 +1,122 @@
1From cf8f6ce02a13f4d1979a53241afbee15a293fce9 Mon Sep 17 00:00:00 2001
2From: Taylor Blau <me@ttaylorr.com>
3Date: Tue, 24 Jan 2023 19:43:48 -0500
4Subject: [PATCH 2/3] clone: delay picking a transport until after get_repo_path()
5
6In the previous commit, t5619 demonstrates an issue where two calls to
7`get_repo_path()` could trick Git into using its local clone mechanism
8in conjunction with a non-local transport.
9
10That sequence is:
11
12 - the starting state is that the local path https:/example.com/foo is a
13 symlink that points to ../../../.git/modules/foo. So it's dangling.
14
15 - get_repo_path() sees that no such path exists (because it's
16 dangling), and thus we do not canonicalize it into an absolute path
17
18 - because we're using --separate-git-dir, we create .git/modules/foo.
19 Now our symlink is no longer dangling!
20
21 - we pass the url to transport_get(), which sees it as an https URL.
22
23 - we call get_repo_path() again, on the url. This second call was
24 introduced by f38aa83 (use local cloning if insteadOf makes a
25 local URL, 2014-07-17). The idea is that we want to pull the url
26 fresh from the remote.c API, because it will apply any aliases.
27
28And of course now it sees that there is a local file, which is a
29mismatch with the transport we already selected.
30
31The issue in the above sequence is calling `transport_get()` before
32deciding whether or not the repository is indeed local, and not passing
33in an absolute path if it is local.
34
35This is reminiscent of a similar bug report in [1], where it was
36suggested to perform the `insteadOf` lookup earlier. Taking that
37approach may not be as straightforward, since the intent is to store the
38original URL in the config, but to actually fetch from the insteadOf
39one, so conflating the two early on is a non-starter.
40
41Note: we pass the path returned by `get_repo_path(remote->url[0])`,
42which should be the same as `repo_name` (aside from any `insteadOf`
43rewrites).
44
45We *could* pass `absolute_pathdup()` of the same argument, which
4686521ac (Bring local clone's origin URL in line with that of a remote
47clone, 2008-09-01) indicates may differ depending on the presence of
48".git/" for a non-bare repo. That matters for forming relative submodule
49paths, but doesn't matter for the second call, since we're just feeding
50it to the transport code, which is fine either way.
51
52[1]: https://lore.kernel.org/git/CAMoD=Bi41mB3QRn3JdZL-FGHs4w3C2jGpnJB-CqSndO7FMtfzA@mail.gmail.com/
53
54Signed-off-by: Jeff King <peff@peff.net>
55Signed-off-by: Taylor Blau <me@ttaylorr.com>
56Signed-off-by: Junio C Hamano <gitster@pobox.com>
57
58Upstream-Status: Backport
59[https://github.com/git/git/commit/cf8f6ce02a13f4d1979a53241afbee15a293fce9]
60CVE: CVE-2023-22490
61Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
62---
63 builtin/clone.c | 8 ++++----
64 t/t5619-clone-local-ambiguous-transport.sh | 15 +++++++++++----
65 2 files changed, 15 insertions(+), 8 deletions(-)
66
67diff --git a/builtin/clone.c b/builtin/clone.c
68index 53e04b1..b57e703 100644
69--- a/builtin/clone.c
70+++ b/builtin/clone.c
71@@ -1112,10 +1112,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
72 branch_top.buf);
73 refspec_append(&remote->fetch, default_refspec.buf);
74
75- transport = transport_get(remote, remote->url[0]);
76- transport_set_verbosity(transport, option_verbosity, option_progress);
77- transport->family = family;
78-
79 path = get_repo_path(remote->url[0], &is_bundle);
80 is_local = option_local != 0 && path && !is_bundle;
81 if (is_local) {
82@@ -1135,6 +1131,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
83 }
84 if (option_local > 0 && !is_local)
85 warning(_("--local is ignored"));
86+
87+ transport = transport_get(remote, path ? path : remote->url[0]);
88+ transport_set_verbosity(transport, option_verbosity, option_progress);
89+ transport->family = family;
90 transport->cloning = 1;
91
92 transport_set_option(transport, TRANS_OPT_KEEP, "yes");
93diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh
94index 7ebd31a..cce62bf 100644
95--- a/t/t5619-clone-local-ambiguous-transport.sh
96+++ b/t/t5619-clone-local-ambiguous-transport.sh
97@@ -53,11 +53,18 @@ test_expect_success 'setup' '
98 git -C "$REPO" update-server-info
99 '
100
101-test_expect_failure 'ambiguous transport does not lead to arbitrary file-inclusion' '
102+test_expect_success 'ambiguous transport does not lead to arbitrary file-inclusion' '
103 git clone malicious clone &&
104- git -C clone submodule update --init &&
105-
106- test_path_is_missing clone/.git/modules/sub/objects/secret
107+ test_must_fail git -C clone submodule update --init 2>err &&
108+
109+ test_path_is_missing clone/.git/modules/sub/objects/secret &&
110+ # We would actually expect "transport .file. not allowed" here,
111+ # but due to quirks of the URL detection in Git, we mis-parse
112+ # the absolute path as a bogus URL and die before that step.
113+ #
114+ # This works for now, and if we ever fix the URL detection, it
115+ # is OK to change this to detect the transport error.
116+ grep "protocol .* is not supported" err
117 '
118
119 test_done
120--
1212.25.1
122
diff --git a/meta/recipes-devtools/git/files/CVE-2023-22490-3.patch b/meta/recipes-devtools/git/files/CVE-2023-22490-3.patch
new file mode 100644
index 0000000000..08fb7f840b
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2023-22490-3.patch
@@ -0,0 +1,154 @@
1From bffc762f87ae8d18c6001bf0044a76004245754c Mon Sep 17 00:00:00 2001
2From: Taylor Blau <me@ttaylorr.com>
3Date: Tue, 24 Jan 2023 19:43:51 -0500
4Subject: [PATCH 3/3] dir-iterator: prevent top-level symlinks without FOLLOW_SYMLINKS
5
6When using the dir_iterator API, we first stat(2) the base path, and
7then use that as a starting point to enumerate the directory's contents.
8
9If the directory contains symbolic links, we will immediately die() upon
10encountering them without the `FOLLOW_SYMLINKS` flag. The same is not
11true when resolving the top-level directory, though.
12
13As explained in a previous commit, this oversight in 6f054f9
14(builtin/clone.c: disallow `--local` clones with symlinks, 2022-07-28)
15can be used as an attack vector to include arbitrary files on a victim's
16filesystem from outside of the repository.
17
18Prevent resolving top-level symlinks unless the FOLLOW_SYMLINKS flag is
19given, which will cause clones of a repository with a symlink'd
20"$GIT_DIR/objects" directory to fail.
21
22Signed-off-by: Taylor Blau <me@ttaylorr.com>
23Signed-off-by: Junio C Hamano <gitster@pobox.com>
24
25Upstream-Status: Backport
26[https://github.com/git/git/commit/bffc762f87ae8d18c6001bf0044a76004245754c]
27CVE: CVE-2023-22490
28Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
29---
30 dir-iterator.c | 13 +++++++++----
31 dir-iterator.h | 5 +++++
32 t/t0066-dir-iterator.sh | 27 ++++++++++++++++++++++++++-
33 t/t5604-clone-reference.sh | 16 ++++++++++++++++
34 4 files changed, 56 insertions(+), 5 deletions(-)
35
36diff --git a/dir-iterator.c b/dir-iterator.c
37index b17e9f9..3764dd8 100644
38--- a/dir-iterator.c
39+++ b/dir-iterator.c
40@@ -203,7 +203,7 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
41 {
42 struct dir_iterator_int *iter = xcalloc(1, sizeof(*iter));
43 struct dir_iterator *dir_iterator = &iter->base;
44- int saved_errno;
45+ int saved_errno, err;
46
47 strbuf_init(&iter->base.path, PATH_MAX);
48 strbuf_addstr(&iter->base.path, path);
49@@ -213,10 +213,15 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
50 iter->flags = flags;
51
52 /*
53- * Note: stat already checks for NULL or empty strings and
54- * inexistent paths.
55+ * Note: stat/lstat already checks for NULL or empty strings and
56+ * nonexistent paths.
57 */
58- if (stat(iter->base.path.buf, &iter->base.st) < 0) {
59+ if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
60+ err = stat(iter->base.path.buf, &iter->base.st);
61+ else
62+ err = lstat(iter->base.path.buf, &iter->base.st);
63+
64+ if (err < 0) {
65 saved_errno = errno;
66 goto error_out;
67 }
68diff --git a/dir-iterator.h b/dir-iterator.h
69index 0822915..e3b6ff2 100644
70--- a/dir-iterator.h
71+++ b/dir-iterator.h
72@@ -61,6 +61,11 @@
73 * not the symlinks themselves, which is the default behavior. Broken
74 * symlinks are ignored.
75 *
76+ * Note: setting DIR_ITERATOR_FOLLOW_SYMLINKS affects resolving the
77+ * starting path as well (e.g., attempting to iterate starting at a
78+ * symbolic link pointing to a directory without FOLLOW_SYMLINKS will
79+ * result in an error).
80+ *
81 * Warning: circular symlinks are also followed when
82 * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with
83 * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set.
84diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh
85index 92910e4..c826f60 100755
86--- a/t/t0066-dir-iterator.sh
87+++ b/t/t0066-dir-iterator.sh
88@@ -109,7 +109,9 @@ test_expect_success SYMLINKS 'setup dirs with symlinks' '
89 mkdir -p dir5/a/c &&
90 ln -s ../c dir5/a/b/d &&
91 ln -s ../ dir5/a/b/e &&
92- ln -s ../../ dir5/a/b/f
93+ ln -s ../../ dir5/a/b/f &&
94+
95+ ln -s dir4 dir6
96 '
97
98 test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' '
99@@ -145,4 +147,27 @@ test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag
100 test_cmp expected-follow-sorted-output actual-follow-sorted-output
101 '
102
103+test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' '
104+ test_must_fail test-tool dir-iterator ./dir6 >out &&
105+
106+ grep "ENOTDIR" out
107+'
108+
109+test_expect_success SYMLINKS 'dir-iterator resolves top-level symlinks w/ follow flag' '
110+ cat >expected-follow-sorted-output <<-EOF &&
111+ [d] (a) [a] ./dir6/a
112+ [d] (a/f) [f] ./dir6/a/f
113+ [d] (a/f/c) [c] ./dir6/a/f/c
114+ [d] (b) [b] ./dir6/b
115+ [d] (b/c) [c] ./dir6/b/c
116+ [f] (a/d) [d] ./dir6/a/d
117+ [f] (a/e) [e] ./dir6/a/e
118+ EOF
119+
120+ test-tool dir-iterator --follow-symlinks ./dir6 >out &&
121+ sort out >actual-follow-sorted-output &&
122+
123+ test_cmp expected-follow-sorted-output actual-follow-sorted-output
124+'
125+
126 test_done
127diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh
128index 4894237..615b981 100755
129--- a/t/t5604-clone-reference.sh
130+++ b/t/t5604-clone-reference.sh
131@@ -354,4 +354,20 @@ test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at obje
132 test_must_be_empty T--shared.objects-symlinks.raw
133 '
134
135+test_expect_success SYMLINKS 'clone repo with symlinked objects directory' '
136+ test_when_finished "rm -fr sensitive malicious" &&
137+
138+ mkdir -p sensitive &&
139+ echo "secret" >sensitive/file &&
140+
141+ git init malicious &&
142+ rm -fr malicious/.git/objects &&
143+ ln -s "$(pwd)/sensitive" ./malicious/.git/objects &&
144+
145+ test_must_fail git clone --local malicious clone 2>err &&
146+
147+ test_path_is_missing clone &&
148+ grep "failed to start iterator over" err
149+'
150+
151 test_done
152--
1532.25.1
154
diff --git a/meta/recipes-devtools/git/files/CVE-2023-23946.patch b/meta/recipes-devtools/git/files/CVE-2023-23946.patch
new file mode 100644
index 0000000000..3629ff57b2
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2023-23946.patch
@@ -0,0 +1,184 @@
1From fade728df1221598f42d391cf377e9e84a32053f Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 2 Feb 2023 11:54:34 +0100
4Subject: [PATCH] apply: fix writing behind newly created symbolic links
5
6When writing files git-apply(1) initially makes sure that none of the
7files it is about to create are behind a symlink:
8
9```
10 $ git init repo
11 Initialized empty Git repository in /tmp/repo/.git/
12 $ cd repo/
13 $ ln -s dir symlink
14 $ git apply - <<EOF
15 diff --git a/symlink/file b/symlink/file
16 new file mode 100644
17 index 0000000..e69de29
18 EOF
19 error: affected file 'symlink/file' is beyond a symbolic link
20```
21
22This safety mechanism is crucial to ensure that we don't write outside
23of the repository's working directory. It can be fooled though when the
24patch that is being applied creates the symbolic link in the first
25place, which can lead to writing files in arbitrary locations.
26
27Fix this by checking whether the path we're about to create is
28beyond a symlink or not. Tightening these checks like this should be
29fine as we already have these precautions in Git as explained
30above. Ideally, we should update the check we do up-front before
31starting to reflect the computed changes to the working tree so that
32we catch this case as well, but as part of embargoed security work,
33adding an equivalent check just before we try to write out a file
34should serve us well as a reasonable first step.
35
36Digging back into history shows that this vulnerability has existed
37since at least Git v2.9.0. As Git v2.8.0 and older don't build on my
38system anymore I cannot tell whether older versions are affected, as
39well.
40
41Reported-by: Joern Schneeweisz <jschneeweisz@gitlab.com>
42Signed-off-by: Patrick Steinhardt <ps@pks.im>
43Signed-off-by: Junio C Hamano <gitster@pobox.com>
44
45Upstream-Status: Backport
46[https://github.com/git/git/commit/fade728df1221598f42d391cf377e9e84a32053f]
47CVE: CVE-2023-23946
48Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
49---
50 apply.c | 27 ++++++++++++++
51 t/t4115-apply-symlink.sh | 81 ++++++++++++++++++++++++++++++++++++++++
52 2 files changed, 108 insertions(+)
53
54diff --git a/apply.c b/apply.c
55index f8a046a..4f303bf 100644
56--- a/apply.c
57+++ b/apply.c
58@@ -4373,6 +4373,33 @@ static int create_one_file(struct apply_state *state,
59 if (state->cached)
60 return 0;
61
62+ /*
63+ * We already try to detect whether files are beyond a symlink in our
64+ * up-front checks. But in the case where symlinks are created by any
65+ * of the intermediate hunks it can happen that our up-front checks
66+ * didn't yet see the symlink, but at the point of arriving here there
67+ * in fact is one. We thus repeat the check for symlinks here.
68+ *
69+ * Note that this does not make the up-front check obsolete as the
70+ * failure mode is different:
71+ *
72+ * - The up-front checks cause us to abort before we have written
73+ * anything into the working directory. So when we exit this way the
74+ * working directory remains clean.
75+ *
76+ * - The checks here happen in the middle of the action where we have
77+ * already started to apply the patch. The end result will be a dirty
78+ * working directory.
79+ *
80+ * Ideally, we should update the up-front checks to catch what would
81+ * happen when we apply the patch before we damage the working tree.
82+ * We have all the information necessary to do so. But for now, as a
83+ * part of embargoed security work, having this check would serve as a
84+ * reasonable first step.
85+ */
86+ if (path_is_beyond_symlink(state, path))
87+ return error(_("affected file '%s' is beyond a symbolic link"), path);
88+
89 res = try_create_file(state, path, mode, buf, size);
90 if (res < 0)
91 return -1;
92diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
93index 872fcda..1acb7b2 100755
94--- a/t/t4115-apply-symlink.sh
95+++ b/t/t4115-apply-symlink.sh
96@@ -44,4 +44,85 @@ test_expect_success 'apply --index symlink patch' '
97
98 '
99
100+test_expect_success 'symlink setup' '
101+ ln -s .git symlink &&
102+ git add symlink &&
103+ git commit -m "add symlink"
104+'
105+
106+test_expect_success SYMLINKS 'symlink escape when creating new files' '
107+ test_when_finished "git reset --hard && git clean -dfx" &&
108+
109+ cat >patch <<-EOF &&
110+ diff --git a/symlink b/renamed-symlink
111+ similarity index 100%
112+ rename from symlink
113+ rename to renamed-symlink
114+ --
115+ diff --git /dev/null b/renamed-symlink/create-me
116+ new file mode 100644
117+ index 0000000..039727e
118+ --- /dev/null
119+ +++ b/renamed-symlink/create-me
120+ @@ -0,0 +1,1 @@
121+ +busted
122+ EOF
123+
124+ test_must_fail git apply patch 2>stderr &&
125+ cat >expected_stderr <<-EOF &&
126+ error: affected file ${SQ}renamed-symlink/create-me${SQ} is beyond a symbolic link
127+ EOF
128+ test_cmp expected_stderr stderr &&
129+ ! test_path_exists .git/create-me
130+'
131+
132+test_expect_success SYMLINKS 'symlink escape when modifying file' '
133+ test_when_finished "git reset --hard && git clean -dfx" &&
134+ touch .git/modify-me &&
135+
136+ cat >patch <<-EOF &&
137+ diff --git a/symlink b/renamed-symlink
138+ similarity index 100%
139+ rename from symlink
140+ rename to renamed-symlink
141+ --
142+ diff --git a/renamed-symlink/modify-me b/renamed-symlink/modify-me
143+ index 1111111..2222222 100644
144+ --- a/renamed-symlink/modify-me
145+ +++ b/renamed-symlink/modify-me
146+ @@ -0,0 +1,1 @@
147+ +busted
148+ EOF
149+
150+ test_must_fail git apply patch 2>stderr &&
151+ cat >expected_stderr <<-EOF &&
152+ error: renamed-symlink/modify-me: No such file or directory
153+ EOF
154+ test_cmp expected_stderr stderr &&
155+ test_must_be_empty .git/modify-me
156+'
157+
158+test_expect_success SYMLINKS 'symlink escape when deleting file' '
159+ test_when_finished "git reset --hard && git clean -dfx && rm .git/delete-me" &&
160+ touch .git/delete-me &&
161+
162+ cat >patch <<-EOF &&
163+ diff --git a/symlink b/renamed-symlink
164+ similarity index 100%
165+ rename from symlink
166+ rename to renamed-symlink
167+ --
168+ diff --git a/renamed-symlink/delete-me b/renamed-symlink/delete-me
169+ deleted file mode 100644
170+ index 1111111..0000000 100644
171+ EOF
172+
173+ test_must_fail git apply patch 2>stderr &&
174+ cat >expected_stderr <<-EOF &&
175+ error: renamed-symlink/delete-me: No such file or directory
176+ EOF
177+ test_cmp expected_stderr stderr &&
178+ test_path_is_file .git/delete-me
179+'
180+
181 test_done
182--
1832.25.1
184
diff --git a/meta/recipes-devtools/git/git.inc b/meta/recipes-devtools/git/git.inc
index 235cb8e4c0..36318eed20 100644
--- a/meta/recipes-devtools/git/git.inc
+++ b/meta/recipes-devtools/git/git.inc
@@ -24,6 +24,10 @@ SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \
24 file://CVE-2022-41903-10.patch \ 24 file://CVE-2022-41903-10.patch \
25 file://CVE-2022-41903-11.patch \ 25 file://CVE-2022-41903-11.patch \
26 file://CVE-2022-41903-12.patch \ 26 file://CVE-2022-41903-12.patch \
27 file://CVE-2023-22490-1.patch \
28 file://CVE-2023-22490-2.patch \
29 file://CVE-2023-22490-3.patch \
30 file://CVE-2023-23946.patch \
27 " 31 "
28S = "${WORKDIR}/git-${PV}" 32S = "${WORKDIR}/git-${PV}"
29 33