Skip to content

Commit 6a78b9e

Browse files
[Medium] Patch jq for CVE-2024-23337 (#13892)
1 parent cac3d54 commit 6a78b9e

File tree

2 files changed

+241
-2
lines changed

2 files changed

+241
-2
lines changed

SPECS/jq/CVE-2024-23337.patch

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
From 9aed9788b5b5e859e15f4a9d658652c8cb3a836e Mon Sep 17 00:00:00 2001
2+
From: akhila-guruju <[email protected]>
3+
Date: Mon, 26 May 2025 09:15:41 +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 | 63 +++++++++++++++++++++++++++++++++++++++------------
10+
src/jv_aux.c | 9 ++++----
11+
tests/jq.test | 4 ++++
12+
3 files changed, 58 insertions(+), 18 deletions(-)
13+
14+
diff --git a/src/jv.c b/src/jv.c
15+
index 979d188..d3042e6 100644
16+
--- a/src/jv.c
17+
+++ b/src/jv.c
18+
@@ -352,6 +352,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+
@@ -371,6 +376,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+
@@ -653,15 +659,24 @@ jv jv_string_indexes(jv j, jv k) {
39+
assert(jv_get_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+
- p = jstr;
49+
- while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
50+
- a = jv_array_append(a, jv_number(p - jstr));
51+
- p += idxlen;
52+
+ if (idxlen != 0) {
53+
+ int n = 0;
54+
+ p = lp = jstr;
55+
+ while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
56+
+ while (lp < p) {
57+
+ lp += jvp_utf8_decode_length(*lp);
58+
+ n++;
59+
+ }
60+
+
61+
+ a = jv_array_append(a, jv_number(n));
62+
+ if (!jv_is_valid(a)) break;
63+
+ p++;
64+
+ }
65+
}
66+
jv_free(j);
67+
jv_free(k);
68+
@@ -682,14 +697,17 @@ jv jv_string_split(jv j, jv sep) {
69+
70+
if (seplen == 0) {
71+
int c;
72+
- while ((jstr = jvp_utf8_next(jstr, jend, &c)))
73+
+ while ((jstr = jvp_utf8_next(jstr, jend, &c))) {
74+
a = jv_array_append(a, jv_string_append_codepoint(jv_string(""), c));
75+
+ if (!jv_is_valid(a)) break;
76+
+ }
77+
} else {
78+
for (p = jstr; p < jend; p = s + seplen) {
79+
s = _jq_memmem(p, jend - p, sepstr, seplen);
80+
if (s == NULL)
81+
s = jend;
82+
a = jv_array_append(a, jv_string_sized(p, s - p));
83+
+ if (!jv_is_valid(a)) break;
84+
// Add an empty string to denote that j ends on a sep
85+
if (s + seplen == jend && seplen != 0)
86+
a = jv_array_append(a, jv_string(""));
87+
@@ -707,8 +725,10 @@ jv jv_string_explode(jv j) {
88+
const char* end = i + len;
89+
jv a = jv_array_sized(len);
90+
int c;
91+
- while ((i = jvp_utf8_next(i, end, &c)))
92+
+ while ((i = jvp_utf8_next(i, end, &c))) {
93+
a = jv_array_append(a, jv_number(c));
94+
+ if (!jv_is_valid(a)) break;
95+
+ }
96+
jv_free(j);
97+
return a;
98+
}
99+
@@ -978,10 +998,13 @@ static void jvp_object_free(jv o) {
100+
}
101+
}
102+
103+
-static jv jvp_object_rehash(jv object) {
104+
+static int jvp_object_rehash(jv *objectp) {
105+
+ jv object = *objectp;
106+
assert(jv_get_kind(object) == JV_KIND_OBJECT);
107+
assert(jvp_refcnt_unshared(object.u.ptr));
108+
int size = jvp_object_size(object);
109+
+ if (size > INT_MAX >> 2)
110+
+ return 0;
111+
jv new_object = jvp_object_new(size * 2);
112+
for (int i=0; i<size; i++) {
113+
struct object_slot* slot = jvp_object_get_slot(object, i);
114+
@@ -994,7 +1017,8 @@ static jv jvp_object_rehash(jv object) {
115+
}
116+
// references are transported, just drop the old table
117+
jv_mem_free(jvp_object_ptr(object));
118+
- return new_object;
119+
+ *objectp = new_object;
120+
+ return 1;
121+
}
122+
123+
static jv jvp_object_unshare(jv object) {
124+
@@ -1023,27 +1047,32 @@ static jv jvp_object_unshare(jv object) {
125+
return new_object;
126+
}
127+
128+
-static jv* jvp_object_write(jv* object, jv key) {
129+
+static int jvp_object_write(jv* object, jv key, jv **valpp) {
130+
*object = jvp_object_unshare(*object);
131+
int* bucket = jvp_object_find_bucket(*object, key);
132+
struct object_slot* slot = jvp_object_find_slot(*object, key, bucket);
133+
if (slot) {
134+
// already has the key
135+
jvp_string_free(key);
136+
- return &slot->value;
137+
+ *valpp = &slot->value;
138+
+ return 1;
139+
}
140+
slot = jvp_object_add_slot(*object, key, bucket);
141+
if (slot) {
142+
slot->value = jv_invalid();
143+
} else {
144+
- *object = jvp_object_rehash(*object);
145+
+ if (!jvp_object_rehash(object)) {
146+
+ *valpp = NULL;
147+
+ return 0;
148+
+ }
149+
bucket = jvp_object_find_bucket(*object, key);
150+
assert(!jvp_object_find_slot(*object, key, bucket));
151+
slot = jvp_object_add_slot(*object, key, bucket);
152+
assert(slot);
153+
slot->value = jv_invalid();
154+
}
155+
- return &slot->value;
156+
+ *valpp = &slot->value;
157+
+ return 1;
158+
}
159+
160+
static int jvp_object_delete(jv* object, jv key) {
161+
@@ -1128,7 +1157,11 @@ jv jv_object_set(jv object, jv key, jv value) {
162+
assert(jv_get_kind(object) == JV_KIND_OBJECT);
163+
assert(jv_get_kind(key) == JV_KIND_STRING);
164+
// copy/free of object, key, value coalesced
165+
- jv* slot = jvp_object_write(&object, key);
166+
+ jv* slot;
167+
+ if (!jvp_object_write(&object, key, &slot)) {
168+
+ jv_free(object);
169+
+ return jv_invalid_with_msg(jv_string("Object too big"));
170+
+ }
171+
jv_free(*slot);
172+
*slot = value;
173+
return object;
174+
@@ -1153,6 +1186,7 @@ jv jv_object_merge(jv a, jv b) {
175+
assert(jv_get_kind(a) == JV_KIND_OBJECT);
176+
jv_object_foreach(b, k, v) {
177+
a = jv_object_set(a, k, v);
178+
+ if (!jv_is_valid(a)) break;
179+
}
180+
jv_free(b);
181+
return a;
182+
@@ -1172,6 +1206,7 @@ jv jv_object_merge_recursive(jv a, jv b) {
183+
jv_free(elem);
184+
a = jv_object_set(a, k, v);
185+
}
186+
+ if (!jv_is_valid(a)) break;
187+
}
188+
jv_free(b);
189+
return a;
190+
diff --git a/src/jv_aux.c b/src/jv_aux.c
191+
index 129cd04..2a9d5f9 100644
192+
--- a/src/jv_aux.c
193+
+++ b/src/jv_aux.c
194+
@@ -148,18 +148,19 @@ jv jv_set(jv t, jv k, jv v) {
195+
if (slice_len < insert_len) {
196+
// array is growing
197+
int shift = insert_len - slice_len;
198+
- for (int i = array_len - 1; i >= end; i--) {
199+
+ for (int i = array_len - 1; i >= end && jv_is_valid(t); i--) {
200+
t = jv_array_set(t, i + shift, jv_array_get(jv_copy(t), i));
201+
}
202+
} else if (slice_len > insert_len) {
203+
// array is shrinking
204+
int shift = slice_len - insert_len;
205+
- for (int i = end; i < array_len; i++) {
206+
+ for (int i = end; i < array_len && jv_is_valid(t); i++) {
207+
t = jv_array_set(t, i - shift, jv_array_get(jv_copy(t), i));
208+
}
209+
- t = jv_array_slice(t, 0, array_len - shift);
210+
+ if (jv_is_valid(t))
211+
+ t = jv_array_slice(t, 0, array_len - shift);
212+
}
213+
- for (int i=0; i < insert_len; i++) {
214+
+ for (int i = 0; i < insert_len && jv_is_valid(t); i++) {
215+
t = jv_array_set(t, start + i, jv_array_get(jv_copy(v), i));
216+
}
217+
jv_free(v);
218+
diff --git a/tests/jq.test b/tests/jq.test
219+
index 7e2dd43..2c58574 100644
220+
--- a/tests/jq.test
221+
+++ b/tests/jq.test
222+
@@ -186,6 +186,10 @@ null
223+
[0,1,2]
224+
[0,5,2]
225+
226+
+try (.[999999999] = 0) catch .
227+
+null
228+
+"Array index too large"
229+
+
230+
#
231+
# Multiple outputs, iteration
232+
#
233+
--
234+
2.45.2
235+

SPECS/jq/jq.spec

Lines changed: 6 additions & 2 deletions
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.6
4-
Release: 2%{?dist}
4+
Release: 3%{?dist}
55
Group: Applications/System
66
Vendor: Microsoft Corporation
77
License: MIT
88
URL: https://github.com/stedolan/jq
99
Source0: https://github.com/stedolan/jq/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
1010
Distribution: Mariner
11+
Patch0: CVE-2024-23337.patch
1112
BuildRequires: bison
1213
BuildRequires: chrpath
1314
BuildRequires: flex
@@ -29,7 +30,7 @@ Requires: %{name} = %{version}-%{release}
2930
Development files for jq
3031

3132
%prep
32-
%setup -q
33+
%autosetup -p1
3334

3435
%build
3536
%configure \
@@ -58,6 +59,9 @@ make check
5859
%{_includedir}/*
5960

6061
%changelog
62+
* Mon May 26 2025 Akhila Guruju <[email protected]> - 1.6-3
63+
- Patch CVE-2024-23337
64+
6165
* Wed Sep 20 2023 Jon Slobodzian <[email protected]> - 1.6-2
6266
- Recompile with stack-protection fixed gcc version (CVE-2023-4039)
6367

0 commit comments

Comments
 (0)