Skip to content
Draft
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 5d4fc05e1c5a2afe071c436e3855ba4f73021344 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 18dbb54..73387d8 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -1091,7 +1091,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;
@@ -1151,6 +1156,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 f14d38d366fd96f56ca2df39d1efc6f32e3f8047 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 bbe1c0d..0855053 100644
--- a/src/jv_aux.c
+++ b/src/jv_aux.c
@@ -376,6 +376,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);
@@ -383,6 +387,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);
@@ -434,6 +444,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;
@@ -511,6 +526,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 500e741..758a161 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -1813,6 +1813,31 @@ all(builtins[] / "/"; .[1]|tonumber >= 0)
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"
+
builtins|any(.[:1] == "_")
null
false
--
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 74d82edd79f8c00f9893fe520fd904b9508c5472 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 902490d..3cb8eb7 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1212,6 +1212,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 5c02ceb537503e731c1666ef959f57fe003605de 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 9755b8a..84a847f 100644
--- a/src/jv_parse.c
+++ b/src/jv_parse.c
@@ -890,8 +890,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);
}
--
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 a52ccfea9038c9e1d22d3d083273a564b7e09b1e 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>
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/jqlang/jq/commit/0c7d133c3c7e37c00b6d46b658a02244fdd3c784.patch
---
configure.ac | 2 ++
src/jv.c | 34 ++++++++++++++++++++++++++++++++--
2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 118e084..7f12b52 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 73387d8..08ded35 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"
@@ -1183,7 +1187,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));
@@ -1202,7 +1232,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

10 changes: 9 additions & 1 deletion SPECS/jq/jq.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Summary: jq is a lightweight and flexible command-line JSON processor.
Name: jq
Version: 1.7.1
Release: 4%{?dist}
Release: 5%{?dist}
Group: Applications/System
Vendor: Microsoft Corporation
License: MIT
Expand All @@ -10,6 +10,11 @@ Source0: https://github.com/jqlang/jq/releases/download/%{name}-%{version
Patch0: CVE-2024-53427.patch
Patch1: CVE-2024-23337.patch
Patch2: CVE-2025-48060.patch
Patch3: CVE-2026-32316.patch
Patch4: CVE-2026-33947.patch
Patch5: CVE-2026-39956.patch
Patch6: CVE-2026-39979.patch
Patch7: CVE-2026-40164.patch
Distribution: Azure Linux
BuildRequires: bison
BuildRequires: chrpath
Expand Down Expand Up @@ -63,6 +68,9 @@ make check
%{_includedir}/*

%changelog
* Fri Apr 17 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 1.7.1-5
- Patch for CVE-2026-40164, CVE-2026-39979, CVE-2026-39956, CVE-2026-33947, CVE-2026-32316

* Wed Jul 23 2025 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 1.7.1-4
- Patch for CVE-2025-48060
- Updated files section to fix duplicated license files
Expand Down
Loading