Skip to content

Commit 4104f73

Browse files
[Medium] Patch jq for CVE-2024-23337 (#13895)
1 parent 162fa3b commit 4104f73

2 files changed

Lines changed: 236 additions & 1 deletion

File tree

SPECS/jq/CVE-2024-23337.patch

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
From f5147060e3339e81857283a61839af58464bca08 Mon Sep 17 00:00:00 2001
2+
From: akhila-guruju <v-guakhila@microsoft.com>
3+
Date: Mon, 26 May 2025 09:31:29 +0000
4+
Subject: [PATCH] Address CVE-2024-23337
5+
6+
Upstream Patch Reference: https://github.com/jqlang/jq/commit/de21386681c0df0104a99d9d09db23a9b2a78b1e
7+
8+
---
9+
src/jv.c | 57 ++++++++++++++++++++++++++++++++++++++++-----------
10+
src/jv_aux.c | 9 ++++----
11+
tests/jq.test | 4 ++++
12+
3 files changed, 54 insertions(+), 16 deletions(-)
13+
14+
diff --git a/src/jv.c b/src/jv.c
15+
index 34573b8..15990f1 100644
16+
--- a/src/jv.c
17+
+++ b/src/jv.c
18+
@@ -1001,6 +1001,11 @@ jv jv_array_set(jv j, int idx, jv val) {
19+
jv_free(val);
20+
return jv_invalid_with_msg(jv_string("Out of bounds negative array index"));
21+
}
22+
+ if (idx > (INT_MAX >> 2) - jvp_array_offset(j)) {
23+
+ jv_free(j);
24+
+ jv_free(val);
25+
+ return jv_invalid_with_msg(jv_string("Array index too large"));
26+
+ }
27+
// copy/free of val,j coalesced
28+
jv* slot = jvp_array_write(&j, idx);
29+
jv_free(*slot);
30+
@@ -1020,6 +1025,7 @@ jv jv_array_concat(jv a, jv b) {
31+
// FIXME: could be faster
32+
jv_array_foreach(b, i, elem) {
33+
a = jv_array_append(a, elem);
34+
+ if (!jv_is_valid(a)) break;
35+
}
36+
jv_free(b);
37+
return a;
38+
@@ -1283,15 +1289,22 @@ jv jv_string_indexes(jv j, jv k) {
39+
assert(JVP_HAS_KIND(k, JV_KIND_STRING));
40+
const char *jstr = jv_string_value(j);
41+
const char *idxstr = jv_string_value(k);
42+
- const char *p;
43+
+ const char *p, *lp;
44+
int jlen = jv_string_length_bytes(jv_copy(j));
45+
int idxlen = jv_string_length_bytes(jv_copy(k));
46+
jv a = jv_array();
47+
48+
if (idxlen != 0) {
49+
- p = jstr;
50+
+ int n = 0;
51+
+ p = lp = jstr;
52+
while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
53+
- a = jv_array_append(a, jv_number(p - jstr));
54+
+ while (lp < p) {
55+
+ lp += jvp_utf8_decode_length(*lp);
56+
+ n++;
57+
+ }
58+
+
59+
+ a = jv_array_append(a, jv_number(n));
60+
+ if (!jv_is_valid(a)) break;
61+
p++;
62+
}
63+
}
64+
@@ -1314,14 +1327,17 @@ jv jv_string_split(jv j, jv sep) {
65+
66+
if (seplen == 0) {
67+
int c;
68+
- while ((jstr = jvp_utf8_next(jstr, jend, &c)))
69+
+ while ((jstr = jvp_utf8_next(jstr, jend, &c))) {
70+
a = jv_array_append(a, jv_string_append_codepoint(jv_string(""), c));
71+
+ if (!jv_is_valid(a)) break;
72+
+ }
73+
} else {
74+
for (p = jstr; p < jend; p = s + seplen) {
75+
s = _jq_memmem(p, jend - p, sepstr, seplen);
76+
if (s == NULL)
77+
s = jend;
78+
a = jv_array_append(a, jv_string_sized(p, s - p));
79+
+ if (!jv_is_valid(a)) break;
80+
// Add an empty string to denote that j ends on a sep
81+
if (s + seplen == jend && seplen != 0)
82+
a = jv_array_append(a, jv_string(""));
83+
@@ -1339,8 +1355,10 @@ jv jv_string_explode(jv j) {
84+
const char* end = i + len;
85+
jv a = jv_array_sized(len);
86+
int c;
87+
- while ((i = jvp_utf8_next(i, end, &c)))
88+
+ while ((i = jvp_utf8_next(i, end, &c))) {
89+
a = jv_array_append(a, jv_number(c));
90+
+ if (!jv_is_valid(a)) break;
91+
+ }
92+
jv_free(j);
93+
return a;
94+
}
95+
@@ -1614,10 +1632,13 @@ static void jvp_object_free(jv o) {
96+
}
97+
}
98+
99+
-static jv jvp_object_rehash(jv object) {
100+
+static int jvp_object_rehash(jv *objectp) {
101+
+ jv object = *objectp;
102+
assert(JVP_HAS_KIND(object, JV_KIND_OBJECT));
103+
assert(jvp_refcnt_unshared(object.u.ptr));
104+
int size = jvp_object_size(object);
105+
+ if (size > INT_MAX >> 2)
106+
+ return 0;
107+
jv new_object = jvp_object_new(size * 2);
108+
for (int i=0; i<size; i++) {
109+
struct object_slot* slot = jvp_object_get_slot(object, i);
110+
@@ -1630,7 +1651,8 @@ static jv jvp_object_rehash(jv object) {
111+
}
112+
// references are transported, just drop the old table
113+
jv_mem_free(jvp_object_ptr(object));
114+
- return new_object;
115+
+ *objectp = new_object;
116+
+ return 1;
117+
}
118+
119+
static jv jvp_object_unshare(jv object) {
120+
@@ -1659,27 +1681,32 @@ static jv jvp_object_unshare(jv object) {
121+
return new_object;
122+
}
123+
124+
-static jv* jvp_object_write(jv* object, jv key) {
125+
+static int jvp_object_write(jv* object, jv key, jv **valpp) {
126+
*object = jvp_object_unshare(*object);
127+
int* bucket = jvp_object_find_bucket(*object, key);
128+
struct object_slot* slot = jvp_object_find_slot(*object, key, bucket);
129+
if (slot) {
130+
// already has the key
131+
jvp_string_free(key);
132+
- return &slot->value;
133+
+ *valpp = &slot->value;
134+
+ return 1;
135+
}
136+
slot = jvp_object_add_slot(*object, key, bucket);
137+
if (slot) {
138+
slot->value = jv_invalid();
139+
} else {
140+
- *object = jvp_object_rehash(*object);
141+
+ if (!jvp_object_rehash(object)) {
142+
+ *valpp = NULL;
143+
+ return 0;
144+
+ }
145+
bucket = jvp_object_find_bucket(*object, key);
146+
assert(!jvp_object_find_slot(*object, key, bucket));
147+
slot = jvp_object_add_slot(*object, key, bucket);
148+
assert(slot);
149+
slot->value = jv_invalid();
150+
}
151+
- return &slot->value;
152+
+ *valpp = &slot->value;
153+
+ return 1;
154+
}
155+
156+
static int jvp_object_delete(jv* object, jv key) {
157+
@@ -1779,7 +1806,11 @@ jv jv_object_set(jv object, jv key, jv value) {
158+
assert(JVP_HAS_KIND(object, JV_KIND_OBJECT));
159+
assert(JVP_HAS_KIND(key, JV_KIND_STRING));
160+
// copy/free of object, key, value coalesced
161+
- jv* slot = jvp_object_write(&object, key);
162+
+ jv* slot;
163+
+ if (!jvp_object_write(&object, key, &slot)) {
164+
+ jv_free(object);
165+
+ return jv_invalid_with_msg(jv_string("Object too big"));
166+
+ }
167+
jv_free(*slot);
168+
*slot = value;
169+
return object;
170+
@@ -1804,6 +1835,7 @@ jv jv_object_merge(jv a, jv b) {
171+
assert(JVP_HAS_KIND(a, JV_KIND_OBJECT));
172+
jv_object_foreach(b, k, v) {
173+
a = jv_object_set(a, k, v);
174+
+ if (!jv_is_valid(a)) break;
175+
}
176+
jv_free(b);
177+
return a;
178+
@@ -1823,6 +1855,7 @@ jv jv_object_merge_recursive(jv a, jv b) {
179+
jv_free(elem);
180+
a = jv_object_set(a, k, v);
181+
}
182+
+ if (!jv_is_valid(a)) break;
183+
}
184+
jv_free(b);
185+
return a;
186+
diff --git a/src/jv_aux.c b/src/jv_aux.c
187+
index 6004799..bbe1c0d 100644
188+
--- a/src/jv_aux.c
189+
+++ b/src/jv_aux.c
190+
@@ -193,18 +193,19 @@ jv jv_set(jv t, jv k, jv v) {
191+
if (slice_len < insert_len) {
192+
// array is growing
193+
int shift = insert_len - slice_len;
194+
- for (int i = array_len - 1; i >= end; i--) {
195+
+ for (int i = array_len - 1; i >= end && jv_is_valid(t); i--) {
196+
t = jv_array_set(t, i + shift, jv_array_get(jv_copy(t), i));
197+
}
198+
} else if (slice_len > insert_len) {
199+
// array is shrinking
200+
int shift = slice_len - insert_len;
201+
- for (int i = end; i < array_len; i++) {
202+
+ for (int i = end; i < array_len && jv_is_valid(t); i++) {
203+
t = jv_array_set(t, i - shift, jv_array_get(jv_copy(t), i));
204+
}
205+
- t = jv_array_slice(t, 0, array_len - shift);
206+
+ if (jv_is_valid(t))
207+
+ t = jv_array_slice(t, 0, array_len - shift);
208+
}
209+
- for (int i=0; i < insert_len; i++) {
210+
+ for (int i = 0; i < insert_len && jv_is_valid(t); i++) {
211+
t = jv_array_set(t, start + i, jv_array_get(jv_copy(v), i));
212+
}
213+
jv_free(v);
214+
diff --git a/tests/jq.test b/tests/jq.test
215+
index 7011cf9..cd650d4 100644
216+
--- a/tests/jq.test
217+
+++ b/tests/jq.test
218+
@@ -198,6 +198,10 @@ null
219+
[0,1,2]
220+
[0,5,2]
221+
222+
+try (.[999999999] = 0) catch .
223+
+null
224+
+"Array index too large"
225+
+
226+
#
227+
# Multiple outputs, iteration
228+
#
229+
--
230+
2.45.2
231+

SPECS/jq/jq.spec

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
Summary: jq is a lightweight and flexible command-line JSON processor.
22
Name: jq
33
Version: 1.7.1
4-
Release: 2%{?dist}
4+
Release: 3%{?dist}
55
Group: Applications/System
66
Vendor: Microsoft Corporation
77
License: MIT
88
URL: https://jqlang.github.io/jq/
99
Source0: https://github.com/jqlang/jq/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
1010
Patch0: CVE-2024-53427.patch
11+
Patch1: CVE-2024-23337.patch
1112
Distribution: Azure Linux
1213
BuildRequires: bison
1314
BuildRequires: chrpath
@@ -60,6 +61,9 @@ make check
6061
%{_includedir}/*
6162

6263
%changelog
64+
* Mon May 26 2025 Akhila Guruju <v-guakhila@microsoft.com> - 1.7.1-3
65+
- Patch CVE-2024-23337
66+
6367
* Wed Mar 05 2025 Kanishk Bansal <kanbansal@microsoft.com> - 1.7.1-2
6468
- Patch CVE-2024-53427
6569

0 commit comments

Comments
 (0)