Skip to content

[Medium] Patch jq for CVE-2024-23337 #13895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 3.0-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 231 additions & 0 deletions SPECS/jq/CVE-2024-23337.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
From f5147060e3339e81857283a61839af58464bca08 Mon Sep 17 00:00:00 2001
From: akhila-guruju <[email protected]>
Date: Mon, 26 May 2025 09:31:29 +0000
Subject: [PATCH] Address CVE-2024-23337

Upstream Patch Reference: https://github.com/jqlang/jq/commit/de21386681c0df0104a99d9d09db23a9b2a78b1e

---
src/jv.c | 57 ++++++++++++++++++++++++++++++++++++++++-----------
src/jv_aux.c | 9 ++++----
tests/jq.test | 4 ++++
3 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/src/jv.c b/src/jv.c
index 34573b8..15990f1 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -1001,6 +1001,11 @@ jv jv_array_set(jv j, int idx, jv val) {
jv_free(val);
return jv_invalid_with_msg(jv_string("Out of bounds negative array index"));
}
+ if (idx > (INT_MAX >> 2) - jvp_array_offset(j)) {
+ jv_free(j);
+ jv_free(val);
+ return jv_invalid_with_msg(jv_string("Array index too large"));
+ }
// copy/free of val,j coalesced
jv* slot = jvp_array_write(&j, idx);
jv_free(*slot);
@@ -1020,6 +1025,7 @@ jv jv_array_concat(jv a, jv b) {
// FIXME: could be faster
jv_array_foreach(b, i, elem) {
a = jv_array_append(a, elem);
+ if (!jv_is_valid(a)) break;
}
jv_free(b);
return a;
@@ -1283,15 +1289,22 @@ jv jv_string_indexes(jv j, jv k) {
assert(JVP_HAS_KIND(k, JV_KIND_STRING));
const char *jstr = jv_string_value(j);
const char *idxstr = jv_string_value(k);
- const char *p;
+ const char *p, *lp;
int jlen = jv_string_length_bytes(jv_copy(j));
int idxlen = jv_string_length_bytes(jv_copy(k));
jv a = jv_array();

if (idxlen != 0) {
- p = jstr;
+ int n = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patch has slight deviation from upstream here.
Request @kgodara912 to also please review my LGTM as well :)

LGTM w.r.t functionality.

+ p = lp = jstr;
while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
- a = jv_array_append(a, jv_number(p - jstr));
+ while (lp < p) {
+ lp += jvp_utf8_decode_length(*lp);
+ n++;
+ }
+
+ a = jv_array_append(a, jv_number(n));
+ if (!jv_is_valid(a)) break;
p++;
}
}
@@ -1314,14 +1327,17 @@ jv jv_string_split(jv j, jv sep) {

if (seplen == 0) {
int c;
- while ((jstr = jvp_utf8_next(jstr, jend, &c)))
+ while ((jstr = jvp_utf8_next(jstr, jend, &c))) {
a = jv_array_append(a, jv_string_append_codepoint(jv_string(""), c));
+ if (!jv_is_valid(a)) break;
+ }
} else {
for (p = jstr; p < jend; p = s + seplen) {
s = _jq_memmem(p, jend - p, sepstr, seplen);
if (s == NULL)
s = jend;
a = jv_array_append(a, jv_string_sized(p, s - p));
+ if (!jv_is_valid(a)) break;
// Add an empty string to denote that j ends on a sep
if (s + seplen == jend && seplen != 0)
a = jv_array_append(a, jv_string(""));
@@ -1339,8 +1355,10 @@ jv jv_string_explode(jv j) {
const char* end = i + len;
jv a = jv_array_sized(len);
int c;
- while ((i = jvp_utf8_next(i, end, &c)))
+ while ((i = jvp_utf8_next(i, end, &c))) {
a = jv_array_append(a, jv_number(c));
+ if (!jv_is_valid(a)) break;
+ }
jv_free(j);
return a;
}
@@ -1614,10 +1632,13 @@ static void jvp_object_free(jv o) {
}
}

-static jv jvp_object_rehash(jv object) {
+static int jvp_object_rehash(jv *objectp) {
+ jv object = *objectp;
assert(JVP_HAS_KIND(object, JV_KIND_OBJECT));
assert(jvp_refcnt_unshared(object.u.ptr));
int size = jvp_object_size(object);
+ if (size > INT_MAX >> 2)
+ return 0;
jv new_object = jvp_object_new(size * 2);
for (int i=0; i<size; i++) {
struct object_slot* slot = jvp_object_get_slot(object, i);
@@ -1630,7 +1651,8 @@ static jv jvp_object_rehash(jv object) {
}
// references are transported, just drop the old table
jv_mem_free(jvp_object_ptr(object));
- return new_object;
+ *objectp = new_object;
+ return 1;
}

static jv jvp_object_unshare(jv object) {
@@ -1659,27 +1681,32 @@ static jv jvp_object_unshare(jv object) {
return new_object;
}

-static jv* jvp_object_write(jv* object, jv key) {
+static int jvp_object_write(jv* object, jv key, jv **valpp) {
*object = jvp_object_unshare(*object);
int* bucket = jvp_object_find_bucket(*object, key);
struct object_slot* slot = jvp_object_find_slot(*object, key, bucket);
if (slot) {
// already has the key
jvp_string_free(key);
- return &slot->value;
+ *valpp = &slot->value;
+ return 1;
}
slot = jvp_object_add_slot(*object, key, bucket);
if (slot) {
slot->value = jv_invalid();
} else {
- *object = jvp_object_rehash(*object);
+ if (!jvp_object_rehash(object)) {
+ *valpp = NULL;
+ return 0;
+ }
bucket = jvp_object_find_bucket(*object, key);
assert(!jvp_object_find_slot(*object, key, bucket));
slot = jvp_object_add_slot(*object, key, bucket);
assert(slot);
slot->value = jv_invalid();
}
- return &slot->value;
+ *valpp = &slot->value;
+ return 1;
}

static int jvp_object_delete(jv* object, jv key) {
@@ -1779,7 +1806,11 @@ jv jv_object_set(jv object, jv key, jv value) {
assert(JVP_HAS_KIND(object, JV_KIND_OBJECT));
assert(JVP_HAS_KIND(key, JV_KIND_STRING));
// copy/free of object, key, value coalesced
- jv* slot = jvp_object_write(&object, key);
+ jv* slot;
+ if (!jvp_object_write(&object, key, &slot)) {
+ jv_free(object);
+ return jv_invalid_with_msg(jv_string("Object too big"));
+ }
jv_free(*slot);
*slot = value;
return object;
@@ -1804,6 +1835,7 @@ jv jv_object_merge(jv a, jv b) {
assert(JVP_HAS_KIND(a, JV_KIND_OBJECT));
jv_object_foreach(b, k, v) {
a = jv_object_set(a, k, v);
+ if (!jv_is_valid(a)) break;
}
jv_free(b);
return a;
@@ -1823,6 +1855,7 @@ jv jv_object_merge_recursive(jv a, jv b) {
jv_free(elem);
a = jv_object_set(a, k, v);
}
+ if (!jv_is_valid(a)) break;
}
jv_free(b);
return a;
diff --git a/src/jv_aux.c b/src/jv_aux.c
index 6004799..bbe1c0d 100644
--- a/src/jv_aux.c
+++ b/src/jv_aux.c
@@ -193,18 +193,19 @@ jv jv_set(jv t, jv k, jv v) {
if (slice_len < insert_len) {
// array is growing
int shift = insert_len - slice_len;
- for (int i = array_len - 1; i >= end; i--) {
+ for (int i = array_len - 1; i >= end && jv_is_valid(t); i--) {
t = jv_array_set(t, i + shift, jv_array_get(jv_copy(t), i));
}
} else if (slice_len > insert_len) {
// array is shrinking
int shift = slice_len - insert_len;
- for (int i = end; i < array_len; i++) {
+ for (int i = end; i < array_len && jv_is_valid(t); i++) {
t = jv_array_set(t, i - shift, jv_array_get(jv_copy(t), i));
}
- t = jv_array_slice(t, 0, array_len - shift);
+ if (jv_is_valid(t))
+ t = jv_array_slice(t, 0, array_len - shift);
}
- for (int i=0; i < insert_len; i++) {
+ for (int i = 0; i < insert_len && jv_is_valid(t); i++) {
t = jv_array_set(t, start + i, jv_array_get(jv_copy(v), i));
}
jv_free(v);
diff --git a/tests/jq.test b/tests/jq.test
index 7011cf9..cd650d4 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -198,6 +198,10 @@ null
[0,1,2]
[0,5,2]

+try (.[999999999] = 0) catch .
+null
+"Array index too large"
+
#
# Multiple outputs, iteration
#
--
2.45.2

6 changes: 5 additions & 1 deletion SPECS/jq/jq.spec
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
Summary: jq is a lightweight and flexible command-line JSON processor.
Name: jq
Version: 1.7.1
Release: 2%{?dist}
Release: 3%{?dist}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Group: Applications/System
Vendor: Microsoft Corporation
License: MIT
URL: https://jqlang.github.io/jq/
Source0: https://github.com/jqlang/jq/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
Patch0: CVE-2024-53427.patch
Patch1: CVE-2024-23337.patch
Distribution: Azure Linux
BuildRequires: bison
BuildRequires: chrpath
Expand Down Expand Up @@ -60,6 +61,9 @@ make check
%{_includedir}/*

%changelog
* Mon May 26 2025 Akhila Guruju <[email protected]> - 1.7.1-3
- Patch CVE-2024-23337

* Wed Mar 05 2025 Kanishk Bansal <[email protected]> - 1.7.1-2
- Patch CVE-2024-53427

Expand Down
Loading