diff mbox series

[meta-oe,kirkstone,1/1] jq: Fix CVE-2024-23337 & CVE-2025-48060

Message ID 20250707205243.2576093-1-colin.mcallister@garmin.com
State New
Headers show
Series [meta-oe,kirkstone,1/1] jq: Fix CVE-2024-23337 & CVE-2025-48060 | expand

Commit Message

Colin McAllister July 7, 2025, 8:52 p.m. UTC
Adds backported patches to fix CVE-2024-23337 & CVE-2025-48060.

Signed-off-by: Colin Pinnell McAllister <colin.mcallister@garmin.com>
---
 .../jq/jq/CVE-2024-23337.patch                | 219 ++++++++++++++++++
 .../jq/jq/CVE-2025-48060.patch                |  46 ++++
 meta-oe/recipes-devtools/jq/jq_git.bb         |   6 +-
 3 files changed, 270 insertions(+), 1 deletion(-)
 create mode 100644 meta-oe/recipes-devtools/jq/jq/CVE-2024-23337.patch
 create mode 100644 meta-oe/recipes-devtools/jq/jq/CVE-2025-48060.patch
diff mbox series

Patch

diff --git a/meta-oe/recipes-devtools/jq/jq/CVE-2024-23337.patch b/meta-oe/recipes-devtools/jq/jq/CVE-2024-23337.patch
new file mode 100644
index 0000000000..87e639aad7
--- /dev/null
+++ b/meta-oe/recipes-devtools/jq/jq/CVE-2024-23337.patch
@@ -0,0 +1,219 @@ 
+From 35cde320ac7ee9ad6da5ce422922fafe592c4c60 Mon Sep 17 00:00:00 2001
+From: itchyny <itchyny@cybozu.co.jp>
+Date: Wed, 21 May 2025 07:45:00 +0900
+Subject: [PATCH 1/2] Fix signed integer overflow in jvp_array_write and
+ jvp_object_rehash
+
+This commit fixes signed integer overflow and SEGV issues on growing
+arrays and objects. The size of arrays and objects is now limited to
+`536870912` (`0x20000000`). This fixes CVE-2024-23337 and fixes #3262.
+
+CVE: CVE-2024-23337
+Upstream-Status: Backport [https://github.com/jqlang/jq/commit/de21386681c0df0104a99d9d09db23a9b2a78b1e]
+Signed-off-by: Colin Pinnell McAllister <colin.mcallister@garmin.com>
+---
+ src/jv.c      | 45 ++++++++++++++++++++++++++++++++++++---------
+ src/jv_aux.c  |  9 +++++----
+ tests/jq.test |  4 ++++
+ 3 files changed, 45 insertions(+), 13 deletions(-)
+
+diff --git a/src/jv.c b/src/jv.c
+index 9784b22..33ccee9 100644
+--- a/src/jv.c
++++ b/src/jv.c
+@@ -1006,6 +1006,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);
+@@ -1025,6 +1030,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;
+@@ -1296,6 +1302,7 @@ jv jv_string_indexes(jv j, jv k) {
+     p = jstr;
+     while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
+       a = jv_array_append(a, jv_number(p - jstr));
++      if (!jv_is_valid(a)) break;
+       p += idxlen;
+     }
+   }
+@@ -1318,14 +1325,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(""));
+@@ -1343,8 +1353,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;
+ }
+@@ -1617,10 +1629,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);
+@@ -1633,7 +1648,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) {
+@@ -1662,27 +1678,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) {
+@@ -1783,7 +1804,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;
+@@ -1808,6 +1833,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;
+@@ -1827,6 +1853,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 994285a..0753aef 100644
+--- a/src/jv_aux.c
++++ b/src/jv_aux.c
+@@ -162,18 +162,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 2d5c36b..c6c6ee5 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.49.0
+
diff --git a/meta-oe/recipes-devtools/jq/jq/CVE-2025-48060.patch b/meta-oe/recipes-devtools/jq/jq/CVE-2025-48060.patch
new file mode 100644
index 0000000000..909a4963c9
--- /dev/null
+++ b/meta-oe/recipes-devtools/jq/jq/CVE-2025-48060.patch
@@ -0,0 +1,46 @@ 
+From 9e23fd7e88bb2d76ddf3fbfc805199f848cd1b92 Mon Sep 17 00:00:00 2001
+From: itchyny <itchyny@cybozu.co.jp>
+Date: Sat, 31 May 2025 11:46:40 +0900
+Subject: [PATCH 2/2] Fix heap buffer overflow when formatting an empty string
+
+The `jv_string_empty` did not properly null-terminate the string data,
+which could lead to a heap buffer overflow. The test case of
+GHSA-p7rr-28xf-3m5w (`0[""*0]`) was fixed by the commit dc849e9bb74a,
+but another case (`0[[]|implode]`) was still vulnerable. This commit
+ensures string data is properly null-terminated, and fixes CVE-2025-48060.
+
+CVE: CVE-2025-48060
+Upstream-Status: Backport [https://github.com/jqlang/jq/commit/c6e041699d8cd31b97375a2596217aff2cfca85b]
+Signed-off-by: Colin Pinnell McAllister <colin.mcallister@garmin.com>
+---
+ src/jv.c      | 1 +
+ tests/jq.test | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/src/jv.c b/src/jv.c
+index 33ccee9..4d7bba1 100644
+--- a/src/jv.c
++++ b/src/jv.c
+@@ -1131,6 +1131,7 @@ static jv jvp_string_empty_new(uint32_t length) {
+   jvp_string* s = jvp_string_alloc(length);
+   s->length_hashed = 0;
+   memset(s->data, 0, length);
++  s->data[length] = 0;
+   jv r = {JVP_FLAGS_STRING, 0, 0, 0, {&s->refcnt}};
+   return r;
+ }
+diff --git a/tests/jq.test b/tests/jq.test
+index c6c6ee5..f783493 100644
+--- a/tests/jq.test
++++ b/tests/jq.test
+@@ -1720,3 +1720,7 @@ false
+ . |= try . catch .
+ 1
+ 1
++
++try 0[implode] catch .
++[]
++"Cannot index number with string \"\""
+-- 
+2.49.0
+
diff --git a/meta-oe/recipes-devtools/jq/jq_git.bb b/meta-oe/recipes-devtools/jq/jq_git.bb
index 8b0218c83e..477fe933b3 100644
--- a/meta-oe/recipes-devtools/jq/jq_git.bb
+++ b/meta-oe/recipes-devtools/jq/jq_git.bb
@@ -9,7 +9,11 @@  LICENSE = "MIT"
 LIC_FILES_CHKSUM = "file://COPYING;md5=2814b59e00e7918c864fa3b6bbe049b4"
 
 PV = "1.6+git${SRCPV}"
-SRC_URI = "git://github.com/stedolan/jq;protocol=https;branch=master"
+SRC_URI = " \
+    git://github.com/stedolan/jq;protocol=https;branch=master \
+    file://CVE-2024-23337.patch \
+    file://CVE-2025-48060.patch \
+    "
 SRCREV = "a9f97e9e61a910a374a5d768244e8ad63f407d3e"
 S = "${WORKDIR}/git"