jq: 1.8.1 -> 1.8.2

Changelogs: https://github.com/jqlang/jq/releases/tag/jq-1.8.2
Should be backported (22 CVEs)
This commit is contained in:
Bart Oostveen 2026-06-21 00:41:07 +02:00
commit ecae36f172
No known key found for this signature in database
GPG key ID: 992D94B57AC43430
7 changed files with 3 additions and 316 deletions

View file

@ -1,49 +0,0 @@
From e47e56d226519635768e6aab2f38f0ab037c09e5 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.
---
src/jv.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/jv.c b/src/jv.c
index 722a539391..2a62b48419 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -1114,7 +1114,12 @@ static jv jvp_string_copy_replace_bad(const char* data, uint32_t length) {
const char* end = data + length;
const char* i = data;
- 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;
@@ -1174,6 +1179,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) {

View file

@ -1,66 +0,0 @@
From fb59f1491058d58bdc3e8dd28f1773d1ac690a1f 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.
---
src/jv_aux.c | 21 +++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/src/jv_aux.c b/src/jv_aux.c
index 018f380b10..fd5ff96684 100644
--- a/src/jv_aux.c
+++ b/src/jv_aux.c
@@ -365,6 +365,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);
@@ -372,6 +376,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);
@@ -424,6 +434,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;
@@ -502,6 +517,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) {

View file

@ -1,45 +0,0 @@
From 6374ae0bcdfe33a18eb0ae6db28493b1f34a0a5b 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.
---
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 fdfdb96d88..80d65fc808 100644
--- a/src/util.c
+++ b/src/util.c
@@ -312,13 +312,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 cb88745277..370f7b7c69 100755
--- a/tests/shtest
+++ b/tests/shtest
@@ -880,4 +880,10 @@ $JQ -nf $d/prog.jq 2> $d/out && {
}
diff $d/out $d/expected
+# 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

View file

@ -1,27 +0,0 @@
From 2f09060afab23fe9390cce7cb860b10416e1bf5f 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>
---
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 aa2054cc09..56847b5eaa 100644
--- a/src/jv_parse.c
+++ b/src/jv_parse.c
@@ -893,8 +893,9 @@ jv jv_parse_sized_custom_flags(const char* string, int length, int flags) {
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);
}

View file

@ -1,87 +0,0 @@
From 0c7d133c3c7e37c00b6d46b658a02244fdd3c784 Mon Sep 17 00:00:00 2001
From: itchyny <itchyny@cybozu.co.jp>
Date: Mon, 13 Apr 2026 08:53:26 +0900
Subject: [PATCH] Randomize hash seed to mitigate hash collision DoS attacks
The hash function used a fixed seed, allowing attackers to craft colliding keys
and cause O(n^2) object parsing performance. Initialize the seed from a random
source at process startup to prevent the attack. This fixes CVE-2026-40164.
Co-authored-by: Asaf Meizner <asafmeizner@gmail.com>
---
configure.ac | 2 ++
src/jv.c | 34 ++++++++++++++++++++++++++++++++--
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5dac42655a..f7067a4341 100644
--- a/configure.ac
+++ b/configure.ac
@@ -149,6 +149,8 @@ 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([setlocale], [c], [#include <locale.h>], [0,0])
+AC_FIND_FUNC([arc4random], [c], [#include <stdlib.h>], [])
+AC_FIND_FUNC([getentropy], [c], [#include <unistd.h>], [0, 0])
dnl Figure out if we have the pthread functions we actually need
AC_FIND_FUNC_NO_LIBS([pthread_key_create], [], [#include <pthread.h>], [NULL, NULL])
diff --git a/src/jv.c b/src/jv.c
index 2a62b48419..607ac174f7 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -40,6 +40,10 @@
#include <limits.h>
#include <math.h>
#include <float.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
#include "jv_alloc.h"
#include "jv.h"
@@ -1206,7 +1210,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));
@@ -1225,7 +1255,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;

View file

@ -1,31 +0,0 @@
From 63e9449a8142ce30c83fcd7e9396e5de9843774e Mon Sep 17 00:00:00 2001
From: Alyssa Ross <hi@alyssa.is>
Date: Thu, 3 Jul 2025 11:00:13 +0200
Subject: [PATCH] jq.test: drop non-portable %F test
%F is a non-portable GNU extension, not supported by all strptime
implementations (for example musl's).
Link: https://github.com/jqlang/jq/pull/3365
---
tests/jq.test | 4 ----
1 file changed, 4 deletions(-)
diff --git a/tests/jq.test b/tests/jq.test
index 4ecf72f..6bfb6f8 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -1848,10 +1848,6 @@ try ["OK", strflocaltime({})] catch ["KO", .]
"2015-03-05T23:51:47Z"
[[2015,2,5,23,51,47,4,63],1425599507]
-[strptime("%FT%T")|(.,mktime)]
-"2025-06-07T08:09:10"
-[[2025,5,7,8,9,10,6,157],1749283750]
-
# Check day-of-week and day of year computations
# (should trip an assert if this fails)
last(range(365 * 67)|("1970-03-01T01:02:03Z"|strptime("%Y-%m-%dT%H:%M:%SZ")|mktime) + (86400 * .)|strftime("%Y-%m-%dT%H:%M:%SZ")|strptime("%Y-%m-%dT%H:%M:%SZ"))
--
2.49.0

View file

@ -14,12 +14,12 @@
stdenv.mkDerivation (finalAttrs: {
pname = "jq";
version = "1.8.1";
version = "1.8.2";
# Note: do not use fetchpatch or fetchFromGitHub to keep this package available in __bootPackages
src = fetchurl {
url = "https://github.com/jqlang/jq/releases/download/jq-${finalAttrs.version}/jq-${finalAttrs.version}.tar.gz";
hash = "sha256-K+ZOcSnOyxHVkGKQ66EK9pT7nj5/n8IIoxHcM8qDfrA=";
hash = "sha256-cbjW6PX+gfbG0NEQ44kiUfbOdu0JWr0xXibm4Rk6868=";
};
outputs = [
@ -30,15 +30,7 @@ stdenv.mkDerivation (finalAttrs: {
"out"
];
patches = [
./musl.patch
./CVE-2026-32316.patch
./CVE-2026-33947.patch
./CVE-2026-33948.patch
./CVE-2026-39979.patch
./CVE-2026-40164.patch
]
++ lib.optionals stdenv.hostPlatform.is32bit [
patches = lib.optionals stdenv.hostPlatform.is32bit [
# needed because epoch conversion test here is right at the end of 32 bit integer space
# See also: https://github.com/jqlang/jq/blob/859a8073ee8a21f2133154eea7c2bd5e0d60837f/tests/optional.test#L15-L18
# "-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64" would be preferrable, but breaks with dynamic linking,