summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/git
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/git')
-rw-r--r--meta/recipes-devtools/git/files/CVE-2021-40330.patch108
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-23521.patch367
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-01.patch39
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-02.patch187
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-03.patch146
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-04.patch150
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-05.patch98
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-06.patch90
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-07.patch123
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-08.patch67
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-09.patch162
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-10.patch99
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-11.patch90
-rw-r--r--meta/recipes-devtools/git/files/CVE-2022-41903-12.patch124
-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/files/CVE-2023-25652.patch94
-rw-r--r--meta/recipes-devtools/git/files/CVE-2023-29007.patch159
-rw-r--r--meta/recipes-devtools/git/git.inc35
-rw-r--r--meta/recipes-devtools/git/git/fixsort.patch36
-rw-r--r--meta/recipes-devtools/git/git_2.24.4.bb (renamed from meta/recipes-devtools/git/git_2.24.3.bb)4
23 files changed, 2813 insertions, 4 deletions
diff --git a/meta/recipes-devtools/git/files/CVE-2021-40330.patch b/meta/recipes-devtools/git/files/CVE-2021-40330.patch
new file mode 100644
index 0000000000..725f98f0b7
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2021-40330.patch
@@ -0,0 +1,108 @@
1From e77ca0c7d577408878d2b3e8c7336e6119cb3931 Mon Sep 17 00:00:00 2001
2From: Minjae Kim <flowergom@gmail.com>
3Date: Thu, 25 Nov 2021 06:36:26 +0000
4Subject: [PATCH] git_connect_git(): forbid newlines in host and path
5
6When we connect to a git:// server, we send an initial request that
7looks something like:
8
9 002dgit-upload-pack repo.git\0host=example.com
10
11If the repo path contains a newline, then it's included literally, and
12we get:
13
14 002egit-upload-pack repo
15 .git\0host=example.com
16
17This works fine if you really do have a newline in your repository name;
18the server side uses the pktline framing to parse the string, not
19newlines. However, there are many _other_ protocols in the wild that do
20parse on newlines, such as HTTP. So a carefully constructed git:// URL
21can actually turn into a valid HTTP request. For example:
22
23 git://localhost:1234/%0d%0a%0d%0aGET%20/%20HTTP/1.1 %0d%0aHost:localhost%0d%0a%0d%0a
24
25becomes:
26
27 0050git-upload-pack /
28 GET / HTTP/1.1
29 Host:localhost
30
31 host=localhost:1234
32
33on the wire. Again, this isn't a problem for a real Git server, but it
34does mean that feeding a malicious URL to Git (e.g., through a
35submodule) can cause it to make unexpected cross-protocol requests.
36Since repository names with newlines are presumably quite rare (and
37indeed, we already disallow them in git-over-http), let's just disallow
38them over this protocol.
39
40Hostnames could likewise inject a newline, but this is unlikely a
41problem in practice; we'd try resolving the hostname with a newline in
42it, which wouldn't work. Still, it doesn't hurt to err on the side of
43caution there, since we would not expect them to work in the first
44place.
45
46The ssh and local code paths are unaffected by this patch. In both cases
47we're trying to run upload-pack via a shell, and will quote the newline
48so that it makes it intact. An attacker can point an ssh url at an
49arbitrary port, of course, but unless there's an actual ssh server
50there, we'd never get as far as sending our shell command anyway. We
51_could_ similarly restrict newlines in those protocols out of caution,
52but there seems little benefit to doing so.
53
54The new test here is run alongside the git-daemon tests, which cover the
55same protocol, but it shouldn't actually contact the daemon at all. In
56theory we could make the test more robust by setting up an actual
57repository with a newline in it (so that our clone would succeed if our
58new check didn't kick in). But a repo directory with newline in it is
59likely not portable across all filesystems. Likewise, we could check
60git-daemon's log that it was not contacted at all, but we do not
61currently record the log (and anyway, it would make the test racy with
62the daemon's log write). We'll just check the client-side stderr to make
63sure we hit the expected code path.
64
65Reported-by: Harold Kim <h.kim@flatt.tech>
66Signed-off-by: Jeff King <peff@peff.net>
67Signed-off-by: Junio C Hamano <gitster@pobox.com>
68
69Upstream-Status: Backported [https://github.com/git/git/commit/a02ea577174ab8ed18f847cf1693f213e0b9c473]
70CVE: CVE-2021-40330
71Signed-off-by: Minjae Kim <flowergom@gmail.com>
72---
73 connect.c | 2 ++
74 t/t5570-git-daemon.sh | 5 +++++
75 2 files changed, 7 insertions(+)
76
77diff --git a/connect.c b/connect.c
78index b6451ab..929de9a 100644
79--- a/connect.c
80+++ b/connect.c
81@@ -1064,6 +1064,8 @@ static struct child_process *git_connect_git(int fd[2], char *hostandport,
82 target_host = xstrdup(hostandport);
83
84 transport_check_allowed("git");
85+ if (strchr(target_host, '\n') || strchr(path, '\n'))
86+ die(_("newline is forbidden in git:// hosts and repo paths"));
87
88 /*
89 * These underlying connection commands die() if they
90diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
91index 34487bb..79cd218 100755
92--- a/t/t5570-git-daemon.sh
93+++ b/t/t5570-git-daemon.sh
94@@ -103,6 +103,11 @@ test_expect_success 'fetch notices corrupt idx' '
95 )
96 '
97
98+test_expect_success 'client refuses to ask for repo with newline' '
99+ test_must_fail git clone "$GIT_DAEMON_URL/repo$LF.git" dst 2>stderr &&
100+ test_i18ngrep newline.is.forbidden stderr
101+'
102+
103 test_remote_error()
104 {
105 do_export=YesPlease
106--
1072.17.1
108
diff --git a/meta/recipes-devtools/git/files/CVE-2022-23521.patch b/meta/recipes-devtools/git/files/CVE-2022-23521.patch
new file mode 100644
index 0000000000..974546013d
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-23521.patch
@@ -0,0 +1,367 @@
1From eb22e7dfa23da6bd9aed9bd1dad69e1e8e167d24 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:45:15 +0100
4Subject: [PATCH] CVE-2022-23521
5
6attr: fix overflow when upserting attribute with overly long name
7
8The function `git_attr_internal()` is called to upsert attributes into
9the global map. And while all callers pass a `size_t`, the function
10itself accepts an `int` as the attribute name's length. This can lead to
11an integer overflow in case the attribute name is longer than `INT_MAX`.
12
13Now this overflow seems harmless as the first thing we do is to call
14`attr_name_valid()`, and that function only succeeds in case all chars
15in the range of `namelen` match a certain small set of chars. We thus
16can't do an out-of-bounds read as NUL is not part of that set and all
17strings passed to this function are NUL-terminated. And furthermore, we
18wouldn't ever read past the current attribute name anyway due to the
19same reason. And if validation fails we will return early.
20
21On the other hand it feels fragile to rely on this behaviour, even more
22so given that we pass `namelen` to `FLEX_ALLOC_MEM()`. So let's instead
23just do the correct thing here and accept a `size_t` as line length.
24
25Upstream-Status: Backport [https://github.com/git/git/commit/eb22e7dfa23da6bd9aed9bd1dad69e1e8e167d24 &https://github.com/git/git/commit/8d0d48cf2157cfb914db1f53b3fe40785b86f3aa & https://github.com/git/git/commit/24557209500e6ed618f04a8795a111a0c491a29c & https://github.com/git/git/commit/34ace8bad02bb14ecc5b631f7e3daaa7a9bba7d9 & https://github.com/git/git/commit/447ac906e189535e77dcb1f4bbe3f1bc917d4c12 & https://github.com/git/git/commit/e1e12e97ac73ded85f7d000da1063a774b3cc14f & https://github.com/git/git/commit/a60a66e409c265b2944f18bf43581c146812586d & https://github.com/git/git/commit/d74b1fd54fdbc45966d12ea907dece11e072fb2b & https://github.com/git/git/commit/dfa6b32b5e599d97448337ed4fc18dd50c90758f & https://github.com/git/git/commit/3c50032ff5289cc45659f21949c8d09e52164579
26
27CVE: CVE-2022-23521
28
29Reviewed-by: Sylvain Beucler <beuc@debian.org>
30Signed-off-by: Patrick Steinhardt <ps@pks.im>
31Signed-off-by: Junio C Hamano <gitster@pobox.com>
32Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
33---
34 attr.c | 97 +++++++++++++++++++++++++++----------------
35 attr.h | 12 ++++++
36 t/t0003-attributes.sh | 59 ++++++++++++++++++++++++++
37 3 files changed, 132 insertions(+), 36 deletions(-)
38
39diff --git a/attr.c b/attr.c
40index 11f19b5..63484ab 100644
41--- a/attr.c
42+++ b/attr.c
43@@ -29,7 +29,7 @@ static const char git_attr__unknown[] = "(builtin)unknown";
44 #endif
45
46 struct git_attr {
47- int attr_nr; /* unique attribute number */
48+ unsigned int attr_nr; /* unique attribute number */
49 char name[FLEX_ARRAY]; /* attribute name */
50 };
51
52@@ -221,7 +221,7 @@ static void report_invalid_attr(const char *name, size_t len,
53 * dictionary. If no entry is found, create a new attribute and store it in
54 * the dictionary.
55 */
56-static const struct git_attr *git_attr_internal(const char *name, int namelen)
57+static const struct git_attr *git_attr_internal(const char *name, size_t namelen)
58 {
59 struct git_attr *a;
60
61@@ -237,8 +237,8 @@ static const struct git_attr *git_attr_internal(const char *name, int namelen)
62 a->attr_nr = hashmap_get_size(&g_attr_hashmap.map);
63
64 attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a);
65- assert(a->attr_nr ==
66- (hashmap_get_size(&g_attr_hashmap.map) - 1));
67+ if (a->attr_nr != hashmap_get_size(&g_attr_hashmap.map) - 1)
68+ die(_("unable to add additional attribute"));
69 }
70
71 hashmap_unlock(&g_attr_hashmap);
72@@ -283,7 +283,7 @@ struct match_attr {
73 const struct git_attr *attr;
74 } u;
75 char is_macro;
76- unsigned num_attr;
77+ size_t num_attr;
78 struct attr_state state[FLEX_ARRAY];
79 };
80
81@@ -300,7 +300,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
82 struct attr_state *e)
83 {
84 const char *ep, *equals;
85- int len;
86+ size_t len;
87
88 ep = cp + strcspn(cp, blank);
89 equals = strchr(cp, '=');
90@@ -344,8 +344,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
91 static struct match_attr *parse_attr_line(const char *line, const char *src,
92 int lineno, int macro_ok)
93 {
94- int namelen;
95- int num_attr, i;
96+ size_t namelen, num_attr, i;
97 const char *cp, *name, *states;
98 struct match_attr *res = NULL;
99 int is_macro;
100@@ -356,6 +355,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
101 return NULL;
102 name = cp;
103
104+ if (strlen(line) >= ATTR_MAX_LINE_LENGTH) {
105+ warning(_("ignoring overly long attributes line %d"), lineno);
106+ return NULL;
107+ }
108+
109 if (*cp == '"' && !unquote_c_style(&pattern, name, &states)) {
110 name = pattern.buf;
111 namelen = pattern.len;
112@@ -392,10 +396,9 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
113 goto fail_return;
114 }
115
116- res = xcalloc(1,
117- sizeof(*res) +
118- sizeof(struct attr_state) * num_attr +
119- (is_macro ? 0 : namelen + 1));
120+ res = xcalloc(1, st_add3(sizeof(*res),
121+ st_mult(sizeof(struct attr_state), num_attr),
122+ is_macro ? 0 : namelen + 1));
123 if (is_macro) {
124 res->u.attr = git_attr_internal(name, namelen);
125 } else {
126@@ -458,11 +461,12 @@ struct attr_stack {
127
128 static void attr_stack_free(struct attr_stack *e)
129 {
130- int i;
131+ unsigned i;
132 free(e->origin);
133 for (i = 0; i < e->num_matches; i++) {
134 struct match_attr *a = e->attrs[i];
135- int j;
136+ size_t j;
137+
138 for (j = 0; j < a->num_attr; j++) {
139 const char *setto = a->state[j].setto;
140 if (setto == ATTR__TRUE ||
141@@ -671,8 +675,8 @@ static void handle_attr_line(struct attr_stack *res,
142 a = parse_attr_line(line, src, lineno, macro_ok);
143 if (!a)
144 return;
145- ALLOC_GROW(res->attrs, res->num_matches + 1, res->alloc);
146- res->attrs[res->num_matches++] = a;
147+ ALLOC_GROW_BY(res->attrs, res->num_matches, 1, res->alloc);
148+ res->attrs[res->num_matches - 1] = a;
149 }
150
151 static struct attr_stack *read_attr_from_array(const char **list)
152@@ -711,21 +715,37 @@ void git_attr_set_direction(enum git_attr_direction new_direction)
153
154 static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
155 {
156+ struct strbuf buf = STRBUF_INIT;
157 FILE *fp = fopen_or_warn(path, "r");
158 struct attr_stack *res;
159- char buf[2048];
160 int lineno = 0;
161+ int fd;
162+ struct stat st;
163
164 if (!fp)
165 return NULL;
166- res = xcalloc(1, sizeof(*res));
167- while (fgets(buf, sizeof(buf), fp)) {
168- char *bufp = buf;
169- if (!lineno)
170- skip_utf8_bom(&bufp, strlen(bufp));
171- handle_attr_line(res, bufp, path, ++lineno, macro_ok);
172+
173+ fd = fileno(fp);
174+ if (fstat(fd, &st)) {
175+ warning_errno(_("cannot fstat gitattributes file '%s'"), path);
176+ fclose(fp);
177+ return NULL;
178 }
179+ if (st.st_size >= ATTR_MAX_FILE_SIZE) {
180+ warning(_("ignoring overly large gitattributes file '%s'"), path);
181+ fclose(fp);
182+ return NULL;
183+ }
184+
185+ CALLOC_ARRAY(res, 1);
186+ while (strbuf_getline(&buf, fp) != EOF) {
187+ if (!lineno && starts_with(buf.buf, utf8_bom))
188+ strbuf_remove(&buf, 0, strlen(utf8_bom));
189+ handle_attr_line(res, buf.buf, path, ++lineno, macro_ok);
190+ }
191+
192 fclose(fp);
193+ strbuf_release(&buf);
194 return res;
195 }
196
197@@ -736,13 +756,18 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate,
198 struct attr_stack *res;
199 char *buf, *sp;
200 int lineno = 0;
201+ size_t size;
202
203 if (!istate)
204 return NULL;
205
206- buf = read_blob_data_from_index(istate, path, NULL);
207+ buf = read_blob_data_from_index(istate, path, &size);
208 if (!buf)
209 return NULL;
210+ if (size >= ATTR_MAX_FILE_SIZE) {
211+ warning(_("ignoring overly large gitattributes blob '%s'"), path);
212+ return NULL;
213+ }
214
215 res = xcalloc(1, sizeof(*res));
216 for (sp = buf; *sp; ) {
217@@ -1012,12 +1037,12 @@ static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem);
218 static int fill_one(const char *what, struct all_attrs_item *all_attrs,
219 const struct match_attr *a, int rem)
220 {
221- int i;
222+ size_t i;
223
224- for (i = a->num_attr - 1; rem > 0 && i >= 0; i--) {
225- const struct git_attr *attr = a->state[i].attr;
226+ for (i = a->num_attr; rem > 0 && i > 0; i--) {
227+ const struct git_attr *attr = a->state[i - 1].attr;
228 const char **n = &(all_attrs[attr->attr_nr].value);
229- const char *v = a->state[i].setto;
230+ const char *v = a->state[i - 1].setto;
231
232 if (*n == ATTR__UNKNOWN) {
233 debug_set(what,
234@@ -1036,11 +1061,11 @@ static int fill(const char *path, int pathlen, int basename_offset,
235 struct all_attrs_item *all_attrs, int rem)
236 {
237 for (; rem > 0 && stack; stack = stack->prev) {
238- int i;
239+ unsigned i;
240 const char *base = stack->origin ? stack->origin : "";
241
242- for (i = stack->num_matches - 1; 0 < rem && 0 <= i; i--) {
243- const struct match_attr *a = stack->attrs[i];
244+ for (i = stack->num_matches; 0 < rem && 0 < i; i--) {
245+ const struct match_attr *a = stack->attrs[i - 1];
246 if (a->is_macro)
247 continue;
248 if (path_matches(path, pathlen, basename_offset,
249@@ -1071,11 +1096,11 @@ static void determine_macros(struct all_attrs_item *all_attrs,
250 const struct attr_stack *stack)
251 {
252 for (; stack; stack = stack->prev) {
253- int i;
254- for (i = stack->num_matches - 1; i >= 0; i--) {
255- const struct match_attr *ma = stack->attrs[i];
256+ unsigned i;
257+ for (i = stack->num_matches; i > 0; i--) {
258+ const struct match_attr *ma = stack->attrs[i - 1];
259 if (ma->is_macro) {
260- int n = ma->u.attr->attr_nr;
261+ unsigned int n = ma->u.attr->attr_nr;
262 if (!all_attrs[n].macro) {
263 all_attrs[n].macro = ma;
264 }
265@@ -1127,7 +1152,7 @@ void git_check_attr(const struct index_state *istate,
266 collect_some_attrs(istate, path, check);
267
268 for (i = 0; i < check->nr; i++) {
269- size_t n = check->items[i].attr->attr_nr;
270+ unsigned int n = check->items[i].attr->attr_nr;
271 const char *value = check->all_attrs[n].value;
272 if (value == ATTR__UNKNOWN)
273 value = ATTR__UNSET;
274diff --git a/attr.h b/attr.h
275index b0378bf..f424285 100644
276--- a/attr.h
277+++ b/attr.h
278@@ -1,6 +1,18 @@
279 #ifndef ATTR_H
280 #define ATTR_H
281
282+/**
283+ * The maximum line length for a gitattributes file. If the line exceeds this
284+ * length we will ignore it.
285+ */
286+#define ATTR_MAX_LINE_LENGTH 2048
287+
288+ /**
289+ * The maximum size of the giattributes file. If the file exceeds this size we
290+ * will ignore it.
291+ */
292+#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
293+
294 struct index_state;
295
296 /* An attribute is a pointer to this opaque structure */
297diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
298index 71e63d8..556245b 100755
299--- a/t/t0003-attributes.sh
300+++ b/t/t0003-attributes.sh
301@@ -342,4 +342,63 @@ test_expect_success 'query binary macro directly' '
302 test_cmp expect actual
303 '
304
305+test_expect_success 'large attributes line ignored in tree' '
306+ test_when_finished "rm .gitattributes" &&
307+ printf "path %02043d" 1 >.gitattributes &&
308+ git check-attr --all path >actual 2>err &&
309+ echo "warning: ignoring overly long attributes line 1" >expect &&
310+ test_cmp expect err &&
311+ test_must_be_empty actual
312+'
313+
314+test_expect_success 'large attributes line ignores trailing content in tree' '
315+ test_when_finished "rm .gitattributes" &&
316+ # older versions of Git broke lines at 2048 bytes; the 2045 bytes
317+ # of 0-padding here is accounting for the three bytes of "a 1", which
318+ # would knock "trailing" to the "next" line, where it would be
319+ # erroneously parsed.
320+ printf "a %02045dtrailing attribute\n" 1 >.gitattributes &&
321+ git check-attr --all trailing >actual 2>err &&
322+ echo "warning: ignoring overly long attributes line 1" >expect &&
323+ test_cmp expect err &&
324+ test_must_be_empty actual
325+'
326+
327+test_expect_success EXPENSIVE 'large attributes file ignored in tree' '
328+ test_when_finished "rm .gitattributes" &&
329+ dd if=/dev/zero of=.gitattributes bs=101M count=1 2>/dev/null &&
330+ git check-attr --all path >/dev/null 2>err &&
331+ echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect &&
332+ test_cmp expect err
333+'
334+
335+test_expect_success 'large attributes line ignored in index' '
336+ test_when_finished "git update-index --remove .gitattributes" &&
337+ blob=$(printf "path %02043d" 1 | git hash-object -w --stdin) &&
338+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
339+ git check-attr --cached --all path >actual 2>err &&
340+ echo "warning: ignoring overly long attributes line 1" >expect &&
341+ test_cmp expect err &&
342+ test_must_be_empty actual
343+'
344+
345+test_expect_success 'large attributes line ignores trailing content in index' '
346+ test_when_finished "git update-index --remove .gitattributes" &&
347+ blob=$(printf "a %02045dtrailing attribute\n" 1 | git hash-object -w --stdin) &&
348+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
349+ git check-attr --cached --all trailing >actual 2>err &&
350+ echo "warning: ignoring overly long attributes line 1" >expect &&
351+ test_cmp expect err &&
352+ test_must_be_empty actual
353+'
354+
355+test_expect_success EXPENSIVE 'large attributes file ignored in index' '
356+ test_when_finished "git update-index --remove .gitattributes" &&
357+ blob=$(dd if=/dev/zero bs=101M count=1 2>/dev/null | git hash-object -w --stdin) &&
358+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
359+ git check-attr --cached --all path >/dev/null 2>err &&
360+ echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect &&
361+ test_cmp expect err
362+'
363+
364 test_done
365--
3662.25.1
367
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-01.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-01.patch
new file mode 100644
index 0000000000..87091abd47
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-01.patch
@@ -0,0 +1,39 @@
1From a244dc5b0a629290881641467c7a545de7508ab2 Mon Sep 17 00:00:00 2001
2From: Carlo Marcelo Arenas Belón <carenas@gmail.com>
3Date: Tue, 2 Nov 2021 15:46:06 +0000
4Subject: [PATCH 01/12] test-lib: add prerequisite for 64-bit platforms
5
6Allow tests that assume a 64-bit `size_t` to be skipped in 32-bit
7platforms and regardless of the size of `long`.
8
9This imitates the `LONG_IS_64BIT` prerequisite.
10
11Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
12Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
13Signed-off-by: Junio C Hamano <gitster@pobox.com>
14
15Upstream-Status: Backport [https://github.com/git/git/commit/a244dc5b0a629290881641467c7a545de7508ab2]
16CVE: CVE-2022-41903
17Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
18---
19 t/test-lib.sh | 4 ++++
20 1 file changed, 4 insertions(+)
21
22diff --git a/t/test-lib.sh b/t/test-lib.sh
23index e06fa02..db5ec2f 100644
24--- a/t/test-lib.sh
25+++ b/t/test-lib.sh
26@@ -1613,6 +1613,10 @@ build_option () {
27 sed -ne "s/^$1: //p"
28 }
29
30+test_lazy_prereq SIZE_T_IS_64BIT '
31+ test 8 -eq "$(build_option sizeof-size_t)"
32+'
33+
34 test_lazy_prereq LONG_IS_64BIT '
35 test 8 -le "$(build_option sizeof-long)"
36 '
37--
382.25.1
39
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-02.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-02.patch
new file mode 100644
index 0000000000..f35e55b585
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-02.patch
@@ -0,0 +1,187 @@
1From 81dc898df9b4b4035534a927f3234a3839b698bf Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:46:25 +0100
4Subject: [PATCH 02/12] pretty: fix out-of-bounds write caused by integer overflow
5
6When using a padding specifier in the pretty format passed to git-log(1)
7we need to calculate the string length in several places. These string
8lengths are stored in `int`s though, which means that these can easily
9overflow when the input lengths exceeds 2GB. This can ultimately lead to
10an out-of-bounds write when these are used in a call to memcpy(3P):
11
12 ==8340==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f1ec62f97fe at pc 0x7f2127e5f427 bp 0x7ffd3bd63de0 sp 0x7ffd3bd63588
13 WRITE of size 1 at 0x7f1ec62f97fe thread T0
14 #0 0x7f2127e5f426 in __interceptor_memcpy /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827
15 #1 0x5628e96aa605 in format_and_pad_commit pretty.c:1762
16 #2 0x5628e96aa7f4 in format_commit_item pretty.c:1801
17 #3 0x5628e97cdb24 in strbuf_expand strbuf.c:429
18 #4 0x5628e96ab060 in repo_format_commit_message pretty.c:1869
19 #5 0x5628e96acd0f in pretty_print_commit pretty.c:2161
20 #6 0x5628e95a44c8 in show_log log-tree.c:781
21 #7 0x5628e95a76ba in log_tree_commit log-tree.c:1117
22 #8 0x5628e922bed5 in cmd_log_walk_no_free builtin/log.c:508
23 #9 0x5628e922c35b in cmd_log_walk builtin/log.c:549
24 #10 0x5628e922f1a2 in cmd_log builtin/log.c:883
25 #11 0x5628e9106993 in run_builtin git.c:466
26 #12 0x5628e9107397 in handle_builtin git.c:721
27 #13 0x5628e9107b07 in run_argv git.c:788
28 #14 0x5628e91088a7 in cmd_main git.c:923
29 #15 0x5628e939d682 in main common-main.c:57
30 #16 0x7f2127c3c28f (/usr/lib/libc.so.6+0x2328f)
31 #17 0x7f2127c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
32 #18 0x5628e91020e4 in _start ../sysdeps/x86_64/start.S:115
33
34 0x7f1ec62f97fe is located 2 bytes to the left of 4831838265-byte region [0x7f1ec62f9800,0x7f1fe62f9839)
35 allocated by thread T0 here:
36 #0 0x7f2127ebe7ea in __interceptor_realloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85
37 #1 0x5628e98774d4 in xrealloc wrapper.c:136
38 #2 0x5628e97cb01c in strbuf_grow strbuf.c:99
39 #3 0x5628e97ccd42 in strbuf_addchars strbuf.c:327
40 #4 0x5628e96aa55c in format_and_pad_commit pretty.c:1761
41 #5 0x5628e96aa7f4 in format_commit_item pretty.c:1801
42 #6 0x5628e97cdb24 in strbuf_expand strbuf.c:429
43 #7 0x5628e96ab060 in repo_format_commit_message pretty.c:1869
44 #8 0x5628e96acd0f in pretty_print_commit pretty.c:2161
45 #9 0x5628e95a44c8 in show_log log-tree.c:781
46 #10 0x5628e95a76ba in log_tree_commit log-tree.c:1117
47 #11 0x5628e922bed5 in cmd_log_walk_no_free builtin/log.c:508
48 #12 0x5628e922c35b in cmd_log_walk builtin/log.c:549
49 #13 0x5628e922f1a2 in cmd_log builtin/log.c:883
50 #14 0x5628e9106993 in run_builtin git.c:466
51 #15 0x5628e9107397 in handle_builtin git.c:721
52 #16 0x5628e9107b07 in run_argv git.c:788
53 #17 0x5628e91088a7 in cmd_main git.c:923
54 #18 0x5628e939d682 in main common-main.c:57
55 #19 0x7f2127c3c28f (/usr/lib/libc.so.6+0x2328f)
56 #20 0x7f2127c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
57 #21 0x5628e91020e4 in _start ../sysdeps/x86_64/start.S:115
58
59 SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy
60 Shadow bytes around the buggy address:
61 0x0fe458c572a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
62 0x0fe458c572b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
63 0x0fe458c572c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
64 0x0fe458c572d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
65 0x0fe458c572e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
66 =>0x0fe458c572f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fa]
67 0x0fe458c57300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
68 0x0fe458c57310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69 0x0fe458c57320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70 0x0fe458c57330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
71 0x0fe458c57340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
72 Shadow byte legend (one shadow byte represents 8 application bytes):
73 Addressable: 00
74 Partially addressable: 01 02 03 04 05 06 07
75 Heap left redzone: fa
76 Freed heap region: fd
77 Stack left redzone: f1
78 Stack mid redzone: f2
79 Stack right redzone: f3
80 Stack after return: f5
81 Stack use after scope: f8
82 Global redzone: f9
83 Global init order: f6
84 Poisoned by user: f7
85 Container overflow: fc
86 Array cookie: ac
87 Intra object redzone: bb
88 ASan internal: fe
89 Left alloca redzone: ca
90 Right alloca redzone: cb
91 ==8340==ABORTING
92
93The pretty format can also be used in `git archive` operations via the
94`export-subst` attribute. So this is what in our opinion makes this a
95critical issue in the context of Git forges which allow to download an
96archive of user supplied Git repositories.
97
98Fix this vulnerability by using `size_t` instead of `int` to track the
99string lengths. Add tests which detect this vulnerability when Git is
100compiled with the address sanitizer.
101
102Reported-by: Joern Schneeweisz <jschneeweisz@gitlab.com>
103Original-patch-by: Joern Schneeweisz <jschneeweisz@gitlab.com>
104Modified-by: Taylor Blau <me@ttalorr.com>
105Signed-off-by: Patrick Steinhardt <ps@pks.im>
106Signed-off-by: Junio C Hamano <gitster@pobox.com>
107
108Upstream-Status: Backport [https://github.com/git/git/commit/81dc898df9b4b4035534a927f3234a3839b698bf]
109CVE: CVE-2022-41903
110Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
111---
112 pretty.c | 11 ++++++-----
113 t/t4205-log-pretty-formats.sh | 17 +++++++++++++++++
114 2 files changed, 23 insertions(+), 5 deletions(-)
115
116diff --git a/pretty.c b/pretty.c
117index b32f036..637e344 100644
118--- a/pretty.c
119+++ b/pretty.c
120@@ -1427,7 +1427,9 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
121 struct format_commit_context *c)
122 {
123 struct strbuf local_sb = STRBUF_INIT;
124- int total_consumed = 0, len, padding = c->padding;
125+ size_t total_consumed = 0;
126+ int len, padding = c->padding;
127+
128 if (padding < 0) {
129 const char *start = strrchr(sb->buf, '\n');
130 int occupied;
131@@ -1439,7 +1441,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
132 }
133 while (1) {
134 int modifier = *placeholder == 'C';
135- int consumed = format_commit_one(&local_sb, placeholder, c);
136+ size_t consumed = format_commit_one(&local_sb, placeholder, c);
137 total_consumed += consumed;
138
139 if (!modifier)
140@@ -1505,7 +1507,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
141 }
142 strbuf_addbuf(sb, &local_sb);
143 } else {
144- int sb_len = sb->len, offset = 0;
145+ size_t sb_len = sb->len, offset = 0;
146 if (c->flush_type == flush_left)
147 offset = padding - len;
148 else if (c->flush_type == flush_both)
149@@ -1528,8 +1530,7 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
150 const char *placeholder,
151 void *context)
152 {
153- int consumed;
154- size_t orig_len;
155+ size_t consumed, orig_len;
156 enum {
157 NO_MAGIC,
158 ADD_LF_BEFORE_NON_EMPTY,
159diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
160index f42a69f..a2acee1 100755
161--- a/t/t4205-log-pretty-formats.sh
162+++ b/t/t4205-log-pretty-formats.sh
163@@ -788,4 +788,21 @@ test_expect_success '%S in git log --format works with other placeholders (part
164 test_cmp expect actual
165 '
166
167+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
168+ # We only assert that this command does not crash. This needs to be
169+ # executed with the address sanitizer to demonstrate failure.
170+ git log -1 --pretty="format:%>(2147483646)%x41%41%>(2147483646)%x41" >/dev/null
171+'
172+
173+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'set up huge commit' '
174+ test-tool genzeros 2147483649 | tr "\000" "1" >expect &&
175+ huge_commit=$(git commit-tree -F expect HEAD^{tree})
176+'
177+
178+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
179+ git log -1 --format="%B%<(1)%x30" $huge_commit >actual &&
180+ echo 0 >>expect &&
181+ test_cmp expect actual
182+'
183+
184 test_done
185--
1862.25.1
187
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-03.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-03.patch
new file mode 100644
index 0000000000..d83d77eaf7
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-03.patch
@@ -0,0 +1,146 @@
1From b49f309aa16febeddb65e82526640a91bbba3be3 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:46:30 +0100
4Subject: [PATCH 03/12] pretty: fix out-of-bounds read when left-flushing with stealing
5
6With the `%>>(<N>)` pretty formatter, you can ask git-log(1) et al to
7steal spaces. To do so we need to look ahead of the next token to see
8whether there are spaces there. This loop takes into account ANSI
9sequences that end with an `m`, and if it finds any it will skip them
10until it finds the first space. While doing so it does not take into
11account the buffer's limits though and easily does an out-of-bounds
12read.
13
14Add a test that hits this behaviour. While we don't have an easy way to
15verify this, the test causes the following failure when run with
16`SANITIZE=address`:
17
18 ==37941==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000baf at pc 0x55ba6f88e0d0 bp 0x7ffc84c50d20 sp 0x7ffc84c50d10
19 READ of size 1 at 0x603000000baf thread T0
20 #0 0x55ba6f88e0cf in format_and_pad_commit pretty.c:1712
21 #1 0x55ba6f88e7b4 in format_commit_item pretty.c:1801
22 #2 0x55ba6f9b1ae4 in strbuf_expand strbuf.c:429
23 #3 0x55ba6f88f020 in repo_format_commit_message pretty.c:1869
24 #4 0x55ba6f890ccf in pretty_print_commit pretty.c:2161
25 #5 0x55ba6f7884c8 in show_log log-tree.c:781
26 #6 0x55ba6f78b6ba in log_tree_commit log-tree.c:1117
27 #7 0x55ba6f40fed5 in cmd_log_walk_no_free builtin/log.c:508
28 #8 0x55ba6f41035b in cmd_log_walk builtin/log.c:549
29 #9 0x55ba6f4131a2 in cmd_log builtin/log.c:883
30 #10 0x55ba6f2ea993 in run_builtin git.c:466
31 #11 0x55ba6f2eb397 in handle_builtin git.c:721
32 #12 0x55ba6f2ebb07 in run_argv git.c:788
33 #13 0x55ba6f2ec8a7 in cmd_main git.c:923
34 #14 0x55ba6f581682 in main common-main.c:57
35 #15 0x7f2d08c3c28f (/usr/lib/libc.so.6+0x2328f)
36 #16 0x7f2d08c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
37 #17 0x55ba6f2e60e4 in _start ../sysdeps/x86_64/start.S:115
38
39 0x603000000baf is located 1 bytes to the left of 24-byte region [0x603000000bb0,0x603000000bc8)
40 allocated by thread T0 here:
41 #0 0x7f2d08ebe7ea in __interceptor_realloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85
42 #1 0x55ba6fa5b494 in xrealloc wrapper.c:136
43 #2 0x55ba6f9aefdc in strbuf_grow strbuf.c:99
44 #3 0x55ba6f9b0a06 in strbuf_add strbuf.c:298
45 #4 0x55ba6f9b1a25 in strbuf_expand strbuf.c:418
46 #5 0x55ba6f88f020 in repo_format_commit_message pretty.c:1869
47 #6 0x55ba6f890ccf in pretty_print_commit pretty.c:2161
48 #7 0x55ba6f7884c8 in show_log log-tree.c:781
49 #8 0x55ba6f78b6ba in log_tree_commit log-tree.c:1117
50 #9 0x55ba6f40fed5 in cmd_log_walk_no_free builtin/log.c:508
51 #10 0x55ba6f41035b in cmd_log_walk builtin/log.c:549
52 #11 0x55ba6f4131a2 in cmd_log builtin/log.c:883
53 #12 0x55ba6f2ea993 in run_builtin git.c:466
54 #13 0x55ba6f2eb397 in handle_builtin git.c:721
55 #14 0x55ba6f2ebb07 in run_argv git.c:788
56 #15 0x55ba6f2ec8a7 in cmd_main git.c:923
57 #16 0x55ba6f581682 in main common-main.c:57
58 #17 0x7f2d08c3c28f (/usr/lib/libc.so.6+0x2328f)
59 #18 0x7f2d08c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
60 #19 0x55ba6f2e60e4 in _start ../sysdeps/x86_64/start.S:115
61
62 SUMMARY: AddressSanitizer: heap-buffer-overflow pretty.c:1712 in format_and_pad_commit
63 Shadow bytes around the buggy address:
64 0x0c067fff8120: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
65 0x0c067fff8130: fd fd fa fa fd fd fd fd fa fa fd fd fd fa fa fa
66 0x0c067fff8140: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
67 0x0c067fff8150: fa fa fd fd fd fd fa fa 00 00 00 fa fa fa fd fd
68 0x0c067fff8160: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
69 =>0x0c067fff8170: fd fd fd fa fa[fa]00 00 00 fa fa fa 00 00 00 fa
70 0x0c067fff8180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
71 0x0c067fff8190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
72 0x0c067fff81a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
73 0x0c067fff81b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
74 0x0c067fff81c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
75 Shadow byte legend (one shadow byte represents 8 application bytes):
76 Addressable: 00
77 Partially addressable: 01 02 03 04 05 06 07
78 Heap left redzone: fa
79 Freed heap region: fd
80 Stack left redzone: f1
81 Stack mid redzone: f2
82 Stack right redzone: f3
83 Stack after return: f5
84 Stack use after scope: f8
85 Global redzone: f9
86 Global init order: f6
87 Poisoned by user: f7
88 Container overflow: fc
89 Array cookie: ac
90 Intra object redzone: bb
91 ASan internal: fe
92 Left alloca redzone: ca
93 Right alloca redzone: cb
94
95Luckily enough, this would only cause us to copy the out-of-bounds data
96into the formatted commit in case we really had an ANSI sequence
97preceding our buffer. So this bug likely has no security consequences.
98
99Fix it regardless by not traversing past the buffer's start.
100
101Reported-by: Patrick Steinhardt <ps@pks.im>
102Reported-by: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>
103Signed-off-by: Patrick Steinhardt <ps@pks.im>
104Signed-off-by: Junio C Hamano <gitster@pobox.com>
105
106Upstream-Status: Backport [https://github.com/git/git/commit/b49f309aa16febeddb65e82526640a91bbba3be3]
107CVE: CVE-2022-41903
108Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
109---
110 pretty.c | 2 +-
111 t/t4205-log-pretty-formats.sh | 6 ++++++
112 2 files changed, 7 insertions(+), 1 deletion(-)
113
114diff --git a/pretty.c b/pretty.c
115index 637e344..4348a82 100644
116--- a/pretty.c
117+++ b/pretty.c
118@@ -1468,7 +1468,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
119 if (*ch != 'm')
120 break;
121 p = ch - 1;
122- while (ch - p < 10 && *p != '\033')
123+ while (p > sb->buf && ch - p < 10 && *p != '\033')
124 p--;
125 if (*p != '\033' ||
126 ch + 1 - p != display_mode_esc_sequence_len(p))
127diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
128index a2acee1..e69caba 100755
129--- a/t/t4205-log-pretty-formats.sh
130+++ b/t/t4205-log-pretty-formats.sh
131@@ -788,6 +788,12 @@ test_expect_success '%S in git log --format works with other placeholders (part
132 test_cmp expect actual
133 '
134
135+test_expect_success 'log --pretty with space stealing' '
136+ printf mm0 >expect &&
137+ git log -1 --pretty="format:mm%>>|(1)%x30" >actual &&
138+ test_cmp expect actual
139+'
140+
141 test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
142 # We only assert that this command does not crash. This needs to be
143 # executed with the address sanitizer to demonstrate failure.
144--
1452.25.1
146
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-04.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-04.patch
new file mode 100644
index 0000000000..9e3c74ff67
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-04.patch
@@ -0,0 +1,150 @@
1From f6e0b9f38987ad5e47bab551f8760b70689a5905 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:46:34 +0100
4Subject: [PATCH 04/12] pretty: fix out-of-bounds read when parsing invalid padding format
5
6An out-of-bounds read can be triggered when parsing an incomplete
7padding format string passed via `--pretty=format` or in Git archives
8when files are marked with the `export-subst` gitattribute.
9
10This bug exists since we have introduced support for truncating output
11via the `trunc` keyword a7f01c6 (pretty: support truncating in %>, %<
12and %><, 2013-04-19). Before this commit, we used to find the end of the
13formatting string by using strchr(3P). This function returns a `NULL`
14pointer in case the character in question wasn't found. The subsequent
15check whether any character was found thus simply checked the returned
16pointer. After the commit we switched to strcspn(3P) though, which only
17returns the offset to the first found character or to the trailing NUL
18byte. As the end pointer is now computed by adding the offset to the
19start pointer it won't be `NULL` anymore, and as a consequence the check
20doesn't do anything anymore.
21
22The out-of-bounds data that is being read can in fact end up in the
23formatted string. As a consequence, it is possible to leak memory
24contents either by calling git-log(1) or via git-archive(1) when any of
25the archived files is marked with the `export-subst` gitattribute.
26
27 ==10888==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000398 at pc 0x7f0356047cb2 bp 0x7fff3ffb95d0 sp 0x7fff3ffb8d78
28 READ of size 1 at 0x602000000398 thread T0
29 #0 0x7f0356047cb1 in __interceptor_strchrnul /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:725
30 #1 0x563b7cec9a43 in strbuf_expand strbuf.c:417
31 #2 0x563b7cda7060 in repo_format_commit_message pretty.c:1869
32 #3 0x563b7cda8d0f in pretty_print_commit pretty.c:2161
33 #4 0x563b7cca04c8 in show_log log-tree.c:781
34 #5 0x563b7cca36ba in log_tree_commit log-tree.c:1117
35 #6 0x563b7c927ed5 in cmd_log_walk_no_free builtin/log.c:508
36 #7 0x563b7c92835b in cmd_log_walk builtin/log.c:549
37 #8 0x563b7c92b1a2 in cmd_log builtin/log.c:883
38 #9 0x563b7c802993 in run_builtin git.c:466
39 #10 0x563b7c803397 in handle_builtin git.c:721
40 #11 0x563b7c803b07 in run_argv git.c:788
41 #12 0x563b7c8048a7 in cmd_main git.c:923
42 #13 0x563b7ca99682 in main common-main.c:57
43 #14 0x7f0355e3c28f (/usr/lib/libc.so.6+0x2328f)
44 #15 0x7f0355e3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
45 #16 0x563b7c7fe0e4 in _start ../sysdeps/x86_64/start.S:115
46
47 0x602000000398 is located 0 bytes to the right of 8-byte region [0x602000000390,0x602000000398)
48 allocated by thread T0 here:
49 #0 0x7f0356072faa in __interceptor_strdup /usr/src/debug/gcc/libsanitizer/asan/asan_interceptors.cpp:439
50 #1 0x563b7cf7317c in xstrdup wrapper.c:39
51 #2 0x563b7cd9a06a in save_user_format pretty.c:40
52 #3 0x563b7cd9b3e5 in get_commit_format pretty.c:173
53 #4 0x563b7ce54ea0 in handle_revision_opt revision.c:2456
54 #5 0x563b7ce597c9 in setup_revisions revision.c:2850
55 #6 0x563b7c9269e0 in cmd_log_init_finish builtin/log.c:269
56 #7 0x563b7c927362 in cmd_log_init builtin/log.c:348
57 #8 0x563b7c92b193 in cmd_log builtin/log.c:882
58 #9 0x563b7c802993 in run_builtin git.c:466
59 #10 0x563b7c803397 in handle_builtin git.c:721
60 #11 0x563b7c803b07 in run_argv git.c:788
61 #12 0x563b7c8048a7 in cmd_main git.c:923
62 #13 0x563b7ca99682 in main common-main.c:57
63 #14 0x7f0355e3c28f (/usr/lib/libc.so.6+0x2328f)
64 #15 0x7f0355e3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
65 #16 0x563b7c7fe0e4 in _start ../sysdeps/x86_64/start.S:115
66
67 SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:725 in __interceptor_strchrnul
68 Shadow bytes around the buggy address:
69 0x0c047fff8020: fa fa fd fd fa fa 00 06 fa fa 05 fa fa fa fd fd
70 0x0c047fff8030: fa fa 00 02 fa fa 06 fa fa fa 05 fa fa fa fd fd
71 0x0c047fff8040: fa fa 00 07 fa fa 03 fa fa fa fd fd fa fa 00 00
72 0x0c047fff8050: fa fa 00 01 fa fa fd fd fa fa 00 00 fa fa 00 01
73 0x0c047fff8060: fa fa 00 06 fa fa 00 06 fa fa 05 fa fa fa 05 fa
74 =>0x0c047fff8070: fa fa 00[fa]fa fa fd fa fa fa fd fd fa fa fd fd
75 0x0c047fff8080: fa fa fd fd fa fa 00 00 fa fa 00 fa fa fa fd fa
76 0x0c047fff8090: fa fa fd fd fa fa 00 00 fa fa fa fa fa fa fa fa
77 0x0c047fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
78 0x0c047fff80b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
79 0x0c047fff80c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
80 Shadow byte legend (one shadow byte represents 8 application bytes):
81 Addressable: 00
82 Partially addressable: 01 02 03 04 05 06 07
83 Heap left redzone: fa
84 Freed heap region: fd
85 Stack left redzone: f1
86 Stack mid redzone: f2
87 Stack right redzone: f3
88 Stack after return: f5
89 Stack use after scope: f8
90 Global redzone: f9
91 Global init order: f6
92 Poisoned by user: f7
93 Container overflow: fc
94 Array cookie: ac
95 Intra object redzone: bb
96 ASan internal: fe
97 Left alloca redzone: ca
98 Right alloca redzone: cb
99 ==10888==ABORTING
100
101Fix this bug by checking whether `end` points at the trailing NUL byte.
102Add a test which catches this out-of-bounds read and which demonstrates
103that we used to write out-of-bounds data into the formatted message.
104
105Reported-by: Markus Vervier <markus.vervier@x41-dsec.de>
106Original-patch-by: Markus Vervier <markus.vervier@x41-dsec.de>
107Signed-off-by: Patrick Steinhardt <ps@pks.im>
108Signed-off-by: Junio C Hamano <gitster@pobox.com>
109
110Upstream-Status: Backport [https://github.com/git/git/commit/f6e0b9f38987ad5e47bab551f8760b70689a5905]
111CVE: CVE-2022-41903
112Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
113---
114 pretty.c | 2 +-
115 t/t4205-log-pretty-formats.sh | 6 ++++++
116 2 files changed, 7 insertions(+), 1 deletion(-)
117
118diff --git a/pretty.c b/pretty.c
119index 4348a82..c49e818 100644
120--- a/pretty.c
121+++ b/pretty.c
122@@ -1024,7 +1024,7 @@ static size_t parse_padding_placeholder(const char *placeholder,
123 const char *end = start + strcspn(start, ",)");
124 char *next;
125 int width;
126- if (!end || end == start)
127+ if (!*end || end == start)
128 return 0;
129 width = strtol(start, &next, 10);
130 if (next == start || width == 0)
131diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
132index e69caba..8a349df 100755
133--- a/t/t4205-log-pretty-formats.sh
134+++ b/t/t4205-log-pretty-formats.sh
135@@ -794,6 +794,12 @@ test_expect_success 'log --pretty with space stealing' '
136 test_cmp expect actual
137 '
138
139+test_expect_success 'log --pretty with invalid padding format' '
140+ printf "%s%%<(20" "$(git rev-parse HEAD)" >expect &&
141+ git log -1 --pretty="format:%H%<(20" >actual &&
142+ test_cmp expect actual
143+'
144+
145 test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
146 # We only assert that this command does not crash. This needs to be
147 # executed with the address sanitizer to demonstrate failure.
148--
1492.25.1
150
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-05.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-05.patch
new file mode 100644
index 0000000000..994f7a55b1
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-05.patch
@@ -0,0 +1,98 @@
1From 1de69c0cdd388b0a5b7bdde0bfa0bda514a354b0 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:46:39 +0100
4Subject: [PATCH 05/12] pretty: fix adding linefeed when placeholder is not expanded
5
6When a formatting directive has a `+` or ` ` after the `%`, then we add
7either a line feed or space if the placeholder expands to a non-empty
8string. In specific cases though this logic doesn't work as expected,
9and we try to add the character even in the case where the formatting
10directive is empty.
11
12One such pattern is `%w(1)%+d%+w(2)`. `%+d` expands to reference names
13pointing to a certain commit, like in `git log --decorate`. For a tagged
14commit this would for example expand to `\n (tag: v1.0.0)`, which has a
15leading newline due to the `+` modifier and a space added by `%d`. Now
16the second wrapping directive will cause us to rewrap the text to
17`\n(tag:\nv1.0.0)`, which is one byte shorter due to the missing leading
18space. The code that handles the `+` magic now notices that the length
19has changed and will thus try to insert a leading line feed at the
20original posititon. But as the string was shortened, the original
21position is past the buffer's boundary and thus we die with an error.
22
23Now there are two issues here:
24
25 1. We check whether the buffer length has changed, not whether it
26 has been extended. This causes us to try and add the character
27 past the string boundary.
28
29 2. The current logic does not make any sense whatsoever. When the
30 string got expanded due to the rewrap, putting the separator into
31 the original position is likely to put it somewhere into the
32 middle of the rewrapped contents.
33
34It is debatable whether `%+w()` makes any sense in the first place.
35Strictly speaking, the placeholder never expands to a non-empty string,
36and consequentially we shouldn't ever accept this combination. We thus
37fix the bug by simply refusing `%+w()`.
38
39Signed-off-by: Patrick Steinhardt <ps@pks.im>
40Signed-off-by: Junio C Hamano <gitster@pobox.com>
41
42Upstream-Status: Backport [https://github.com/git/git/commit/1de69c0cdd388b0a5b7bdde0bfa0bda514a354b0]
43CVE: CVE-2022-41903
44Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
45---
46 pretty.c | 14 +++++++++++++-
47 t/t4205-log-pretty-formats.sh | 8 ++++++++
48 2 files changed, 21 insertions(+), 1 deletion(-)
49
50diff --git a/pretty.c b/pretty.c
51index c49e818..195d005 100644
52--- a/pretty.c
53+++ b/pretty.c
54@@ -1551,9 +1551,21 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
55 default:
56 break;
57 }
58- if (magic != NO_MAGIC)
59+ if (magic != NO_MAGIC) {
60 placeholder++;
61
62+ switch (placeholder[0]) {
63+ case 'w':
64+ /*
65+ * `%+w()` cannot ever expand to a non-empty string,
66+ * and it potentially changes the layout of preceding
67+ * contents. We're thus not able to handle the magic in
68+ * this combination and refuse the pattern.
69+ */
70+ return 0;
71+ };
72+ }
73+
74 orig_len = sb->len;
75 if (((struct format_commit_context *)context)->flush_type != no_flush)
76 consumed = format_and_pad_commit(sb, placeholder, context);
77diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
78index 8a349df..fa1bc2b 100755
79--- a/t/t4205-log-pretty-formats.sh
80+++ b/t/t4205-log-pretty-formats.sh
81@@ -800,6 +800,14 @@ test_expect_success 'log --pretty with invalid padding format' '
82 test_cmp expect actual
83 '
84
85+test_expect_success 'log --pretty with magical wrapping directives' '
86+ commit_id=$(git commit-tree HEAD^{tree} -m "describe me") &&
87+ git tag describe-me $commit_id &&
88+ printf "\n(tag:\ndescribe-me)%%+w(2)" >expect &&
89+ git log -1 --pretty="format:%w(1)%+d%+w(2)" $commit_id >actual &&
90+ test_cmp expect actual
91+'
92+
93 test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
94 # We only assert that this command does not crash. This needs to be
95 # executed with the address sanitizer to demonstrate failure.
96--
972.25.1
98
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-06.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-06.patch
new file mode 100644
index 0000000000..93fbe5c7fe
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-06.patch
@@ -0,0 +1,90 @@
1From 48050c42c73c28b0c001d63d11dffac7e116847b Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:46:49 +0100
4Subject: [PATCH 06/12] pretty: fix integer overflow in wrapping format
5
6The `%w(width,indent1,indent2)` formatting directive can be used to
7rewrap text to a specific width and is designed after git-shortlog(1)'s
8`-w` parameter. While the three parameters are all stored as `size_t`
9internally, `strbuf_add_wrapped_text()` accepts integers as input. As a
10result, the casted integers may overflow. As these now-negative integers
11are later on passed to `strbuf_addchars()`, we will ultimately run into
12implementation-defined behaviour due to casting a negative number back
13to `size_t` again. On my platform, this results in trying to allocate
149000 petabyte of memory.
15
16Fix this overflow by using `cast_size_t_to_int()` so that we reject
17inputs that cannot be represented as an integer.
18
19Signed-off-by: Patrick Steinhardt <ps@pks.im>
20Signed-off-by: Junio C Hamano <gitster@pobox.com>
21
22Upstream-Status: Backport [https://github.com/git/git/commit/48050c42c73c28b0c001d63d11dffac7e116847b]
23CVE: CVE-2022-41903
24Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
25---
26 git-compat-util.h | 8 ++++++++
27 pretty.c | 4 +++-
28 t/t4205-log-pretty-formats.sh | 12 ++++++++++++
29 3 files changed, 23 insertions(+), 1 deletion(-)
30
31diff --git a/git-compat-util.h b/git-compat-util.h
32index a1ecfd3..b0f3890 100644
33--- a/git-compat-util.h
34+++ b/git-compat-util.h
35@@ -854,6 +854,14 @@ static inline size_t st_sub(size_t a, size_t b)
36 return a - b;
37 }
38
39+static inline int cast_size_t_to_int(size_t a)
40+{
41+ if (a > INT_MAX)
42+ die("number too large to represent as int on this platform: %"PRIuMAX,
43+ (uintmax_t)a);
44+ return (int)a;
45+}
46+
47 #ifdef HAVE_ALLOCA_H
48 # include <alloca.h>
49 # define xalloca(size) (alloca(size))
50diff --git a/pretty.c b/pretty.c
51index 195d005..ff9fc97 100644
52--- a/pretty.c
53+++ b/pretty.c
54@@ -898,7 +898,9 @@ static void strbuf_wrap(struct strbuf *sb, size_t pos,
55 if (pos)
56 strbuf_add(&tmp, sb->buf, pos);
57 strbuf_add_wrapped_text(&tmp, sb->buf + pos,
58- (int) indent1, (int) indent2, (int) width);
59+ cast_size_t_to_int(indent1),
60+ cast_size_t_to_int(indent2),
61+ cast_size_t_to_int(width));
62 strbuf_swap(&tmp, sb);
63 strbuf_release(&tmp);
64 }
65diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
66index fa1bc2b..23ac508 100755
67--- a/t/t4205-log-pretty-formats.sh
68+++ b/t/t4205-log-pretty-formats.sh
69@@ -808,6 +808,18 @@ test_expect_success 'log --pretty with magical wrapping directives' '
70 test_cmp expect actual
71 '
72
73+test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping directive' '
74+ cat >expect <<-EOF &&
75+ fatal: number too large to represent as int on this platform: 2147483649
76+ EOF
77+ test_must_fail git log -1 --pretty="format:%w(2147483649,1,1)%d" 2>error &&
78+ test_cmp expect error &&
79+ test_must_fail git log -1 --pretty="format:%w(1,2147483649,1)%d" 2>error &&
80+ test_cmp expect error &&
81+ test_must_fail git log -1 --pretty="format:%w(1,1,2147483649)%d" 2>error &&
82+ test_cmp expect error
83+'
84+
85 test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
86 # We only assert that this command does not crash. This needs to be
87 # executed with the address sanitizer to demonstrate failure.
88--
892.25.1
90
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-07.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-07.patch
new file mode 100644
index 0000000000..ec248ad6c2
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-07.patch
@@ -0,0 +1,123 @@
1From 522cc87fdc25449222a5894a428eebf4b8d5eaa9 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:46:53 +0100
4Subject: [PATCH 07/12] utf8: fix truncated string lengths in utf8_strnwidth()
5
6The `utf8_strnwidth()` function accepts an optional string length as
7input parameter. This parameter can either be set to `-1`, in which case
8we call `strlen()` on the input. Or it can be set to a positive integer
9that indicates a precomputed length, which callers typically compute by
10calling `strlen()` at some point themselves.
11
12The input parameter is an `int` though, whereas `strlen()` returns a
13`size_t`. This can lead to implementation-defined behaviour though when
14the `size_t` cannot be represented by the `int`. In the general case
15though this leads to wrap-around and thus to negative string sizes,
16which is sure enough to not lead to well-defined behaviour.
17
18Fix this by accepting a `size_t` instead of an `int` as string length.
19While this takes away the ability of callers to simply pass in `-1` as
20string length, it really is trivial enough to convert them to instead
21pass in `strlen()` instead.
22
23Signed-off-by: Patrick Steinhardt <ps@pks.im>
24Signed-off-by: Junio C Hamano <gitster@pobox.com>
25
26Upstream-Status: Backport [https://github.com/git/git/commit/522cc87fdc25449222a5894a428eebf4b8d5eaa9]
27CVE: CVE-2022-41903
28Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
29---
30 column.c | 2 +-
31 pretty.c | 4 ++--
32 utf8.c | 8 +++-----
33 utf8.h | 2 +-
34 4 files changed, 7 insertions(+), 9 deletions(-)
35
36diff --git a/column.c b/column.c
37index 4a38eed..0c79850 100644
38--- a/column.c
39+++ b/column.c
40@@ -23,7 +23,7 @@ struct column_data {
41 /* return length of 's' in letters, ANSI escapes stripped */
42 static int item_length(const char *s)
43 {
44- return utf8_strnwidth(s, -1, 1);
45+ return utf8_strnwidth(s, strlen(s), 1);
46 }
47
48 /*
49diff --git a/pretty.c b/pretty.c
50index ff9fc97..c3c1443 100644
51--- a/pretty.c
52+++ b/pretty.c
53@@ -1437,7 +1437,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
54 int occupied;
55 if (!start)
56 start = sb->buf;
57- occupied = utf8_strnwidth(start, -1, 1);
58+ occupied = utf8_strnwidth(start, strlen(start), 1);
59 occupied += c->pretty_ctx->graph_width;
60 padding = (-padding) - occupied;
61 }
62@@ -1455,7 +1455,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
63 placeholder++;
64 total_consumed++;
65 }
66- len = utf8_strnwidth(local_sb.buf, -1, 1);
67+ len = utf8_strnwidth(local_sb.buf, local_sb.len, 1);
68
69 if (c->flush_type == flush_left_and_steal) {
70 const char *ch = sb->buf + sb->len - 1;
71diff --git a/utf8.c b/utf8.c
72index 5c8f151..a66984b 100644
73--- a/utf8.c
74+++ b/utf8.c
75@@ -206,13 +206,11 @@ int utf8_width(const char **start, size_t *remainder_p)
76 * string, assuming that the string is utf8. Returns strlen() instead
77 * if the string does not look like a valid utf8 string.
78 */
79-int utf8_strnwidth(const char *string, int len, int skip_ansi)
80+int utf8_strnwidth(const char *string, size_t len, int skip_ansi)
81 {
82 int width = 0;
83 const char *orig = string;
84
85- if (len == -1)
86- len = strlen(string);
87 while (string && string < orig + len) {
88 int skip;
89 while (skip_ansi &&
90@@ -225,7 +223,7 @@ int utf8_strnwidth(const char *string, int len, int skip_ansi)
91
92 int utf8_strwidth(const char *string)
93 {
94- return utf8_strnwidth(string, -1, 0);
95+ return utf8_strnwidth(string, strlen(string), 0);
96 }
97
98 int is_utf8(const char *text)
99@@ -792,7 +790,7 @@ int skip_utf8_bom(char **text, size_t len)
100 void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int width,
101 const char *s)
102 {
103- int slen = strlen(s);
104+ size_t slen = strlen(s);
105 int display_len = utf8_strnwidth(s, slen, 0);
106 int utf8_compensation = slen - display_len;
107
108diff --git a/utf8.h b/utf8.h
109index fcd5167..6da1b6d 100644
110--- a/utf8.h
111+++ b/utf8.h
112@@ -7,7 +7,7 @@ typedef unsigned int ucs_char_t; /* assuming 32bit int */
113
114 size_t display_mode_esc_sequence_len(const char *s);
115 int utf8_width(const char **start, size_t *remainder_p);
116-int utf8_strnwidth(const char *string, int len, int skip_ansi);
117+int utf8_strnwidth(const char *string, size_t len, int skip_ansi);
118 int utf8_strwidth(const char *string);
119 int is_utf8(const char *text);
120 int is_encoding_utf8(const char *name);
121--
1222.25.1
123
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-08.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-08.patch
new file mode 100644
index 0000000000..3de6a5ba6a
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-08.patch
@@ -0,0 +1,67 @@
1From 17d23e8a3812a5ca3dd6564e74d5250f22e5d76d Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:47:00 +0100
4Subject: [PATCH 08/12] utf8: fix returning negative string width
5
6The `utf8_strnwidth()` function calls `utf8_width()` in a loop and adds
7its returned width to the end result. `utf8_width()` can return `-1`
8though in case it reads a control character, which means that the
9computed string width is going to be wrong. In the worst case where
10there are more control characters than non-control characters, we may
11even return a negative string width.
12
13Fix this bug by treating control characters as having zero width.
14
15Signed-off-by: Patrick Steinhardt <ps@pks.im>
16Signed-off-by: Junio C Hamano <gitster@pobox.com>
17
18Upstream-Status: Backport [https://github.com/git/git/commit/17d23e8a3812a5ca3dd6564e74d5250f22e5d76d]
19CVE: CVE-2022-41903
20Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
21---
22 t/t4205-log-pretty-formats.sh | 6 ++++++
23 utf8.c | 8 ++++++--
24 2 files changed, 12 insertions(+), 2 deletions(-)
25
26diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
27index 23ac508..261a6f0 100755
28--- a/t/t4205-log-pretty-formats.sh
29+++ b/t/t4205-log-pretty-formats.sh
30@@ -820,6 +820,12 @@ test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping dire
31 test_cmp expect error
32 '
33
34+test_expect_success 'log --pretty with padding and preceding control chars' '
35+ printf "\20\20 0" >expect &&
36+ git log -1 --pretty="format:%x10%x10%>|(4)%x30" >actual &&
37+ test_cmp expect actual
38+'
39+
40 test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
41 # We only assert that this command does not crash. This needs to be
42 # executed with the address sanitizer to demonstrate failure.
43diff --git a/utf8.c b/utf8.c
44index a66984b..6632bd2 100644
45--- a/utf8.c
46+++ b/utf8.c
47@@ -212,11 +212,15 @@ int utf8_strnwidth(const char *string, size_t len, int skip_ansi)
48 const char *orig = string;
49
50 while (string && string < orig + len) {
51- int skip;
52+ int glyph_width, skip;
53+
54 while (skip_ansi &&
55 (skip = display_mode_esc_sequence_len(string)) != 0)
56 string += skip;
57- width += utf8_width(&string, NULL);
58+
59+ glyph_width = utf8_width(&string, NULL);
60+ if (glyph_width > 0)
61+ width += glyph_width;
62 }
63 return string ? width : len;
64 }
65--
662.25.1
67
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-09.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-09.patch
new file mode 100644
index 0000000000..761d4c6a9f
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-09.patch
@@ -0,0 +1,162 @@
1From 937b71cc8b5b998963a7f9a33312ba3549d55510 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:47:04 +0100
4Subject: [PATCH 09/12] utf8: fix overflow when returning string width
5
6The return type of both `utf8_strwidth()` and `utf8_strnwidth()` is
7`int`, but we operate on string lengths which are typically of type
8`size_t`. This means that when the string is longer than `INT_MAX`, we
9will overflow and thus return a negative result.
10
11This can lead to an out-of-bounds write with `--pretty=format:%<1)%B`
12and a commit message that is 2^31+1 bytes long:
13
14 =================================================================
15 ==26009==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000001168 at pc 0x7f95c4e5f427 bp 0x7ffd8541c900 sp 0x7ffd8541c0a8
16 WRITE of size 2147483649 at 0x603000001168 thread T0
17 #0 0x7f95c4e5f426 in __interceptor_memcpy /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827
18 #1 0x5612bbb1068c in format_and_pad_commit pretty.c:1763
19 #2 0x5612bbb1087a in format_commit_item pretty.c:1801
20 #3 0x5612bbc33bab in strbuf_expand strbuf.c:429
21 #4 0x5612bbb110e7 in repo_format_commit_message pretty.c:1869
22 #5 0x5612bbb12d96 in pretty_print_commit pretty.c:2161
23 #6 0x5612bba0a4d5 in show_log log-tree.c:781
24 #7 0x5612bba0d6c7 in log_tree_commit log-tree.c:1117
25 #8 0x5612bb691ed5 in cmd_log_walk_no_free builtin/log.c:508
26 #9 0x5612bb69235b in cmd_log_walk builtin/log.c:549
27 #10 0x5612bb6951a2 in cmd_log builtin/log.c:883
28 #11 0x5612bb56c993 in run_builtin git.c:466
29 #12 0x5612bb56d397 in handle_builtin git.c:721
30 #13 0x5612bb56db07 in run_argv git.c:788
31 #14 0x5612bb56e8a7 in cmd_main git.c:923
32 #15 0x5612bb803682 in main common-main.c:57
33 #16 0x7f95c4c3c28f (/usr/lib/libc.so.6+0x2328f)
34 #17 0x7f95c4c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
35 #18 0x5612bb5680e4 in _start ../sysdeps/x86_64/start.S:115
36
37 0x603000001168 is located 0 bytes to the right of 24-byte region [0x603000001150,0x603000001168)
38 allocated by thread T0 here:
39 #0 0x7f95c4ebe7ea in __interceptor_realloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85
40 #1 0x5612bbcdd556 in xrealloc wrapper.c:136
41 #2 0x5612bbc310a3 in strbuf_grow strbuf.c:99
42 #3 0x5612bbc32acd in strbuf_add strbuf.c:298
43 #4 0x5612bbc33aec in strbuf_expand strbuf.c:418
44 #5 0x5612bbb110e7 in repo_format_commit_message pretty.c:1869
45 #6 0x5612bbb12d96 in pretty_print_commit pretty.c:2161
46 #7 0x5612bba0a4d5 in show_log log-tree.c:781
47 #8 0x5612bba0d6c7 in log_tree_commit log-tree.c:1117
48 #9 0x5612bb691ed5 in cmd_log_walk_no_free builtin/log.c:508
49 #10 0x5612bb69235b in cmd_log_walk builtin/log.c:549
50 #11 0x5612bb6951a2 in cmd_log builtin/log.c:883
51 #12 0x5612bb56c993 in run_builtin git.c:466
52 #13 0x5612bb56d397 in handle_builtin git.c:721
53 #14 0x5612bb56db07 in run_argv git.c:788
54 #15 0x5612bb56e8a7 in cmd_main git.c:923
55 #16 0x5612bb803682 in main common-main.c:57
56 #17 0x7f95c4c3c28f (/usr/lib/libc.so.6+0x2328f)
57
58 SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy
59 Shadow bytes around the buggy address:
60 0x0c067fff81d0: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
61 0x0c067fff81e0: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
62 0x0c067fff81f0: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
63 0x0c067fff8200: fd fd fd fa fa fa fd fd fd fd fa fa 00 00 00 fa
64 0x0c067fff8210: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
65 =>0x0c067fff8220: fd fa fa fa fd fd fd fa fa fa 00 00 00[fa]fa fa
66 0x0c067fff8230: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
67 0x0c067fff8240: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
68 0x0c067fff8250: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
69 0x0c067fff8260: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
70 0x0c067fff8270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
71 Shadow byte legend (one shadow byte represents 8 application bytes):
72 Addressable: 00
73 Partially addressable: 01 02 03 04 05 06 07
74 Heap left redzone: fa
75 Freed heap region: fd
76 Stack left redzone: f1
77 Stack mid redzone: f2
78 Stack right redzone: f3
79 Stack after return: f5
80 Stack use after scope: f8
81 Global redzone: f9
82 Global init order: f6
83 Poisoned by user: f7
84 Container overflow: fc
85 Array cookie: ac
86 Intra object redzone: bb
87 ASan internal: fe
88 Left alloca redzone: ca
89 Right alloca redzone: cb
90 ==26009==ABORTING
91
92Now the proper fix for this would be to convert both functions to return
93an `size_t` instead of an `int`. But given that this commit may be part
94of a security release, let's instead do the minimal viable fix and die
95in case we see an overflow.
96
97Add a test that would have previously caused us to crash.
98
99Signed-off-by: Patrick Steinhardt <ps@pks.im>
100Signed-off-by: Junio C Hamano <gitster@pobox.com>
101
102Upstream-Status: Backport [https://github.com/git/git/commit/937b71cc8b5b998963a7f9a33312ba3549d55510]
103CVE: CVE-2022-41903
104Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
105---
106 t/t4205-log-pretty-formats.sh | 8 ++++++++
107 utf8.c | 12 +++++++++---
108 2 files changed, 17 insertions(+), 3 deletions(-)
109
110diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
111index 261a6f0..de15007 100755
112--- a/t/t4205-log-pretty-formats.sh
113+++ b/t/t4205-log-pretty-formats.sh
114@@ -843,4 +843,12 @@ test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit mes
115 test_cmp expect actual
116 '
117
118+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message does not cause allocation failure' '
119+ test_must_fail git log -1 --format="%<(1)%B" $huge_commit 2>error &&
120+ cat >expect <<-EOF &&
121+ fatal: number too large to represent as int on this platform: 2147483649
122+ EOF
123+ test_cmp expect error
124+'
125+
126 test_done
127diff --git a/utf8.c b/utf8.c
128index 6632bd2..03be475 100644
129--- a/utf8.c
130+++ b/utf8.c
131@@ -208,11 +208,12 @@ int utf8_width(const char **start, size_t *remainder_p)
132 */
133 int utf8_strnwidth(const char *string, size_t len, int skip_ansi)
134 {
135- int width = 0;
136 const char *orig = string;
137+ size_t width = 0;
138
139 while (string && string < orig + len) {
140- int glyph_width, skip;
141+ int glyph_width;
142+ size_t skip;
143
144 while (skip_ansi &&
145 (skip = display_mode_esc_sequence_len(string)) != 0)
146@@ -222,7 +223,12 @@ int utf8_strnwidth(const char *string, size_t len, int skip_ansi)
147 if (glyph_width > 0)
148 width += glyph_width;
149 }
150- return string ? width : len;
151+
152+ /*
153+ * TODO: fix the interface of this function and `utf8_strwidth()` to
154+ * return `size_t` instead of `int`.
155+ */
156+ return cast_size_t_to_int(string ? width : len);
157 }
158
159 int utf8_strwidth(const char *string)
160--
1612.25.1
162
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-10.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-10.patch
new file mode 100644
index 0000000000..bbfc6e758f
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-10.patch
@@ -0,0 +1,99 @@
1From 81c2d4c3a5ba0e6ab8c348708441fed170e63a82 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:47:10 +0100
4Subject: [PATCH 10/12] utf8: fix checking for glyph width in strbuf_utf8_replace()
5
6In `strbuf_utf8_replace()`, we call `utf8_width()` to compute the width
7of the current glyph. If the glyph is a control character though it can
8be that `utf8_width()` returns `-1`, but because we assign this value to
9a `size_t` the conversion will cause us to underflow. This bug can
10easily be triggered with the following command:
11
12 $ git log --pretty='format:xxx%<|(1,trunc)%x10'
13
14>From all I can see though this seems to be a benign underflow that has
15no security-related consequences.
16
17Fix the bug by using an `int` instead. When we see a control character,
18we now copy it into the target buffer but don't advance the current
19width of the string.
20
21Signed-off-by: Patrick Steinhardt <ps@pks.im>
22Signed-off-by: Junio C Hamano <gitster@pobox.com>
23
24Upstream-Status: Backport [https://github.com/git/git/commit/81c2d4c3a5ba0e6ab8c348708441fed170e63a82]
25CVE: CVE-2022-41903
26Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
27---
28 t/t4205-log-pretty-formats.sh | 7 +++++++
29 utf8.c | 19 ++++++++++++++-----
30 2 files changed, 21 insertions(+), 5 deletions(-)
31
32diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
33index de15007..52c8bc8 100755
34--- a/t/t4205-log-pretty-formats.sh
35+++ b/t/t4205-log-pretty-formats.sh
36@@ -826,6 +826,13 @@ test_expect_success 'log --pretty with padding and preceding control chars' '
37 test_cmp expect actual
38 '
39
40+test_expect_success 'log --pretty truncation with control chars' '
41+ test_commit "$(printf "\20\20\20\20xxxx")" file contents commit-with-control-chars &&
42+ printf "\20\20\20\20x.." >expect &&
43+ git log -1 --pretty="format:%<(3,trunc)%s" commit-with-control-chars >actual &&
44+ test_cmp expect actual
45+'
46+
47 test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
48 # We only assert that this command does not crash. This needs to be
49 # executed with the address sanitizer to demonstrate failure.
50diff --git a/utf8.c b/utf8.c
51index 03be475..ec03e69 100644
52--- a/utf8.c
53+++ b/utf8.c
54@@ -377,6 +377,7 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
55 dst = sb_dst.buf;
56
57 while (src < end) {
58+ int glyph_width;
59 char *old;
60 size_t n;
61
62@@ -390,21 +391,29 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
63 break;
64
65 old = src;
66- n = utf8_width((const char**)&src, NULL);
67- if (!src) /* broken utf-8, do nothing */
68+ glyph_width = utf8_width((const char**)&src, NULL);
69+ if (!src) /* broken utf-8, do nothing */
70 goto out;
71- if (n && w >= pos && w < pos + width) {
72+
73+ /*
74+ * In case we see a control character we copy it into the
75+ * buffer, but don't add it to the width.
76+ */
77+ if (glyph_width < 0)
78+ glyph_width = 0;
79+
80+ if (glyph_width && w >= pos && w < pos + width) {
81 if (subst) {
82 memcpy(dst, subst, subst_len);
83 dst += subst_len;
84 subst = NULL;
85 }
86- w += n;
87+ w += glyph_width;
88 continue;
89 }
90 memcpy(dst, old, src - old);
91 dst += src - old;
92- w += n;
93+ w += glyph_width;
94 }
95 strbuf_setlen(&sb_dst, dst - sb_dst.buf);
96 strbuf_swap(sb_src, &sb_dst);
97--
982.25.1
99
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-11.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-11.patch
new file mode 100644
index 0000000000..f339edfc8a
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-11.patch
@@ -0,0 +1,90 @@
1From f930a2394303b902e2973f4308f96529f736b8bc Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:47:15 +0100
4Subject: [PATCH 11/12] utf8: refactor strbuf_utf8_replace to not rely on preallocated buffer
5
6In `strbuf_utf8_replace`, we preallocate the destination buffer and then
7use `memcpy` to copy bytes into it at computed offsets. This feels
8rather fragile and is hard to understand at times. Refactor the code to
9instead use `strbuf_add` and `strbuf_addstr` so that we can be sure that
10there is no possibility to perform an out-of-bounds write.
11
12Signed-off-by: Patrick Steinhardt <ps@pks.im>
13Signed-off-by: Junio C Hamano <gitster@pobox.com>
14
15Upstream-Status: Backport [https://github.com/git/git/commit/f930a2394303b902e2973f4308f96529f736b8bc]
16CVE: CVE-2022-41903
17Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
18---
19 utf8.c | 34 +++++++++++++---------------------
20 1 file changed, 13 insertions(+), 21 deletions(-)
21
22diff --git a/utf8.c b/utf8.c
23index ec03e69..a13f5e3 100644
24--- a/utf8.c
25+++ b/utf8.c
26@@ -365,26 +365,20 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
27 void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
28 const char *subst)
29 {
30- struct strbuf sb_dst = STRBUF_INIT;
31- char *src = sb_src->buf;
32- char *end = src + sb_src->len;
33- char *dst;
34- int w = 0, subst_len = 0;
35+ const char *src = sb_src->buf, *end = sb_src->buf + sb_src->len;
36+ struct strbuf dst;
37+ int w = 0;
38
39- if (subst)
40- subst_len = strlen(subst);
41- strbuf_grow(&sb_dst, sb_src->len + subst_len);
42- dst = sb_dst.buf;
43+ strbuf_init(&dst, sb_src->len);
44
45 while (src < end) {
46+ const char *old;
47 int glyph_width;
48- char *old;
49 size_t n;
50
51 while ((n = display_mode_esc_sequence_len(src))) {
52- memcpy(dst, src, n);
53+ strbuf_add(&dst, src, n);
54 src += n;
55- dst += n;
56 }
57
58 if (src >= end)
59@@ -404,21 +398,19 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
60
61 if (glyph_width && w >= pos && w < pos + width) {
62 if (subst) {
63- memcpy(dst, subst, subst_len);
64- dst += subst_len;
65+ strbuf_addstr(&dst, subst);
66 subst = NULL;
67 }
68- w += glyph_width;
69- continue;
70+ } else {
71+ strbuf_add(&dst, old, src - old);
72 }
73- memcpy(dst, old, src - old);
74- dst += src - old;
75+
76 w += glyph_width;
77 }
78- strbuf_setlen(&sb_dst, dst - sb_dst.buf);
79- strbuf_swap(sb_src, &sb_dst);
80+
81+ strbuf_swap(sb_src, &dst);
82 out:
83- strbuf_release(&sb_dst);
84+ strbuf_release(&dst);
85 }
86
87 /*
88--
892.25.1
90
diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-12.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-12.patch
new file mode 100644
index 0000000000..978865978d
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2022-41903-12.patch
@@ -0,0 +1,124 @@
1From 304a50adff6480ede46b68f7545baab542cbfb46 Mon Sep 17 00:00:00 2001
2From: Patrick Steinhardt <ps@pks.im>
3Date: Thu, 1 Dec 2022 15:47:23 +0100
4Subject: [PATCH 12/12] pretty: restrict input lengths for padding and wrapping formats
5
6Both the padding and wrapping formatting directives allow the caller to
7specify an integer that ultimately leads to us adding this many chars to
8the result buffer. As a consequence, it is trivial to e.g. allocate 2GB
9of RAM via a single formatting directive and cause resource exhaustion
10on the machine executing this logic. Furthermore, it is debatable
11whether there are any sane usecases that require the user to pad data to
122GB boundaries or to indent wrapped data by 2GB.
13
14Restrict the input sizes to 16 kilobytes at a maximum to limit the
15amount of bytes that can be requested by the user. This is not meant
16as a fix because there are ways to trivially amplify the amount of
17data we generate via formatting directives; the real protection is
18achieved by the changes in previous steps to catch and avoid integer
19wraparound that causes us to under-allocate and access beyond the
20end of allocated memory reagions. But having such a limit
21significantly helps fuzzing the pretty format, because the fuzzer is
22otherwise quite fast to run out-of-memory as it discovers these
23formatters.
24
25Signed-off-by: Patrick Steinhardt <ps@pks.im>
26Signed-off-by: Junio C Hamano <gitster@pobox.com>
27
28Upstream-Status: Backport [https://github.com/git/git/commit/304a50adff6480ede46b68f7545baab542cbfb46]
29CVE: CVE-2022-41903
30Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
31---
32 pretty.c | 26 ++++++++++++++++++++++++++
33 t/t4205-log-pretty-formats.sh | 24 +++++++++++++++---------
34 2 files changed, 41 insertions(+), 9 deletions(-)
35
36diff --git a/pretty.c b/pretty.c
37index c3c1443..e9687f0 100644
38--- a/pretty.c
39+++ b/pretty.c
40@@ -13,6 +13,13 @@
41 #include "gpg-interface.h"
42 #include "trailer.h"
43
44+/*
45+ * The limit for formatting directives, which enable the caller to append
46+ * arbitrarily many bytes to the formatted buffer. This includes padding
47+ * and wrapping formatters.
48+ */
49+#define FORMATTING_LIMIT (16 * 1024)
50+
51 static char *user_format;
52 static struct cmt_fmt_map {
53 const char *name;
54@@ -1029,6 +1036,15 @@ static size_t parse_padding_placeholder(const char *placeholder,
55 if (!*end || end == start)
56 return 0;
57 width = strtol(start, &next, 10);
58+
59+ /*
60+ * We need to limit the amount of padding, or otherwise this
61+ * would allow the user to pad the buffer by arbitrarily many
62+ * bytes and thus cause resource exhaustion.
63+ */
64+ if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT)
65+ return 0;
66+
67 if (next == start || width == 0)
68 return 0;
69 if (width < 0) {
70@@ -1188,6 +1204,16 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
71 if (*next != ')')
72 return 0;
73 }
74+
75+ /*
76+ * We need to limit the format here as it allows the
77+ * user to prepend arbitrarily many bytes to the buffer
78+ * when rewrapping.
79+ */
80+ if (width > FORMATTING_LIMIT ||
81+ indent1 > FORMATTING_LIMIT ||
82+ indent2 > FORMATTING_LIMIT)
83+ return 0;
84 rewrap_message_tail(sb, c, width, indent1, indent2);
85 return end - placeholder + 1;
86 } else
87diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
88index 52c8bc8..572d02f 100755
89--- a/t/t4205-log-pretty-formats.sh
90+++ b/t/t4205-log-pretty-formats.sh
91@@ -809,15 +809,21 @@ test_expect_success 'log --pretty with magical wrapping directives' '
92 '
93
94 test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping directive' '
95- cat >expect <<-EOF &&
96- fatal: number too large to represent as int on this platform: 2147483649
97- EOF
98- test_must_fail git log -1 --pretty="format:%w(2147483649,1,1)%d" 2>error &&
99- test_cmp expect error &&
100- test_must_fail git log -1 --pretty="format:%w(1,2147483649,1)%d" 2>error &&
101- test_cmp expect error &&
102- test_must_fail git log -1 --pretty="format:%w(1,1,2147483649)%d" 2>error &&
103- test_cmp expect error
104+ printf "%%w(2147483649,1,1)0" >expect &&
105+ git log -1 --pretty="format:%w(2147483649,1,1)%x30" >actual &&
106+ test_cmp expect actual &&
107+ printf "%%w(1,2147483649,1)0" >expect &&
108+ git log -1 --pretty="format:%w(1,2147483649,1)%x30" >actual &&
109+ test_cmp expect actual &&
110+ printf "%%w(1,1,2147483649)0" >expect &&
111+ git log -1 --pretty="format:%w(1,1,2147483649)%x30" >actual &&
112+ test_cmp expect actual
113+'
114+
115+test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing padding directive' '
116+ printf "%%<(2147483649)0" >expect &&
117+ git log -1 --pretty="format:%<(2147483649)%x30" >actual &&
118+ test_cmp expect actual
119 '
120
121 test_expect_success 'log --pretty with padding and preceding control chars' '
122--
1232.25.1
124
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/files/CVE-2023-25652.patch b/meta/recipes-devtools/git/files/CVE-2023-25652.patch
new file mode 100644
index 0000000000..d6b17a2b8a
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2023-25652.patch
@@ -0,0 +1,94 @@
1From 9db05711c98efc14f414d4c87135a34c13586e0b Mon Sep 17 00:00:00 2001
2From: Johannes Schindelin <johannes.schindelin@gmx.de>
3Date: Thu, 9 Mar 2023 16:02:54 +0100
4Subject: [PATCH] apply --reject: overwrite existing `.rej` symlink if it
5 exists
6
7The `git apply --reject` is expected to write out `.rej` files in case
8one or more hunks fail to apply cleanly. Historically, the command
9overwrites any existing `.rej` files. The idea being that
10apply/reject/edit cycles are relatively common, and the generated `.rej`
11files are not considered precious.
12
13But the command does not overwrite existing `.rej` symbolic links, and
14instead follows them. This is unsafe because the same patch could
15potentially create such a symbolic link and point at arbitrary paths
16outside the current worktree, and `git apply` would write the contents
17of the `.rej` file into that location.
18
19Therefore, let's make sure that any existing `.rej` file or symbolic
20link is removed before writing it.
21
22Reported-by: RyotaK <ryotak.mail@gmail.com>
23Helped-by: Taylor Blau <me@ttaylorr.com>
24Helped-by: Junio C Hamano <gitster@pobox.com>
25Helped-by: Linus Torvalds <torvalds@linuxfoundation.org>
26Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
27
28Upstream-Status: Backport [https://github.com/git/git/commit/9db05711c98efc14f414d4c87135a34c13586e0b]
29CVE: CVE-2023-25652
30Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
31---
32 apply.c | 14 ++++++++++++--
33 t/t4115-apply-symlink.sh | 15 +++++++++++++++
34 2 files changed, 27 insertions(+), 2 deletions(-)
35
36diff --git a/apply.c b/apply.c
37index 4f303bf..aa7111d 100644
38--- a/apply.c
39+++ b/apply.c
40@@ -4531,7 +4531,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
41 FILE *rej;
42 char namebuf[PATH_MAX];
43 struct fragment *frag;
44- int cnt = 0;
45+ int fd, cnt = 0;
46 struct strbuf sb = STRBUF_INIT;
47
48 for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
49@@ -4571,7 +4571,17 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
50 memcpy(namebuf, patch->new_name, cnt);
51 memcpy(namebuf + cnt, ".rej", 5);
52
53- rej = fopen(namebuf, "w");
54+ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
55+ if (fd < 0) {
56+ if (errno != EEXIST)
57+ return error_errno(_("cannot open %s"), namebuf);
58+ if (unlink(namebuf))
59+ return error_errno(_("cannot unlink '%s'"), namebuf);
60+ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
61+ if (fd < 0)
62+ return error_errno(_("cannot open %s"), namebuf);
63+ }
64+ rej = fdopen(fd, "w");
65 if (!rej)
66 return error_errno(_("cannot open %s"), namebuf);
67
68diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
69index 1acb7b2..2b034ff 100755
70--- a/t/t4115-apply-symlink.sh
71+++ b/t/t4115-apply-symlink.sh
72@@ -125,4 +125,19 @@ test_expect_success SYMLINKS 'symlink escape when deleting file' '
73 test_path_is_file .git/delete-me
74 '
75
76+test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' '
77+ test_when_finished "git reset --hard && git clean -dfx" &&
78+
79+ test_commit file &&
80+ echo modified >file.t &&
81+ git diff -- file.t >patch &&
82+ echo modified-again >file.t &&
83+
84+ ln -s foo file.t.rej &&
85+ test_must_fail git apply patch --reject 2>err &&
86+ test_i18ngrep "Rejected hunk" err &&
87+ test_path_is_missing foo &&
88+ test_path_is_file file.t.rej
89+'
90+
91 test_done
92--
932.25.1
94
diff --git a/meta/recipes-devtools/git/files/CVE-2023-29007.patch b/meta/recipes-devtools/git/files/CVE-2023-29007.patch
new file mode 100644
index 0000000000..e166c01412
--- /dev/null
+++ b/meta/recipes-devtools/git/files/CVE-2023-29007.patch
@@ -0,0 +1,159 @@
1From 057c07a7b1fae22fdeef26c243f4cfbe3afc90ce Mon Sep 17 00:00:00 2001
2From: Taylor Blau <me@ttaylorr.com>
3Date: Fri, 14 Apr 2023 11:46:59 -0400
4Subject: [PATCH] Merge branch 'tb/config-copy-or-rename-in-file-injection'
5
6Avoids issues with renaming or deleting sections with long lines, where
7configuration values may be interpreted as sections, leading to
8configuration injection. Addresses CVE-2023-29007.
9
10* tb/config-copy-or-rename-in-file-injection:
11 config.c: disallow overly-long lines in `copy_or_rename_section_in_file()`
12 config.c: avoid integer truncation in `copy_or_rename_section_in_file()`
13 config: avoid fixed-sized buffer when renaming/deleting a section
14 t1300: demonstrate failure when renaming sections with long lines
15
16Signed-off-by: Taylor Blau <me@ttaylorr.com>
17
18Upstream-Status: Backport [https://github.com/git/git/commit/528290f8c61222433a8cf02fb7cfffa8438432b4]
19CVE: CVE-2023-29007
20Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
21---
22 config.c | 36 +++++++++++++++++++++++++-----------
23 t/t1300-config.sh | 30 ++++++++++++++++++++++++++++++
24 2 files changed, 55 insertions(+), 11 deletions(-)
25
26diff --git a/config.c b/config.c
27index e7052b3..676b687 100644
28--- a/config.c
29+++ b/config.c
30@@ -2987,9 +2987,10 @@ void git_config_set_multivar(const char *key, const char *value,
31 multi_replace);
32 }
33
34-static int section_name_match (const char *buf, const char *name)
35+static size_t section_name_match (const char *buf, const char *name)
36 {
37- int i = 0, j = 0, dot = 0;
38+ size_t i = 0, j = 0;
39+ int dot = 0;
40 if (buf[i] != '[')
41 return 0;
42 for (i = 1; buf[i] && buf[i] != ']'; i++) {
43@@ -3042,6 +3043,8 @@ static int section_name_is_ok(const char *name)
44 return 1;
45 }
46
47+#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
48+
49 /* if new_name == NULL, the section is removed instead */
50 static int git_config_copy_or_rename_section_in_file(const char *config_filename,
51 const char *old_name,
52@@ -3051,11 +3054,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
53 char *filename_buf = NULL;
54 struct lock_file lock = LOCK_INIT;
55 int out_fd;
56- char buf[1024];
57+ struct strbuf buf = STRBUF_INIT;
58 FILE *config_file = NULL;
59 struct stat st;
60 struct strbuf copystr = STRBUF_INIT;
61 struct config_store_data store;
62+ uint32_t line_nr = 0;
63
64 memset(&store, 0, sizeof(store));
65
66@@ -3092,16 +3096,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
67 goto out;
68 }
69
70- while (fgets(buf, sizeof(buf), config_file)) {
71- int i;
72- int length;
73+ while (!strbuf_getwholeline(&buf, config_file, '\n')) {
74+ size_t i, length;
75 int is_section = 0;
76- char *output = buf;
77- for (i = 0; buf[i] && isspace(buf[i]); i++)
78+ char *output = buf.buf;
79+
80+ line_nr++;
81+
82+ if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) {
83+ ret = error(_("refusing to work with overly long line "
84+ "in '%s' on line %"PRIuMAX),
85+ config_filename, (uintmax_t)line_nr);
86+ goto out;
87+ }
88+
89+ for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++)
90 ; /* do nothing */
91- if (buf[i] == '[') {
92+ if (buf.buf[i] == '[') {
93 /* it's a section */
94- int offset;
95+ size_t offset;
96 is_section = 1;
97
98 /*
99@@ -3118,7 +3131,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
100 strbuf_reset(&copystr);
101 }
102
103- offset = section_name_match(&buf[i], old_name);
104+ offset = section_name_match(&buf.buf[i], old_name);
105 if (offset > 0) {
106 ret++;
107 if (new_name == NULL) {
108@@ -3193,6 +3206,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
109 out_no_rollback:
110 free(filename_buf);
111 config_store_data_clear(&store);
112+ strbuf_release(&buf);
113 return ret;
114 }
115
116diff --git a/t/t1300-config.sh b/t/t1300-config.sh
117index 983a0a1..9b67f6b 100755
118--- a/t/t1300-config.sh
119+++ b/t/t1300-config.sh
120@@ -616,6 +616,36 @@ test_expect_success 'renaming to bogus section is rejected' '
121 test_must_fail git config --rename-section branch.zwei "bogus name"
122 '
123
124+test_expect_success 'renaming a section with a long line' '
125+ {
126+ printf "[b]\\n" &&
127+ printf " c = d %1024s [a] e = f\\n" " " &&
128+ printf "[a] g = h\\n"
129+ } >y &&
130+ git config -f y --rename-section a xyz &&
131+ test_must_fail git config -f y b.e
132+'
133+
134+test_expect_success 'renaming an embedded section with a long line' '
135+ {
136+ printf "[b]\\n" &&
137+ printf " c = d %1024s [a] [foo] e = f\\n" " " &&
138+ printf "[a] g = h\\n"
139+ } >y &&
140+ git config -f y --rename-section a xyz &&
141+ test_must_fail git config -f y foo.e
142+'
143+
144+test_expect_success 'renaming a section with an overly-long line' '
145+ {
146+ printf "[b]\\n" &&
147+ printf " c = d %525000s e" " " &&
148+ printf "[a] g = h\\n"
149+ } >y &&
150+ test_must_fail git config -f y --rename-section a xyz 2>err &&
151+ test_i18ngrep "refusing to work with overly long line in .y. on line 2" err
152+'
153+
154 cat >> .git/config << EOF
155 [branch "zwei"] a = 1 [branch "vier"]
156 EOF
157--
1582.25.1
159
diff --git a/meta/recipes-devtools/git/git.inc b/meta/recipes-devtools/git/git.inc
index 4131c98977..e64472ea28 100644
--- a/meta/recipes-devtools/git/git.inc
+++ b/meta/recipes-devtools/git/git.inc
@@ -1,5 +1,6 @@
1SUMMARY = "Distributed version control system" 1SUMMARY = "Distributed version control system"
2HOMEPAGE = "http://git-scm.com" 2HOMEPAGE = "http://git-scm.com"
3DESCRIPTION = "Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency."
3SECTION = "console/utils" 4SECTION = "console/utils"
4LICENSE = "GPLv2" 5LICENSE = "GPLv2"
5DEPENDS = "openssl curl zlib expat" 6DEPENDS = "openssl curl zlib expat"
@@ -7,14 +8,44 @@ DEPENDS = "openssl curl zlib expat"
7PROVIDES_append_class-native = " git-replacement-native" 8PROVIDES_append_class-native = " git-replacement-native"
8 9
9SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \ 10SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \
10 ${KERNELORG_MIRROR}/software/scm/git/git-manpages-${PV}.tar.gz;name=manpages" 11 ${KERNELORG_MIRROR}/software/scm/git/git-manpages-${PV}.tar.gz;name=manpages \
11 12 file://fixsort.patch \
13 file://CVE-2021-40330.patch \
14 file://CVE-2022-23521.patch \
15 file://CVE-2022-41903-01.patch \
16 file://CVE-2022-41903-02.patch \
17 file://CVE-2022-41903-03.patch \
18 file://CVE-2022-41903-04.patch \
19 file://CVE-2022-41903-05.patch \
20 file://CVE-2022-41903-06.patch \
21 file://CVE-2022-41903-07.patch \
22 file://CVE-2022-41903-08.patch \
23 file://CVE-2022-41903-09.patch \
24 file://CVE-2022-41903-10.patch \
25 file://CVE-2022-41903-11.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 \
31 file://CVE-2023-29007.patch \
32 file://CVE-2023-25652.patch \
33 "
12S = "${WORKDIR}/git-${PV}" 34S = "${WORKDIR}/git-${PV}"
13 35
14LIC_FILES_CHKSUM = "file://COPYING;md5=7c0d7ef03a7eb04ce795b0f60e68e7e1" 36LIC_FILES_CHKSUM = "file://COPYING;md5=7c0d7ef03a7eb04ce795b0f60e68e7e1"
15 37
16CVE_PRODUCT = "git-scm:git" 38CVE_PRODUCT = "git-scm:git"
17 39
40# This is about a manpage not mentioning --mirror may "leak" information
41# in mirrored git repos. Most OE users wouldn't build the docs and
42# we don't see this as a major issue for our general users/usecases.
43CVE_CHECK_WHITELIST += "CVE-2022-24975"
44# This is specific to Git-for-Windows
45CVE_CHECK_WHITELIST += "CVE-2022-41953"
46# specific to Git for Windows
47CVE_CHECK_WHITELIST += "CVE-2023-22743"
48
18PACKAGECONFIG ??= "" 49PACKAGECONFIG ??= ""
19PACKAGECONFIG[cvsserver] = "" 50PACKAGECONFIG[cvsserver] = ""
20PACKAGECONFIG[svn] = "" 51PACKAGECONFIG[svn] = ""
diff --git a/meta/recipes-devtools/git/git/fixsort.patch b/meta/recipes-devtools/git/git/fixsort.patch
new file mode 100644
index 0000000000..eec1f84945
--- /dev/null
+++ b/meta/recipes-devtools/git/git/fixsort.patch
@@ -0,0 +1,36 @@
1[PATCH] generate-cmdlist.sh: Fix determinism issue
2
3Currently git binaries are not entirely reproducible, at least partly
4due to config-list.h differing in order depending on the system's
5locale settings. Under different locales, the entries:
6
7"sendemail.identity",
8"sendemail.<identity>.*",
9
10would differ in order for example and this leads to differences in
11the debug symbols for the binaries.
12
13This can be fixed by specifying the C locale for the sort in the
14shell script generating the header.
15
16Note: This is a backport of Richard Purdie's original patch for a more
17recent version of git. The offending code in this older version is
18in generate-cmdlist.sh. The upstream current version has this code
19in generate-configlist.sh.
20
21Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
22Signed-off-by: Steve Sakoman <steve@sakoman.com>
23Upstream-Status: Submitted [https://public-inbox.org/git/f029a942dd3d50d85e60bd37d8e454524987842f.camel@linuxfoundation.org/T/#u]
24
25index 71158f7..c137091 100755
26--- a/generate-cmdlist.sh
27+++ b/generate-cmdlist.sh
28@@ -82,7 +82,7 @@ static const char *config_name_list[] = {
29 EOF
30 grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
31 sed '/deprecated/d; s/::$//; s/, */\n/g' |
32- sort |
33+ LC_ALL=C sort |
34 while read line
35 do
36 echo " \"$line\","
diff --git a/meta/recipes-devtools/git/git_2.24.3.bb b/meta/recipes-devtools/git/git_2.24.4.bb
index ddd875f07b..f38c25f0ef 100644
--- a/meta/recipes-devtools/git/git_2.24.3.bb
+++ b/meta/recipes-devtools/git/git_2.24.4.bb
@@ -5,5 +5,5 @@ EXTRA_OECONF += "ac_cv_snprintf_returns_bogus=no \
5 " 5 "
6EXTRA_OEMAKE += "NO_GETTEXT=1" 6EXTRA_OEMAKE += "NO_GETTEXT=1"
7 7
8SRC_URI[tarball.sha256sum] = "ef6d1d1de1d7921a54d23d07479bd2766f050d6435cea5d3b5322aa4897cb3d7" 8SRC_URI[tarball.sha256sum] = "6e119e70d3762f28e1dc9928c526eb4d7519fd3870f862775cd10186653eb85a"
9SRC_URI[manpages.sha256sum] = "325795ba33c0be02370de79636f32ad3b447665c1f2b5b4de65181fa804bed31" 9SRC_URI[manpages.sha256sum] = "e687bcc91a6fd9cb74243f91a9c2d77c50ce202a09b35931021ecc521a373ed5"