Skip to content

Commit e996e72

Browse files
[AutoPR- Security] Patch jq for CVE-2026-43896, CVE-2026-43895, CVE-2026-41257, CVE-2026-41256, CVE-2026-40612, CVE-2026-44777 [MEDIUM] (#17162)
Co-authored-by: akhila-guruju <v-guakhila@microsoft.com>
1 parent 89086ae commit e996e72

7 files changed

Lines changed: 732 additions & 2 deletions

File tree

SPECS/jq/CVE-2026-40612.patch

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
From d1a12569d91641135976a8536776a4a329c02cc2 Mon Sep 17 00:00:00 2001
2+
From: itchyny <itchyny@cybozu.co.jp>
3+
Date: Fri, 24 Apr 2026 22:02:24 +0900
4+
Subject: [PATCH] Limit the containment check depth
5+
6+
This fixes CVE-2026-40612.
7+
8+
Modified to apply to Azure Linux.
9+
Added extra closed brackets `()` after try in jq.test file to avoid syntax errors caused due to version differences.
10+
11+
Upstream Patch reference: https://github.com/jqlang/jq/commit/d1a12569d91641135976a8536776a4a329c02cc2.patch
12+
---
13+
src/builtin.c | 5 ++++-
14+
src/jv.c | 40 +++++++++++++++++++++++++++-------------
15+
tests/jq.test | 9 +++++++++
16+
3 files changed, 40 insertions(+), 14 deletions(-)
17+
18+
diff --git a/src/builtin.c b/src/builtin.c
19+
index 3cb8eb7..08b94ac 100644
20+
--- a/src/builtin.c
21+
+++ b/src/builtin.c
22+
@@ -471,7 +471,10 @@ jv binop_greatereq(jv a, jv b) {
23+
24+
static jv f_contains(jq_state *jq, jv a, jv b) {
25+
if (jv_get_kind(a) == jv_get_kind(b)) {
26+
- return jv_bool(jv_contains(a, b));
27+
+ int r = jv_contains(a, b);
28+
+ if (r < 0)
29+
+ return jv_invalid_with_msg(jv_string("Containment check too deep"));
30+
+ return jv_bool(r);
31+
} else {
32+
return type_error2(a, b, "cannot have their containment checked");
33+
}
34+
diff --git a/src/jv.c b/src/jv.c
35+
index 08ded35..5a2c3a2 100644
36+
--- a/src/jv.c
37+
+++ b/src/jv.c
38+
@@ -914,19 +914,19 @@ static void jvp_clamp_slice_params(int len, int *pstart, int *pend)
39+
}
40+
41+
42+
-static int jvp_array_contains(jv a, jv b) {
43+
+static int jvp_contains(jv a, jv b, int depth);
44+
+
45+
+static int jvp_array_contains(jv a, jv b, int depth) {
46+
int r = 1;
47+
jv_array_foreach(b, bi, belem) {
48+
int ri = 0;
49+
jv_array_foreach(a, ai, aelem) {
50+
- if (jv_contains(aelem, jv_copy(belem))) {
51+
- ri = 1;
52+
- break;
53+
- }
54+
+ ri = jvp_contains(aelem, jv_copy(belem), depth);
55+
+ if (ri) break;
56+
}
57+
jv_free(belem);
58+
- if (!ri) {
59+
- r = 0;
60+
+ if (ri <= 0) {
61+
+ r = ri;
62+
break;
63+
}
64+
}
65+
@@ -1794,7 +1794,7 @@ static int jvp_object_equal(jv o1, jv o2) {
66+
return len1 == len2;
67+
}
68+
69+
-static int jvp_object_contains(jv a, jv b) {
70+
+static int jvp_object_contains(jv a, jv b, int depth) {
71+
assert(JVP_HAS_KIND(a, JV_KIND_OBJECT));
72+
assert(JVP_HAS_KIND(b, JV_KIND_OBJECT));
73+
int r = 1;
74+
@@ -1802,9 +1802,9 @@ static int jvp_object_contains(jv a, jv b) {
75+
jv_object_foreach(b, key, b_val) {
76+
jv a_val = jv_object_get(jv_copy(a), key);
77+
78+
- r = jv_contains(a_val, b_val);
79+
+ r = jvp_contains(a_val, b_val, depth);
80+
81+
- if (!r) break;
82+
+ if (r <= 0) break;
83+
}
84+
return r;
85+
}
86+
@@ -2035,14 +2035,23 @@ int jv_identical(jv a, jv b) {
87+
return r;
88+
}
89+
90+
-int jv_contains(jv a, jv b) {
91+
+#ifndef MAX_CONTAINS_DEPTH
92+
+#define MAX_CONTAINS_DEPTH (10000)
93+
+#endif
94+
+
95+
+static int jvp_contains(jv a, jv b, int depth) {
96+
+ if (depth > MAX_CONTAINS_DEPTH) {
97+
+ jv_free(a);
98+
+ jv_free(b);
99+
+ return -1;
100+
+ }
101+
int r = 1;
102+
if (jv_get_kind(a) != jv_get_kind(b)) {
103+
r = 0;
104+
} else if (JVP_HAS_KIND(a, JV_KIND_OBJECT)) {
105+
- r = jvp_object_contains(a, b);
106+
+ r = jvp_object_contains(a, b, depth + 1);
107+
} else if (JVP_HAS_KIND(a, JV_KIND_ARRAY)) {
108+
- r = jvp_array_contains(a, b);
109+
+ r = jvp_array_contains(a, b, depth + 1);
110+
} else if (JVP_HAS_KIND(a, JV_KIND_STRING)) {
111+
int b_len = jv_string_length_bytes(jv_copy(b));
112+
if (b_len != 0) {
113+
@@ -2058,3 +2067,8 @@ int jv_contains(jv a, jv b) {
114+
jv_free(b);
115+
return r;
116+
}
117+
+
118+
+// Returns 1 (contained), 0 (not contained), or -1 (too deep)
119+
+int jv_contains(jv a, jv b) {
120+
+ return jvp_contains(a, b, 0);
121+
+}
122+
diff --git a/tests/jq.test b/tests/jq.test
123+
index 758a161..0516ff1 100644
124+
--- a/tests/jq.test
125+
+++ b/tests/jq.test
126+
@@ -2155,3 +2155,12 @@ try ltrimstr("x") catch "x", try rtrimstr("x") catch "x" | "ok"
127+
{"hey":[]}
128+
"ok"
129+
"ok"
130+
+
131+
+# regression test for CVE-2026-40612
132+
+reduce range(10000) as $_ ([]; [.]) | contains([[]])
133+
+null
134+
+true
135+
+
136+
+try ((reduce range(10001) as $_ ([]; [.])) as $x | $x | contains($x)) catch .
137+
+null
138+
+"Containment check too deep"
139+
--
140+
2.43.0
141+

SPECS/jq/CVE-2026-41256.patch

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
From 7c0f40aeaf45d56956b18ef1e2f485873e69ac7f Mon Sep 17 00:00:00 2001
2+
From: itchyny <itchyny@cybozu.co.jp>
3+
Date: Fri, 24 Apr 2026 22:15:08 +0900
4+
Subject: [PATCH] Fix NUL truncation in program files loaded with -f
5+
6+
This fixes CVE-2026-41256.
7+
8+
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
9+
Upstream-reference: https://github.com/jqlang/jq/commit/5a015deae35d19e3ebbc65db6c157a80e76df738.patch
10+
---
11+
src/main.c | 8 ++++++++
12+
tests/shtest | 7 +++++++
13+
2 files changed, 15 insertions(+)
14+
15+
diff --git a/src/main.c b/src/main.c
16+
index 43586c4..f462e4d 100644
17+
--- a/src/main.c
18+
+++ b/src/main.c
19+
@@ -677,6 +677,14 @@ int main(int argc, char* argv[]) {
20+
ret = JQ_ERROR_SYSTEM;
21+
goto out;
22+
}
23+
+ int len = jv_string_length_bytes(jv_copy(data));
24+
+ if ((size_t)len != strlen(jv_string_value(data))) {
25+
+ fprintf(stderr, "jq: program file contains NUL bytes\n");
26+
+ free(program_origin);
27+
+ jv_free(data);
28+
+ ret = JQ_ERROR_SYSTEM;
29+
+ goto out;
30+
+ }
31+
jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(program_origin))));
32+
ARGS = JV_OBJECT(jv_string("positional"), ARGS,
33+
jv_string("named"), jv_copy(program_arguments));
34+
diff --git a/tests/shtest b/tests/shtest
35+
index 0397ca0..505d45d 100755
36+
--- a/tests/shtest
37+
+++ b/tests/shtest
38+
@@ -615,4 +615,11 @@ if printf '{}\x00{}' | $JQ >/dev/null 2> /dev/null; then
39+
exit 1
40+
fi
41+
42+
+# CVE-2026-41256: No NUL truncation in program files loaded with -f
43+
+printf '.\x00invalid' > "$d/nul_prog.jq"
44+
+if echo '42' | $JQ -f "$d/nul_prog.jq" >/dev/null 2>/dev/null; then
45+
+ printf 'Error expected for program file with NUL bytes\n' 1>&2
46+
+ exit 1
47+
+fi
48+
+
49+
exit 0
50+
--
51+
2.45.4
52+

SPECS/jq/CVE-2026-41257.patch

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
From 59ff1987e1d364e418984eb46943a53c3e7606b5 Mon Sep 17 00:00:00 2001
2+
From: itchyny <itchyny@cybozu.co.jp>
3+
Date: Fri, 24 Apr 2026 22:09:44 +0900
4+
Subject: [PATCH] Fix signed-int overflow in `stack_reallocate`
5+
6+
This fixes CVE-2026-41257.
7+
8+
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
9+
Upstream-reference: https://github.com/jqlang/jq/commit/01b3cded76daacbfddb7f8763700b0803bcb5c6f.patch
10+
---
11+
src/exec_stack.h | 14 ++++++++++----
12+
1 file changed, 10 insertions(+), 4 deletions(-)
13+
14+
diff --git a/src/exec_stack.h b/src/exec_stack.h
15+
index 2a063e8..159c56e 100644
16+
--- a/src/exec_stack.h
17+
+++ b/src/exec_stack.h
18+
@@ -2,8 +2,10 @@
19+
#define EXEC_STACK_H
20+
#include <stddef.h>
21+
#include <stdint.h>
22+
+#include <stdio.h>
23+
#include <stdlib.h>
24+
#include <string.h>
25+
+#include <limits.h>
26+
#include "jv_alloc.h"
27+
28+
/*
29+
@@ -81,15 +83,19 @@ static stack_ptr* stack_block_next(struct stack* s, stack_ptr p) {
30+
}
31+
32+
static void stack_reallocate(struct stack* s, size_t sz) {
33+
- int old_mem_length = -(s->bound) + ALIGNMENT;
34+
- char* old_mem_start = (s->mem_end != NULL) ? (s->mem_end - old_mem_length) : NULL;
35+
+ size_t old_mem_length = (size_t)(-(s->bound)) + ALIGNMENT;
36+
+ char* old_mem_start = s->mem_end != NULL ? s->mem_end - old_mem_length : NULL;
37+
38+
- int new_mem_length = align_round_up((old_mem_length + sz + 256) * 2);
39+
+ size_t new_mem_length = align_round_up((old_mem_length + sz + 256) * 2);
40+
+ if (new_mem_length > INT_MAX) {
41+
+ fprintf(stderr, "jq: error: cannot allocate memory\n");
42+
+ abort();
43+
+ }
44+
char* new_mem_start = jv_mem_realloc(old_mem_start, new_mem_length);
45+
memmove(new_mem_start + (new_mem_length - old_mem_length),
46+
new_mem_start, old_mem_length);
47+
s->mem_end = new_mem_start + new_mem_length;
48+
- s->bound = -(new_mem_length - ALIGNMENT);
49+
+ s->bound = -(int)(new_mem_length - ALIGNMENT);
50+
}
51+
52+
static stack_ptr stack_push_block(struct stack* s, stack_ptr p, size_t sz) {
53+
--
54+
2.45.4
55+

0 commit comments

Comments
 (0)