Skip to content

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

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: main
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
235 changes: 235 additions & 0 deletions SPECS/jq/CVE-2024-23337.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
From 9aed9788b5b5e859e15f4a9d658652c8cb3a836e Mon Sep 17 00:00:00 2001
From: akhila-guruju <[email protected]>
Date: Mon, 26 May 2025 09:15:41 +0000
Subject: [PATCH] Address CVE-2024-23337

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

---
src/jv.c | 63 +++++++++++++++++++++++++++++++++++++++------------
src/jv_aux.c | 9 ++++----
tests/jq.test | 4 ++++
3 files changed, 58 insertions(+), 18 deletions(-)

diff --git a/src/jv.c b/src/jv.c
index 979d188..d3042e6 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -352,6 +352,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);
@@ -371,6 +376,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;
@@ -653,15 +659,24 @@ jv jv_string_indexes(jv j, jv k) {
assert(jv_get_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();

- p = jstr;
- while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
- a = jv_array_append(a, jv_number(p - jstr));
- p += idxlen;
+ if (idxlen != 0) {
+ int n = 0;
+ p = lp = jstr;
+ while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like these lines are absent from upstream reference, could you please include reference for these lines as well or have you modified them for fixing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have taken reference from the same upstream link.

+ 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++;
+ }
}
jv_free(j);
jv_free(k);
@@ -682,14 +697,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(""));
@@ -707,8 +725,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;
}
@@ -978,10 +998,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(jv_get_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);
@@ -994,7 +1017,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) {
@@ -1023,27 +1047,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) {
@@ -1128,7 +1157,11 @@ jv jv_object_set(jv object, jv key, jv value) {
assert(jv_get_kind(object) == JV_KIND_OBJECT);
assert(jv_get_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;
@@ -1153,6 +1186,7 @@ jv jv_object_merge(jv a, jv b) {
assert(jv_get_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;
@@ -1172,6 +1206,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 129cd04..2a9d5f9 100644
--- a/src/jv_aux.c
+++ b/src/jv_aux.c
@@ -148,18 +148,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 7e2dd43..2c58574 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -186,6 +186,10 @@ null
[0,1,2]
[0,5,2]

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

8 changes: 6 additions & 2 deletions 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.6
Release: 2%{?dist}
Release: 3%{?dist}
Group: Applications/System
Vendor: Microsoft Corporation
License: MIT
URL: https://github.com/stedolan/jq
Source0: https://github.com/stedolan/jq/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
Distribution: Mariner
Patch0: CVE-2024-23337.patch
BuildRequires: bison
BuildRequires: chrpath
BuildRequires: flex
Expand All @@ -29,7 +30,7 @@ Requires: %{name} = %{version}-%{release}
Development files for jq

%prep
%setup -q
%autosetup -p1

%build
%configure \
Expand Down Expand Up @@ -58,6 +59,9 @@ make check
%{_includedir}/*

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

* Wed Sep 20 2023 Jon Slobodzian <[email protected]> - 1.6-2
- Recompile with stack-protection fixed gcc version (CVE-2023-4039)

Expand Down
Loading