mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-07-06 17:13:24 -05:00
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:
parent
6f7e3c1dec
commit
ecae36f172
7 changed files with 3 additions and 316 deletions
|
|
@ -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) {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue