mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-08-30 00:33:19 +00:00
jq: Fix CVE-2026-43895
This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jqlang/jq/commit/9d223f153c3632a207fa071caaa6292da33ae361 [2] https://github.com/jqlang/jq/security/advisories/GHSA-7q7g-mrq3-phxr Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
committed by
Anuj Mittal
parent
30eaef2541
commit
da15df26e6
@@ -0,0 +1,206 @@
|
||||
From 5192a59c2c6ca6ab0667cbee608db29c0710f346 Mon Sep 17 00:00:00 2001
|
||||
From: itchyny <itchyny@cybozu.co.jp>
|
||||
Date: Sat, 9 May 2026 17:08:43 +0900
|
||||
Subject: [PATCH 1/2] Reject embedded NUL bytes in module import paths
|
||||
|
||||
jq accepts embedded NUL bytes at the language level but resolves
|
||||
module import paths through NUL-terminated C strings, so the path
|
||||
validated by policy or audit code could differ from the on-disk
|
||||
path jq actually opens. Pass jv through gen_import so the AST
|
||||
preserves the original bytes, and reject embedded NULs in
|
||||
validate_relpath.
|
||||
|
||||
Fixes CVE-2026-43895.
|
||||
|
||||
CVE: CVE-2026-43895
|
||||
Upstream-Status: Backport [https://github.com/jqlang/jq/commit/9d223f153c3632a207fa071caaa6292da33ae361]
|
||||
|
||||
Backport Changes:
|
||||
- Kept jq 1.7.1 HOME lookup in linker.c.
|
||||
The newer get_home() flow is absent from the target.
|
||||
Only the jv-based gen_import() call was required.
|
||||
- Limited parser.c to three import/include action changes.
|
||||
The newer grammar caused unrelated generated-parser churn.
|
||||
Keeping target numbering avoids unrelated generated changes.
|
||||
|
||||
(cherry picked from commit 9d223f153c3632a207fa071caaa6292da33ae361)
|
||||
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
|
||||
---
|
||||
src/compile.c | 12 ++++++++----
|
||||
src/compile.h | 2 +-
|
||||
src/linker.c | 6 +++++-
|
||||
src/parser.c | 16 +++-------------
|
||||
src/parser.y | 16 +++-------------
|
||||
tests/shtest | 17 +++++++++++++++++
|
||||
6 files changed, 37 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/src/compile.c b/src/compile.c
|
||||
index e5e65f2..27b2cfd 100644
|
||||
--- a/src/compile.c
|
||||
+++ b/src/compile.c
|
||||
@@ -526,13 +526,17 @@ jv block_module_meta(block b) {
|
||||
return jv_null();
|
||||
}
|
||||
|
||||
-block gen_import(const char* name, const char* as, int is_data) {
|
||||
+block gen_import(jv name, jv as, int is_data) {
|
||||
+ assert(jv_get_kind(name) == JV_KIND_STRING);
|
||||
+ assert(!jv_is_valid(as) || jv_get_kind(as) == JV_KIND_STRING);
|
||||
inst* i = inst_new(DEPS);
|
||||
jv meta = jv_object();
|
||||
- if (as != NULL)
|
||||
- meta = jv_object_set(meta, jv_string("as"), jv_string(as));
|
||||
+ if (jv_is_valid(as))
|
||||
+ meta = jv_object_set(meta, jv_string("as"), as);
|
||||
+ else
|
||||
+ jv_free(as);
|
||||
meta = jv_object_set(meta, jv_string("is_data"), is_data ? jv_true() : jv_false());
|
||||
- meta = jv_object_set(meta, jv_string("relpath"), jv_string(name));
|
||||
+ meta = jv_object_set(meta, jv_string("relpath"), name);
|
||||
i->imm.constant = meta;
|
||||
return inst_block(i);
|
||||
}
|
||||
diff --git a/src/compile.h b/src/compile.h
|
||||
index c1512e6..bac65ef 100644
|
||||
--- a/src/compile.h
|
||||
+++ b/src/compile.h
|
||||
@@ -33,7 +33,7 @@ block gen_op_pushk_under(jv constant);
|
||||
|
||||
block gen_module(block metadata);
|
||||
jv block_module_meta(block b);
|
||||
-block gen_import(const char* name, const char *as, int is_data);
|
||||
+block gen_import(jv name, jv as, int is_data);
|
||||
block gen_import_meta(block import, block metadata);
|
||||
block gen_function(const char* name, block formals, block body);
|
||||
block gen_param_regular(const char* name);
|
||||
diff --git a/src/linker.c b/src/linker.c
|
||||
index e7d1024..4b15008 100644
|
||||
--- a/src/linker.c
|
||||
+++ b/src/linker.c
|
||||
@@ -93,6 +93,10 @@ static jv build_lib_search_chain(jq_state *jq, jv search_path, jv jq_origin, jv
|
||||
// in between).
|
||||
static jv validate_relpath(jv name) {
|
||||
const char *s = jv_string_value(name);
|
||||
+ if (strlen(s) != (size_t)jv_string_length_bytes(jv_copy(name))) {
|
||||
+ jv_free(name);
|
||||
+ return jv_invalid_with_msg(jv_string("Module path contains a NUL byte"));
|
||||
+ }
|
||||
if (strchr(s, '\\')) {
|
||||
jv res = jv_invalid_with_msg(jv_string_fmt("Modules must be named by relative paths using '/', not '\\' (%s)", s));
|
||||
jv_free(name);
|
||||
@@ -423,7 +427,7 @@ int load_program(jq_state *jq, struct locfile* src, block *out_block) {
|
||||
char* home = getenv("HOME");
|
||||
if (home) { // silently ignore no $HOME
|
||||
/* Import ~/.jq as a library named "" found in $HOME */
|
||||
- block import = gen_import_meta(gen_import("", NULL, 0),
|
||||
+ block import = gen_import_meta(gen_import(jv_string(""), jv_invalid(), 0),
|
||||
gen_const(JV_OBJECT(
|
||||
jv_string("optional"), jv_true(),
|
||||
jv_string("search"), jv_string(home))));
|
||||
diff --git a/src/parser.c b/src/parser.c
|
||||
index 0599db7..c50f2fb 100644
|
||||
--- a/src/parser.c
|
||||
+++ b/src/parser.c
|
||||
@@ -3081,13 +3081,8 @@ yyreduce:
|
||||
case 50: /* ImportWhat: "import" ImportFrom "as" BINDING */
|
||||
#line 506 "src/parser.y"
|
||||
{
|
||||
- jv v = block_const((yyvsp[-2].blk));
|
||||
- // XXX Make gen_import take only blocks and the int is_data so we
|
||||
- // don't have to free so much stuff here
|
||||
- (yyval.blk) = gen_import(jv_string_value(v), jv_string_value((yyvsp[0].literal)), 1);
|
||||
+ (yyval.blk) = gen_import(block_const((yyvsp[-2].blk)), (yyvsp[0].literal), 1);
|
||||
block_free((yyvsp[-2].blk));
|
||||
- jv_free((yyvsp[0].literal));
|
||||
- jv_free(v);
|
||||
}
|
||||
#line 3093 "src/parser.c"
|
||||
break;
|
||||
@@ -3095,11 +3090,8 @@ yyreduce:
|
||||
case 51: /* ImportWhat: "import" ImportFrom "as" IDENT */
|
||||
#line 515 "src/parser.y"
|
||||
{
|
||||
- jv v = block_const((yyvsp[-2].blk));
|
||||
- (yyval.blk) = gen_import(jv_string_value(v), jv_string_value((yyvsp[0].literal)), 0);
|
||||
+ (yyval.blk) = gen_import(block_const((yyvsp[-2].blk)), (yyvsp[0].literal), 0);
|
||||
block_free((yyvsp[-2].blk));
|
||||
- jv_free((yyvsp[0].literal));
|
||||
- jv_free(v);
|
||||
}
|
||||
#line 3105 "src/parser.c"
|
||||
break;
|
||||
@@ -3107,10 +3099,8 @@ yyreduce:
|
||||
case 52: /* ImportWhat: "include" ImportFrom */
|
||||
#line 522 "src/parser.y"
|
||||
{
|
||||
- jv v = block_const((yyvsp[0].blk));
|
||||
- (yyval.blk) = gen_import(jv_string_value(v), NULL, 0);
|
||||
+ (yyval.blk) = gen_import(block_const((yyvsp[0].blk)), jv_invalid(), 0);
|
||||
block_free((yyvsp[0].blk));
|
||||
- jv_free(v);
|
||||
}
|
||||
#line 3116 "src/parser.c"
|
||||
break;
|
||||
diff --git a/src/parser.y b/src/parser.y
|
||||
index 3d24689..2901cab 100644
|
||||
--- a/src/parser.y
|
||||
+++ b/src/parser.y
|
||||
@@ -504,26 +504,16 @@ ImportWhat Exp ';' {
|
||||
|
||||
ImportWhat:
|
||||
"import" ImportFrom "as" BINDING {
|
||||
- jv v = block_const($2);
|
||||
- // XXX Make gen_import take only blocks and the int is_data so we
|
||||
- // don't have to free so much stuff here
|
||||
- $$ = gen_import(jv_string_value(v), jv_string_value($4), 1);
|
||||
+ $$ = gen_import(block_const($2), $4, 1);
|
||||
block_free($2);
|
||||
- jv_free($4);
|
||||
- jv_free(v);
|
||||
} |
|
||||
"import" ImportFrom "as" IDENT {
|
||||
- jv v = block_const($2);
|
||||
- $$ = gen_import(jv_string_value(v), jv_string_value($4), 0);
|
||||
+ $$ = gen_import(block_const($2), $4, 0);
|
||||
block_free($2);
|
||||
- jv_free($4);
|
||||
- jv_free(v);
|
||||
} |
|
||||
"include" ImportFrom {
|
||||
- jv v = block_const($2);
|
||||
- $$ = gen_import(jv_string_value(v), NULL, 0);
|
||||
+ $$ = gen_import(block_const($2), jv_invalid(), 0);
|
||||
block_free($2);
|
||||
- jv_free(v);
|
||||
}
|
||||
|
||||
ImportFrom:
|
||||
diff --git a/tests/shtest b/tests/shtest
|
||||
index 505d45d..4a5978c 100755
|
||||
--- a/tests/shtest
|
||||
+++ b/tests/shtest
|
||||
@@ -622,4 +622,21 @@ if echo '42' | $JQ -f "$d/nul_prog.jq" >/dev/null 2>/dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
+# CVE-2026-43895: No NUL bytes in module/data import paths
|
||||
+printf 'import "a\\u0000b" as $x; .' > "$d/nul_import.jq"
|
||||
+if $JQ -nf "$d/nul_import.jq" >/dev/null 2>/dev/null; then
|
||||
+ printf 'Error expected for import path with NUL bytes\n' 1>&2
|
||||
+ exit 1
|
||||
+fi
|
||||
+printf 'include "a\\u0000b"; .' > "$d/nul_include.jq"
|
||||
+if $JQ -nf "$d/nul_include.jq" >/dev/null 2>/dev/null; then
|
||||
+ printf 'Error expected for include path with NUL bytes\n' 1>&2
|
||||
+ exit 1
|
||||
+fi
|
||||
+printf '"a\\u0000b" | modulemeta' > "$d/nul_modulemeta.jq"
|
||||
+if $JQ -nf "$d/nul_modulemeta.jq" >/dev/null 2>/dev/null; then
|
||||
+ printf 'Error expected for modulemeta with NUL bytes\n' 1>&2
|
||||
+ exit 1
|
||||
+fi
|
||||
+
|
||||
exit 0
|
||||
--
|
||||
2.44.4
|
||||
|
||||
@@ -25,6 +25,7 @@ SRC_URI = "${GITHUB_BASE_URI}/download/${BPN}-${PV}/${BPN}-${PV}.tar.gz \
|
||||
file://CVE-2026-41257.patch \
|
||||
file://CVE-2026-43894.patch \
|
||||
file://CVE-2026-43896.patch \
|
||||
file://CVE-2026-43895.patch \
|
||||
"
|
||||
SRC_URI[sha256sum] = "478c9ca129fd2e3443fe27314b455e211e0d8c60bc8ff7df703873deeee580c2"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user