Skip to content
Merged
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
55 changes: 55 additions & 0 deletions SPECS/jq/CVE-2026-32316.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
From a7fbbe20b2c2d9d779c5258438e339dd5b18f19f Mon Sep 17 00:00:00 2001
From: itchyny <itchyny@cybozu.co.jp>
Date: Thu, 12 Mar 2026 20:28:43 +0900
Subject: [PATCH] Fix heap buffer overflow in `jvp_string_append` and
`jvp_string_copy_replace_bad`

In `jvp_string_append`, the allocation size `(currlen + len) * 2` could
overflow `uint32_t` when `currlen + len` exceeds `INT_MAX`, causing a small
allocation followed by a large `memcpy`.

In `jvp_string_copy_replace_bad`, the output buffer size calculation
`length * 3 + 1` could overflow `uint32_t`, again resulting in a small
allocation followed by a large write.

Add overflow checks to both functions to return an error for strings
that would exceed `INT_MAX` in length. Fixes CVE-2026-32316.

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/jqlang/jq/commit/e47e56d226519635768e6aab2f38f0ab037c09e5.patch
---
src/jv.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/jv.c b/src/jv.c
index d7e3938..8b4afad 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -464,7 +464,12 @@ static jv jvp_string_copy_replace_bad(const char* data, uint32_t length) {
const char* i = data;
const char* cstart;

- uint32_t maxlength = length * 3 + 1; // worst case: all bad bytes, each becomes a 3-byte U+FFFD
+ // worst case: all bad bytes, each becomes a 3-byte U+FFFD
+ uint64_t maxlength = (uint64_t)length * 3 + 1;
+ if (maxlength >= INT_MAX) {
+ return jv_invalid_with_msg(jv_string("String too long"));
+ }
+
jvp_string* s = jvp_string_alloc(maxlength);
char* out = s->data;
int c = 0;
@@ -524,6 +529,10 @@ static uint32_t jvp_string_remaining_space(jvp_string* s) {
static jv jvp_string_append(jv string, const char* data, uint32_t len) {
jvp_string* s = jvp_string_ptr(string);
uint32_t currlen = jvp_string_length(s);
+ if ((uint64_t)currlen + len >= INT_MAX) {
+ jv_free(string);
+ return jv_invalid_with_msg(jv_string("String too long"));
+ }

if (jvp_refcnt_unshared(string.u.ptr) &&
jvp_string_remaining_space(s) >= len) {
--
2.45.4

109 changes: 109 additions & 0 deletions SPECS/jq/CVE-2026-33947.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
From af899d361e521471524c17979fe508a24a69c0a1 Mon Sep 17 00:00:00 2001
From: itchyny <itchyny@cybozu.co.jp>
Date: Mon, 13 Apr 2026 11:23:40 +0900
Subject: [PATCH] Limit path depth to prevent stack overflow

Deeply nested path arrays can cause unbounded recursion in
`jv_setpath`, `jv_getpath`, and `jv_delpaths`, leading to
stack overflow. Add a depth limit of 10000 to match the
existing `tojson` depth limit. This fixes CVE-2026-33947.

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/jqlang/jq/commit/fb59f1491058d58bdc3e8dd28f1773d1ac690a1f.patch
---
src/jv_aux.c | 21 +++++++++++++++++++++
tests/jq.test | 25 +++++++++++++++++++++++++
2 files changed, 46 insertions(+)

diff --git a/src/jv_aux.c b/src/jv_aux.c
index 2a9d5f9..0d52e2c 100644
--- a/src/jv_aux.c
+++ b/src/jv_aux.c
@@ -317,6 +317,10 @@ static jv jv_dels(jv t, jv keys) {
return t;
}

+#ifndef MAX_PATH_DEPTH
+#define MAX_PATH_DEPTH (10000)
+#endif
+
jv jv_setpath(jv root, jv path, jv value) {
if (jv_get_kind(path) != JV_KIND_ARRAY) {
jv_free(value);
@@ -324,6 +328,12 @@ jv jv_setpath(jv root, jv path, jv value) {
jv_free(path);
return jv_invalid_with_msg(jv_string("Path must be specified as an array"));
}
+ if (jv_array_length(jv_copy(path)) > MAX_PATH_DEPTH) {
+ jv_free(value);
+ jv_free(root);
+ jv_free(path);
+ return jv_invalid_with_msg(jv_string("Path too deep"));
+ }
if (!jv_is_valid(root)){
jv_free(value);
jv_free(path);
@@ -346,6 +356,11 @@ jv jv_getpath(jv root, jv path) {
jv_free(path);
return jv_invalid_with_msg(jv_string("Path must be specified as an array"));
}
+ if (jv_array_length(jv_copy(path)) > MAX_PATH_DEPTH) {
+ jv_free(root);
+ jv_free(path);
+ return jv_invalid_with_msg(jv_string("Path too deep"));
+ }
if (!jv_is_valid(root)) {
jv_free(path);
return root;
@@ -423,6 +438,12 @@ jv jv_delpaths(jv object, jv paths) {
jv_free(elem);
return err;
}
+ if (jv_array_length(jv_copy(elem)) > MAX_PATH_DEPTH) {
+ jv_free(object);
+ jv_free(paths);
+ jv_free(elem);
+ return jv_invalid_with_msg(jv_string("Path too deep"));
+ }
jv_free(elem);
}
if (jv_array_length(jv_copy(paths)) == 0) {
diff --git a/tests/jq.test b/tests/jq.test
index 06c39f0..a948d81 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -1512,6 +1512,31 @@ isempty(empty)
null
true

+# regression test for CVE-2026-33947
+setpath([range(10000) | 0]; 0) | flatten
+null
+[0]
+
+try setpath([range(10001) | 0]; 0) catch .
+null
+"Path too deep"
+
+getpath([range(10000) | 0])
+null
+null
+
+try getpath([range(10001) | 0]) catch .
+null
+"Path too deep"
+
+delpaths([[range(10000) | 0]])
+null
+null
+
+try delpaths([[range(10001) | 0]]) catch .
+null
+"Path too deep"
+
isempty(range(3))
null
false
--
2.45.4

51 changes: 51 additions & 0 deletions SPECS/jq/CVE-2026-33948.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
From 765c0cd2087dee2ae1c964213fbb75cbaf533eac Mon Sep 17 00:00:00 2001
From: itchyny <itchyny@cybozu.co.jp>
Date: Mon, 13 Apr 2026 08:46:11 +0900
Subject: [PATCH] Fix NUL truncation in the JSON parser

This fixes CVE-2026-33948.

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/jqlang/jq/commit/6374ae0bcdfe33a18eb0ae6db28493b1f34a0a5b.patch
---
src/util.c | 8 +-------
tests/shtest | 6 ++++++
2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/util.c b/src/util.c
index df83952..cd21a43 100644
--- a/src/util.c
+++ b/src/util.c
@@ -324,13 +324,7 @@ static int jq_util_input_read_more(jq_util_input_state *state) {
if (p != NULL)
state->current_line++;

- if (p == NULL && state->parser != NULL) {
- /*
- * There should be no NULs in JSON texts (but JSON text
- * sequences are another story).
- */
- state->buf_valid_len = strlen(state->buf);
- } else if (p == NULL && feof(state->current_input)) {
+ if (p == NULL && feof(state->current_input)) {
size_t i;

/*
diff --git a/tests/shtest b/tests/shtest
index 86fec33..804607f 100755
--- a/tests/shtest
+++ b/tests/shtest
@@ -306,4 +306,10 @@ JQ_COLORS="0123456789123:0123456789123:0123456789123:0123456789123:0123456789123
cmp $d/color $d/expect
cmp $d/warning $d/expect_warning

+# CVE-2026-33948: No NUL truncation in the JSON parser
+if printf '{}\x00{}' | $JQ >/dev/null 2> /dev/null; then
+ printf 'Error expected but jq exited successfully\n' 1>&2
+ exit 1
+fi
+
exit 0
--
2.45.4

35 changes: 35 additions & 0 deletions SPECS/jq/CVE-2026-39956.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
From b06fc1bc1e07c9c8d684195d3f35ad6950e8d2d0 Mon Sep 17 00:00:00 2001
From: tlsbollei <170938166+tlsbollei@users.noreply.github.com>
Date: Wed, 8 Apr 2026 21:43:46 +0200
Subject: [PATCH] Add runtime type checks to f_string_indexes

This fixes CVE-2026-39956.

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/jqlang/jq/commit/fdf8ef0f0810e3d365cdd5160de43db46f57ed03.patch
---
src/builtin.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/src/builtin.c b/src/builtin.c
index c6c8c2e..c03cae0 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1123,6 +1123,14 @@ static jv f_string_explode(jq_state *jq, jv a) {
}

static jv f_string_indexes(jq_state *jq, jv a, jv b) {
+ if (jv_get_kind(a) != JV_KIND_STRING) {
+ jv_free(b);
+ return type_error(a, "cannot be searched, as it is not a string");
+ }
+ if (jv_get_kind(b) != JV_KIND_STRING) {
+ jv_free(a);
+ return type_error(b, "is not a string");
+ }
return jv_string_indexes(a, b);
}

--
2.45.4

32 changes: 32 additions & 0 deletions SPECS/jq/CVE-2026-39979.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
From c0cbbd16af052f0517f76ec5478c0309f1b91259 Mon Sep 17 00:00:00 2001
From: itchyny <itchyny@cybozu.co.jp>
Date: Mon, 13 Apr 2026 11:04:52 +0900
Subject: [PATCH] Fix out-of-bounds read in jv_parse_sized()

This fixes CVE-2026-39979.

Co-authored-by: Mattias Wadman <mattias.wadman@gmail.com>
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/jqlang/jq/commit/2f09060afab23fe9390cce7cb860b10416e1bf5f.patch
---
src/jv_parse.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/jv_parse.c b/src/jv_parse.c
index 51ad9f0..5f97840 100644
--- a/src/jv_parse.c
+++ b/src/jv_parse.c
@@ -845,8 +845,9 @@ jv jv_parse_sized(const char* string, int length) {

if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) {
jv msg = jv_invalid_get_msg(value);
- value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')",
+ value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%.*s')",
jv_string_value(msg),
+ length,
string));
jv_free(msg);
}
--
2.45.4

92 changes: 92 additions & 0 deletions SPECS/jq/CVE-2026-40164.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
From 76357b5d2daec74a0ad811313124c630ad80c41b Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Fri, 24 Apr 2026 01:03:20 +0000
Subject: [PATCH] Randomize hash seed to mitigate hash collision DoS attacks
(backport). Initialize hash seed from strong entropy sources or fallback to
time/pid and use pthread_once to init. Add configure checks for
arc4random/getentropy.

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport of https://github.com/jqlang/jq/commit/0c7d133c3c7e37c00b6d46b658a02244fdd3c784.patch
---
configure.ac | 3 +++
src/jv.c | 35 +++++++++++++++++++++++++++++++++--
2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 9e9d6d8..f5c84c6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,6 +132,9 @@ AC_CHECK_MEMBER([struct tm.tm_gmtoff], [AC_DEFINE([HAVE_TM_TM_GMT_OFF],1,[Define
AC_CHECK_MEMBER([struct tm.__tm_gmtoff], [AC_DEFINE([HAVE_TM___TM_GMT_OFF],1,[Define to 1 if the system has the __tm_gmt_off field in struct tm])],
[], [[#include <time.h>]])

+AC_FIND_FUNC([arc4random], [c], [#include <stdlib.h>], [])
+AC_FIND_FUNC([getentropy], [c], [#include <unistd.h>], [0, 0])
+
AC_ARG_ENABLE([pthread-tls],
[AC_HELP_STRING([--enable-pthread-tls],
[Enable use of pthread thread local storage])],
diff --git a/src/jv.c b/src/jv.c
index 8b4afad..d452199 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -7,6 +7,11 @@
#include <stdarg.h>
#include <limits.h>
#include <math.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+

#include "jv_alloc.h"
#include "jv.h"
@@ -556,7 +561,33 @@ static jv jvp_string_append(jv string, const char* data, uint32_t len) {
}
}

-static const uint32_t HASH_SEED = 0x432A9843;
+static uint32_t hash_seed;
+static pthread_once_t hash_seed_once = PTHREAD_ONCE_INIT;
+
+static void jvp_hash_seed_init(void) {
+ uint32_t seed;
+#if defined(HAVE_ARC4RANDOM)
+ seed = arc4random();
+#elif defined(HAVE_GETENTROPY)
+ if (getentropy(&seed, sizeof(seed)) != 0)
+ seed = (uint32_t)getpid() ^ (uint32_t)time(NULL);
+#else
+ int fd = open("/dev/urandom", O_RDONLY);
+ if (fd >= 0) {
+ if (read(fd, &seed, sizeof(seed)) != 4)
+ seed = (uint32_t)getpid() ^ (uint32_t)time(NULL);
+ close(fd);
+ } else {
+ seed = (uint32_t)getpid() ^ (uint32_t)time(NULL);
+ }
+#endif
+ hash_seed = seed;
+}
+
+static uint32_t jvp_hash_seed(void) {
+ pthread_once(&hash_seed_once, jvp_hash_seed_init);
+ return hash_seed;
+}

static uint32_t rotl32 (uint32_t x, int8_t r){
return (x << r) | (x >> (32 - r));
@@ -575,7 +606,7 @@ static uint32_t jvp_string_hash(jv jstr) {
int len = (int)jvp_string_length(str);
const int nblocks = len / 4;

- uint32_t h1 = HASH_SEED;
+ uint32_t h1 = jvp_hash_seed();

const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
--
2.45.4

Loading
Loading