summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/git/files/CVE-2023-22490-1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/git/files/CVE-2023-22490-1.patch')
-rw-r--r--meta/recipes-devtools/git/files/CVE-2023-22490-1.patch179
1 files changed, 179 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