diff options
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.patch | 179 |
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 @@ | |||
1 | From 58325b93c5b6212697b088371809e9948fee8052 Mon Sep 17 00:00:00 2001 | ||
2 | From: Taylor Blau <me@ttaylorr.com> | ||
3 | Date: Tue, 24 Jan 2023 19:43:45 -0500 | ||
4 | Subject: [PATCH 1/3] t5619: demonstrate clone_local() with ambiguous transport | ||
5 | |||
6 | When cloning a repository, Git must determine (a) what transport | ||
7 | mechanism to use, and (b) whether or not the clone is local. | ||
8 | |||
9 | Since f38aa83 (use local cloning if insteadOf makes a local URL, | ||
10 | 2014-07-17), the latter check happens after the remote has been | ||
11 | initialized, and references the remote's URL instead of the local path. | ||
12 | This is done to make it possible for a `url.<base>.insteadOf` rule to | ||
13 | convert a remote URL into a local one, in which case the `clone_local()` | ||
14 | mechanism should be used. | ||
15 | |||
16 | However, with a specially crafted repository, Git can be tricked into | ||
17 | using a non-local transport while still setting `is_local` to "1" and | ||
18 | using the `clone_local()` optimization. The below test case | ||
19 | demonstrates such an instance, and shows that it can be used to include | ||
20 | arbitrary (known) paths in the working copy of a cloned repository on a | ||
21 | victim's machine[^1], even if local file clones are forbidden by | ||
22 | `protocol.file.allow`. | ||
23 | |||
24 | This 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 | |||
37 | The attack works by including a submodule whose URL corresponds to a | ||
38 | path on disk. In the below example, the repository "sub" is reachable | ||
39 | via the dumb HTTP protocol at (something like): | ||
40 | |||
41 | http://127.0.0.1:NNNN/dumb/sub.git | ||
42 | |||
43 | However, the path "http:/127.0.0.1:NNNN/dumb" (that is, a top-level | ||
44 | directory called "http:", then nested directories "127.0.0.1:NNNN", and | ||
45 | "dumb") exists within the repository, too. | ||
46 | |||
47 | To determine this, it first picks the appropriate transport, which is | ||
48 | dumb HTTP. It then uses the remote's URL in order to determine whether | ||
49 | the repository exists locally on disk. However, the malicious repository | ||
50 | also contains an embedded stub repository which is the target of a | ||
51 | symbolic link at the local path corresponding to the "sub" repository on | ||
52 | disk (i.e., there is a symbolic link at "http:/127.0.0.1/dumb/sub.git", | ||
53 | pointing to the stub repository via ".git/modules/sub/../../../repo"). | ||
54 | |||
55 | This stub repository fools Git into thinking that a local repository | ||
56 | exists at that URL and thus can be cloned locally. The affected call is | ||
57 | in `get_repo_path()`, which in turn calls `get_repo_path_1()`, which | ||
58 | locates a valid repository at that target. | ||
59 | |||
60 | This then causes Git to set the `is_local` variable to "1", and in turn | ||
61 | instructs Git to clone the repository using its local clone optimization | ||
62 | via the `clone_local()` function. | ||
63 | |||
64 | The 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 | ||
66 | arbitrary path on the victim's machine. `clone_local()` resolves the | ||
67 | top-level "objects" directory through a `stat(2)` call, meaning that we | ||
68 | read through the symbolic link and copy or hardlink the directory | ||
69 | contents at the destination of the link. | ||
70 | |||
71 | In other words, we can get steps (1) and (3) to disagree by leveraging | ||
72 | the dangling symlink to pick a non-local transport in the first step, | ||
73 | and then set is_local to "1" in the third step when cloning with | ||
74 | `--separate-git-dir`, which makes the symlink non-dangling. | ||
75 | |||
76 | This can result in data-exfiltration on the victim's machine when | ||
77 | sensitive data is at a known path (e.g., "/home/$USER/.ssh"). | ||
78 | |||
79 | The 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 | |||
87 | This patch merely demonstrates the issue. The following two patches will | ||
88 | implement 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 | |||
95 | Reported-by: yvvdwf <yvvdwf@gmail.com> | ||
96 | Signed-off-by: Taylor Blau <me@ttaylorr.com> | ||
97 | Signed-off-by: Junio C Hamano <gitster@pobox.com> | ||
98 | |||
99 | Upstream-Status: Backport | ||
100 | [https://github.com/git/git/commit/58325b93c5b6212697b088371809e9948fee8052] | ||
101 | CVE: CVE-2023-22490 | ||
102 | Signed-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 | |||
108 | diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh | ||
109 | new file mode 100644 | ||
110 | index 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 | -- | ||
178 | 2.25.1 | ||
179 | |||