From patchwork Tue Oct 3 17:58:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Shubham Kulkarni X-Patchwork-Id: 31631 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id DB1D7E75458 for ; Tue, 3 Oct 2023 17:59:14 +0000 (UTC) Received: from mail-oa1-f44.google.com (mail-oa1-f44.google.com [209.85.160.44]) by mx.groups.io with SMTP id smtpd.web11.115099.1696355952891076917 for ; Tue, 03 Oct 2023 10:59:13 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=cA/klKPk; spf=pass (domain: mvista.com, ip: 209.85.160.44, mailfrom: skulkarni@mvista.com) Received: by mail-oa1-f44.google.com with SMTP id 586e51a60fabf-1e0ee4e777bso746919fac.3 for ; Tue, 03 Oct 2023 10:59:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; t=1696355951; x=1696960751; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=GB13vNf3yjEN022+9TlIemnGhGjMGdHtvOBV2V8hyQQ=; b=cA/klKPkdEwmWG2rInHTz+7kvqTejslCvZcoFUV9ZE7+/twYQ5BWtQ+l053+Ws4Hc9 4W1bunh33mgdw2h9nqGLxMQ9DwMxsr0CdU7gAeJVxyKv/d/YIr7W5SUxU2EcMhFzeCY4 c5IRInjMTrbfpjFvbOa34G+nGZAAIKRg0eww4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696355951; x=1696960751; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=GB13vNf3yjEN022+9TlIemnGhGjMGdHtvOBV2V8hyQQ=; b=lS2XsAgmodwN1ENugO2elIc2wwp//Oy8Kf2YwQw0XIecGvEQLasNSZv3m9NIdBZIRa Mpf//MQe1l/39kTIi/SrRq8PjDfN5K6k89FE9zn1a8ZL3i0O8fwPK2A2JhakVMJXOCF6 cbvnTZNaIkAqKSsdIH7NLV1cUhvznG6Lqj61tILpfzvLnEW/4xsZ8ZGdyWgKEjsyG3dx /VexQdaXmoPPLftw+bykJBQyddJV03UwffaySCBMuxExpGQLz++HJJpGqcWtTWzXHzMT /IsgIfuNFAcJIiyodki+r3OLPx973aeTz8cpMjsAhGbotEsW6uEWkuPiORrLwqWE/jck ZpLA== X-Gm-Message-State: AOJu0YzOW2cyKhdtXOhapzjpi+wKAy8RdXpLhXVPz+3ujs5frF3cG4No lml2hdifkPehpPFpLpgJRLnbK7e2OM1JZ4SGiNA= X-Google-Smtp-Source: AGHT+IHxOj8wsASUWK53DL7+5DG8k7Lbg6eObBP+o6RaQG6NfXTDE/gSQqszC7ZeK8ORIPr26x4cAQ== X-Received: by 2002:a05:6870:c1d2:b0:1b7:2d92:58d6 with SMTP id i18-20020a056870c1d200b001b72d9258d6mr326738oad.32.1696355950346; Tue, 03 Oct 2023 10:59:10 -0700 (PDT) Received: from MVIN00032.domain.name ([103.134.108.34]) by smtp.gmail.com with ESMTPSA id d23-20020a637357000000b0056c24c2e23dsm1679881pgn.25.2023.10.03.10.59.07 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Oct 2023 10:59:09 -0700 (PDT) From: skulkarni@mvista.com To: openembedded-core@lists.openembedded.org Cc: Shubham Kulkarni Subject: [OE-core][dunfell][PATCH v5] go: Update fix for CVE-2023-24538 & CVE-2023-39318 Date: Tue, 3 Oct 2023 23:28:51 +0530 Message-ID: <20231003175853.29809-1-skulkarni@mvista.com> X-Mailer: git-send-email 2.42.0 MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 03 Oct 2023 17:59:14 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/188647 From: Shubham Kulkarni Add missing files in fix for CVE-2023-24538 & CVE-2023-39318 Upstream Link - CVE-2023-24538: https://github.com/golang/go/commit/b1e3ecfa06b67014429a197ec5e134ce4303ad9b CVE-2023-39318: https://github.com/golang/go/commit/023b542edf38e2a1f87fcefb9f75ff2f99401b4c Signed-off-by: Shubham Kulkarni --- meta/recipes-devtools/go/go-1.14.inc | 5 +- .../go/go-1.14/CVE-2023-24538-1.patch | 4 +- .../go/go-1.14/CVE-2023-24538-2.patch | 447 ++++++++++++- .../go/go-1.14/CVE-2023-24538_3.patch | 393 ++++++++++++ .../go/go-1.14/CVE-2023-24538_4.patch | 497 +++++++++++++++ .../go/go-1.14/CVE-2023-24538_5.patch | 585 ++++++++++++++++++ ...3-24538-3.patch => CVE-2023-24538_6.patch} | 175 +++++- .../go/go-1.14/CVE-2023-39318.patch | 38 +- 8 files changed, 2124 insertions(+), 20 deletions(-) create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2023-24538_3.patch create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2023-24538_5.patch rename meta/recipes-devtools/go/go-1.14/{CVE-2023-24538-3.patch => CVE-2023-24538_6.patch} (53%) diff --git a/meta/recipes-devtools/go/go-1.14.inc b/meta/recipes-devtools/go/go-1.14.inc index be63f64825..091b778de8 100644 --- a/meta/recipes-devtools/go/go-1.14.inc +++ b/meta/recipes-devtools/go/go-1.14.inc @@ -60,7 +60,10 @@ SRC_URI += "\ file://CVE-2023-24534.patch \ file://CVE-2023-24538-1.patch \ file://CVE-2023-24538-2.patch \ - file://CVE-2023-24538-3.patch \ + file://CVE-2023-24538_3.patch \ + file://CVE-2023-24538_4.patch \ + file://CVE-2023-24538_5.patch \ + file://CVE-2023-24538_6.patch \ file://CVE-2023-24539.patch \ file://CVE-2023-24540.patch \ file://CVE-2023-29405-1.patch \ diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-1.patch index eda26e5ff6..23c5075e41 100644 --- a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-1.patch +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-1.patch @@ -1,7 +1,7 @@ From 8acd01094d9ee17f6e763a61e49a8a808b3a9ddb Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 2 Aug 2021 14:55:51 -0700 -Subject: [PATCH 1/3] net/netip: add new IP address package +Subject: [PATCH 1/6] net/netip: add new IP address package Co-authored-by: Alex Willmer (GitHub @moreati) Co-authored-by: Alexander Yastrebov @@ -31,7 +31,7 @@ Trust: Brad Fitzpatrick Dependency Patch #1 -Upstream-Status: Backport [https://github.com/golang/go/commit/a59e33224e42d60a97fa720a45e1b74eb6aaa3d0] +Upstream-Status: Backport from https://github.com/golang/go/commit/a59e33224e42d60a97fa720a45e1b74eb6aaa3d0 CVE: CVE-2023-24538 Signed-off-by: Shubham Kulkarni --- diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch index 5036f2890b..f200c41e16 100644 --- a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch @@ -1,7 +1,7 @@ From 6fc21505614f36178df0dad7034b6b8e3f7588d5 Mon Sep 17 00:00:00 2001 From: empijei Date: Fri, 27 Mar 2020 19:27:55 +0100 -Subject: [PATCH 2/3] html/template,text/template: switch to Unicode escapes +Subject: [PATCH 2/6] html/template,text/template: switch to Unicode escapes for JSON compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -31,10 +31,238 @@ Upstream-Status: Backport from https://github.com/golang/go/commit/d4d298040d072 CVE: CVE-2023-24538 Signed-off-by: Shubham Kulkarni --- - src/html/template/js.go | 70 +++++++++++++++++++++++++++------------------- - src/text/template/funcs.go | 8 +++--- - 2 files changed, 46 insertions(+), 32 deletions(-) + src/html/template/content_test.go | 70 +++++++++++++++++++------------------- + src/html/template/escape_test.go | 6 ++-- + src/html/template/example_test.go | 6 ++-- + src/html/template/js.go | 70 +++++++++++++++++++++++--------------- + src/html/template/js_test.go | 68 ++++++++++++++++++------------------ + src/html/template/template_test.go | 39 +++++++++++++++++++++ + src/text/template/exec_test.go | 6 ++-- + src/text/template/funcs.go | 8 ++--- + 8 files changed, 163 insertions(+), 110 deletions(-) +diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go +index 72d56f5..bd86527 100644 +--- a/src/html/template/content_test.go ++++ b/src/html/template/content_test.go +@@ -18,7 +18,7 @@ func TestTypedContent(t *testing.T) { + HTML(`Hello, World &tc!`), + HTMLAttr(` dir="ltr"`), + JS(`c && alert("Hello, World!");`), +- JSStr(`Hello, World & O'Reilly\x21`), ++ JSStr(`Hello, World & O'Reilly\u0021`), + URL(`greeting=H%69,&addressee=(World)`), + Srcset(`greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`), + URL(`,foo/,`), +@@ -70,7 +70,7 @@ func TestTypedContent(t *testing.T) { + `Hello, World &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -100,7 +100,7 @@ func TestTypedContent(t *testing.T) { + `Hello, World &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -115,7 +115,7 @@ func TestTypedContent(t *testing.T) { + `Hello, World &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -130,7 +130,7 @@ func TestTypedContent(t *testing.T) { + `Hello, <b>World</b> &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -146,7 +146,7 @@ func TestTypedContent(t *testing.T) { + // Not escaped. + `c && alert("Hello, World!");`, + // Escape sequence not over-escaped. +- `"Hello, World & O'Reilly\x21"`, ++ `"Hello, World & O'Reilly\u0021"`, + `"greeting=H%69,\u0026addressee=(World)"`, + `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, + `",foo/,"`, +@@ -162,7 +162,7 @@ func TestTypedContent(t *testing.T) { + // Not JS escaped but HTML escaped. + `c && alert("Hello, World!");`, + // Escape sequence not over-escaped. +- `"Hello, World & O'Reilly\x21"`, ++ `"Hello, World & O'Reilly\u0021"`, + `"greeting=H%69,\u0026addressee=(World)"`, + `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, + `",foo/,"`, +@@ -171,30 +171,30 @@ func TestTypedContent(t *testing.T) { + { + ``, + []string{ +- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, +- `a[href =~ \x22\/\/example.com\x22]#foo`, +- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, +- ` dir=\x22ltr\x22`, +- `c \x26\x26 alert(\x22Hello, World!\x22);`, ++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, ++ `a[href =~ \u0022\/\/example.com\u0022]#foo`, ++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, ++ ` dir=\u0022ltr\u0022`, ++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, + // Escape sequence not over-escaped. +- `Hello, World \x26 O\x27Reilly\x21`, +- `greeting=H%69,\x26addressee=(World)`, +- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, ++ `Hello, World \u0026 O\u0027Reilly\u0021`, ++ `greeting=H%69,\u0026addressee=(World)`, ++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `,foo\/,`, + }, + }, + { + ``, + []string{ +- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, +- `a[href =~ \x22\/\/example.com\x22]#foo`, +- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, +- ` dir=\x22ltr\x22`, +- `c \x26\x26 alert(\x22Hello, World!\x22);`, ++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, ++ `a[href =~ \u0022\/\/example.com\u0022]#foo`, ++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, ++ ` dir=\u0022ltr\u0022`, ++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, + // Escape sequence not over-escaped. +- `Hello, World \x26 O\x27Reilly\x21`, +- `greeting=H%69,\x26addressee=(World)`, +- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, ++ `Hello, World \u0026 O\u0027Reilly\u0021`, ++ `greeting=H%69,\u0026addressee=(World)`, ++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `,foo\/,`, + }, + }, +@@ -208,7 +208,7 @@ func TestTypedContent(t *testing.T) { + // Not escaped. + `c && alert("Hello, World!");`, + // Escape sequence not over-escaped. +- `"Hello, World & O'Reilly\x21"`, ++ `"Hello, World & O'Reilly\u0021"`, + `"greeting=H%69,\u0026addressee=(World)"`, + `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, + `",foo/,"`, +@@ -224,7 +224,7 @@ func TestTypedContent(t *testing.T) { + `Hello, World &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -233,15 +233,15 @@ func TestTypedContent(t *testing.T) { + { + ``, + "helper": `{{11}} of {{"<100>"}}`, + }, +- ``, ++ ``, + }, + // A non-recursive template that ends in a different context. + // helper starts in jsCtxRegexp and ends in jsCtxDivOp. +diff --git a/src/html/template/example_test.go b/src/html/template/example_test.go +index 9d965f1..6cf936f 100644 +--- a/src/html/template/example_test.go ++++ b/src/html/template/example_test.go +@@ -116,9 +116,9 @@ func Example_escape() { + // "Fran & Freddie's Diner" <tasty@example.com> + // "Fran & Freddie's Diner" <tasty@example.com> + // "Fran & Freddie's Diner"32<tasty@example.com> +- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E +- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E +- // \"Fran \x26 Freddie\'s Diner\"32\x3Ctasty@example.com\x3E ++ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E ++ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E ++ // \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E + // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E + + } diff --git a/src/html/template/js.go b/src/html/template/js.go index 0e91458..ea9c183 100644 --- a/src/html/template/js.go @@ -173,6 +401,217 @@ index 0e91458..ea9c183 100644 '?': `\?`, '[': `\[`, '\\': `\\`, +diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go +index 075adaa..d7ee47b 100644 +--- a/src/html/template/js_test.go ++++ b/src/html/template/js_test.go +@@ -137,7 +137,7 @@ func TestJSValEscaper(t *testing.T) { + {"foo", `"foo"`}, + // Newlines. + {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, +- // "\v" == "v" on IE 6 so use "\x0b" instead. ++ // "\v" == "v" on IE 6 so use "\u000b" instead. + {"\t\x0b", `"\t\u000b"`}, + {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, + {[]interface{}{}, "[]"}, +@@ -173,7 +173,7 @@ func TestJSStrEscaper(t *testing.T) { + }{ + {"", ``}, + {"foo", `foo`}, +- {"\u0000", `\0`}, ++ {"\u0000", `\u0000`}, + {"\t", `\t`}, + {"\n", `\n`}, + {"\r", `\r`}, +@@ -183,14 +183,14 @@ func TestJSStrEscaper(t *testing.T) { + {"\\n", `\\n`}, + {"foo\r\nbar", `foo\r\nbar`}, + // Preserve attribute boundaries. +- {`"`, `\x22`}, +- {`'`, `\x27`}, ++ {`"`, `\u0022`}, ++ {`'`, `\u0027`}, + // Allow embedding in HTML without further escaping. +- {`&`, `\x26amp;`}, ++ {`&`, `\u0026amp;`}, + // Prevent breaking out of text node and element boundaries. +- {"", `\x3c\/script\x3e`}, +- {"", `]]\x3e`}, ++ {"", `\u003c\/script\u003e`}, ++ {"", `]]\u003e`}, + // https://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span + // "The text in style, script, title, and textarea elements + // must not have an escaping text span start that is not +@@ -201,11 +201,11 @@ func TestJSStrEscaper(t *testing.T) { + // allow regular text content to be interpreted as script + // allowing script execution via a combination of a JS string + // injection followed by an HTML text injection. +- {"", `--\x3e`}, ++ {"", `--\u003e`}, + // From https://code.google.com/p/doctype/wiki/ArticleUtf7 + {"+ADw-script+AD4-alert(1)+ADw-/script+AD4-", +- `\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`, ++ `\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`, + }, + // Invalid UTF-8 sequence + {"foo\xA0bar", "foo\xA0bar"}, +@@ -228,7 +228,7 @@ func TestJSRegexpEscaper(t *testing.T) { + }{ + {"", `(?:)`}, + {"foo", `foo`}, +- {"\u0000", `\0`}, ++ {"\u0000", `\u0000`}, + {"\t", `\t`}, + {"\n", `\n`}, + {"\r", `\r`}, +@@ -238,19 +238,19 @@ func TestJSRegexpEscaper(t *testing.T) { + {"\\n", `\\n`}, + {"foo\r\nbar", `foo\r\nbar`}, + // Preserve attribute boundaries. +- {`"`, `\x22`}, +- {`'`, `\x27`}, ++ {`"`, `\u0022`}, ++ {`'`, `\u0027`}, + // Allow embedding in HTML without further escaping. +- {`&`, `\x26amp;`}, ++ {`&`, `\u0026amp;`}, + // Prevent breaking out of text node and element boundaries. +- {"", `\x3c\/script\x3e`}, +- {"", `\]\]\x3e`}, ++ {"", `\u003c\/script\u003e`}, ++ {"", `\]\]\u003e`}, + // Escaping text spans. +- {"", `\-\-\x3e`}, ++ {"", `\-\-\u003e`}, + {"*", `\*`}, +- {"+", `\x2b`}, ++ {"+", `\u002b`}, + {"?", `\?`}, + {"[](){}", `\[\]\(\)\{\}`}, + {"$foo|x.y", `\$foo\|x\.y`}, +@@ -284,27 +284,27 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) { + { + "jsStrEscaper", + jsStrEscaper, +- "\\0\x01\x02\x03\x04\x05\x06\x07" + +- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + +- "\x10\x11\x12\x13\x14\x15\x16\x17" + +- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + +- ` !\x22#$%\x26\x27()*\x2b,-.\/` + +- `0123456789:;\x3c=\x3e?` + ++ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` + ++ `\u0008\t\n\u000b\f\r\u000e\u000f` + ++ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` + ++ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` + ++ ` !\u0022#$%\u0026\u0027()*\u002b,-.\/` + ++ `0123456789:;\u003c=\u003e?` + + `@ABCDEFGHIJKLMNO` + + `PQRSTUVWXYZ[\\]^_` + + "`abcdefghijklmno" + +- "pqrstuvwxyz{|}~\x7f" + ++ "pqrstuvwxyz{|}~\u007f" + + "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E", + }, + { + "jsRegexpEscaper", + jsRegexpEscaper, +- "\\0\x01\x02\x03\x04\x05\x06\x07" + +- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + +- "\x10\x11\x12\x13\x14\x15\x16\x17" + +- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + +- ` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` + +- `0123456789:;\x3c=\x3e\?` + ++ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` + ++ `\u0008\t\n\u000b\f\r\u000e\u000f` + ++ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` + ++ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` + ++ ` !\u0022#\$%\u0026\u0027\(\)\*\u002b,\-\.\/` + ++ `0123456789:;\u003c=\u003e\?` + + `@ABCDEFGHIJKLMNO` + + `PQRSTUVWXYZ\[\\\]\^_` + + "`abcdefghijklmno" + +diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go +index 13e6ba4..86bd4db 100644 +--- a/src/html/template/template_test.go ++++ b/src/html/template/template_test.go +@@ -6,6 +6,7 @@ package template_test + + import ( + "bytes" ++ "encoding/json" + . "html/template" + "strings" + "testing" +@@ -121,6 +122,44 @@ func TestNumbers(t *testing.T) { + c.mustExecute(c.root, nil, "12.34 7.5") + } + ++func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) { ++ // See #33671 and #37634 for more context on this. ++ tests := []struct{ name, in string }{ ++ {"empty", ""}, ++ {"invalid", string(rune(-1))}, ++ {"null", "\u0000"}, ++ {"unit separator", "\u001F"}, ++ {"tab", "\t"}, ++ {"gt and lt", "<>"}, ++ {"quotes", `'"`}, ++ {"ASCII letters", "ASCII letters"}, ++ {"Unicode", "ʕ⊙ϖ⊙ʔ"}, ++ {"Pizza", "P"}, ++ } ++ const ( ++ prefix = `` ++ templ = prefix + `"{{.}}"` + suffix ++ ) ++ tpl := Must(New("JS string is JSON string").Parse(templ)) ++ for _, tt := range tests { ++ t.Run(tt.name, func(t *testing.T) { ++ var buf bytes.Buffer ++ if err := tpl.Execute(&buf, tt.in); err != nil { ++ t.Fatalf("Cannot render template: %v", err) ++ } ++ trimmed := bytes.TrimSuffix(bytes.TrimPrefix(buf.Bytes(), []byte(prefix)), []byte(suffix)) ++ var got string ++ if err := json.Unmarshal(trimmed, &got); err != nil { ++ t.Fatalf("Cannot parse JS string %q as JSON: %v", trimmed[1:len(trimmed)-1], err) ++ } ++ if got != tt.in { ++ t.Errorf("Serialization changed the string value: got %q want %q", got, tt.in) ++ } ++ }) ++ } ++} ++ + type testCase struct { + t *testing.T + root *Template +diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go +index 77294ed..b8a809e 100644 +--- a/src/text/template/exec_test.go ++++ b/src/text/template/exec_test.go +@@ -911,9 +911,9 @@ func TestJSEscaping(t *testing.T) { + {`Go "jump" \`, `Go \"jump\" \\`}, + {`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`}, + {"unprintable \uFDFF", `unprintable \uFDFF`}, +- {``, `\x3Chtml\x3E`}, +- {`no = in attributes`, `no \x3D in attributes`}, +- {`' does not become HTML entity`, `\x26#x27; does not become HTML entity`}, ++ {``, `\u003Chtml\u003E`}, ++ {`no = in attributes`, `no \u003D in attributes`}, ++ {`' does not become HTML entity`, `\u0026#x27; does not become HTML entity`}, + } + for _, tc := range testCases { + s := JSEscapeString(tc.in) diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index 46125bc..f3de9fb 100644 --- a/src/text/template/funcs.go diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_3.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_3.patch new file mode 100644 index 0000000000..cd7dd0957c --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_3.patch @@ -0,0 +1,393 @@ +From 7ddce23c7d5b728acf8482f5006497c7b9915f8a Mon Sep 17 00:00:00 2001 +From: Ariel Mashraki +Date: Wed, 22 Apr 2020 22:17:56 +0300 +Subject: [PATCH 3/6] text/template: add CommentNode to template parse tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes #34652 + +Change-Id: Icf6e3eda593fed826736f34f95a9d66f5450cc98 +Reviewed-on: https://go-review.googlesource.com/c/go/+/229398 +Reviewed-by: Daniel Martí +Run-TryBot: Daniel Martí +TryBot-Result: Gobot Gobot + +Dependency Patch #3 + +Upstream-Status: Backport from https://github.com/golang/go/commit/c8ea03828b0645b1fd5725888e44873b75fcfbb6 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni +--- + api/next.txt | 19 +++++++++++++++++++ + src/html/template/escape.go | 2 ++ + src/html/template/template_test.go | 16 ++++++++++++++++ + src/text/template/exec.go | 1 + + src/text/template/parse/lex.go | 8 +++++++- + src/text/template/parse/lex_test.go | 7 +++++-- + src/text/template/parse/node.go | 33 +++++++++++++++++++++++++++++++++ + src/text/template/parse/parse.go | 22 +++++++++++++++++++--- + src/text/template/parse/parse_test.go | 25 +++++++++++++++++++++++++ + 9 files changed, 127 insertions(+), 6 deletions(-) + +diff --git a/api/next.txt b/api/next.txt +index e69de29..076f39e 100644 +--- a/api/next.txt ++++ b/api/next.txt +@@ -0,0 +1,19 @@ ++pkg unicode, const Version = "13.0.0" ++pkg unicode, var Chorasmian *RangeTable ++pkg unicode, var Dives_Akuru *RangeTable ++pkg unicode, var Khitan_Small_Script *RangeTable ++pkg unicode, var Yezidi *RangeTable ++pkg text/template/parse, const NodeComment = 20 ++pkg text/template/parse, const NodeComment NodeType ++pkg text/template/parse, const ParseComments = 1 ++pkg text/template/parse, const ParseComments Mode ++pkg text/template/parse, method (*CommentNode) Copy() Node ++pkg text/template/parse, method (*CommentNode) String() string ++pkg text/template/parse, method (CommentNode) Position() Pos ++pkg text/template/parse, method (CommentNode) Type() NodeType ++pkg text/template/parse, type CommentNode struct ++pkg text/template/parse, type CommentNode struct, Text string ++pkg text/template/parse, type CommentNode struct, embedded NodeType ++pkg text/template/parse, type CommentNode struct, embedded Pos ++pkg text/template/parse, type Mode uint ++pkg text/template/parse, type Tree struct, Mode Mode +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index f12dafa..8739735 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -124,6 +124,8 @@ func (e *escaper) escape(c context, n parse.Node) context { + switch n := n.(type) { + case *parse.ActionNode: + return e.escapeAction(c, n) ++ case *parse.CommentNode: ++ return c + case *parse.IfNode: + return e.escapeBranch(c, &n.BranchNode, "if") + case *parse.ListNode: +diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go +index 86bd4db..1f2c888 100644 +--- a/src/html/template/template_test.go ++++ b/src/html/template/template_test.go +@@ -10,6 +10,7 @@ import ( + . "html/template" + "strings" + "testing" ++ "text/template/parse" + ) + + func TestTemplateClone(t *testing.T) { +@@ -160,6 +161,21 @@ func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) { + } + } + ++func TestSkipEscapeComments(t *testing.T) { ++ c := newTestCase(t) ++ tr := parse.New("root") ++ tr.Mode = parse.ParseComments ++ newT, err := tr.Parse("{{/* A comment */}}{{ 1 }}{{/* Another comment */}}", "", "", make(map[string]*parse.Tree)) ++ if err != nil { ++ t.Fatalf("Cannot parse template text: %v", err) ++ } ++ c.root, err = c.root.AddParseTree("root", newT) ++ if err != nil { ++ t.Fatalf("Cannot add parse tree to template: %v", err) ++ } ++ c.mustExecute(c.root, nil, "1") ++} ++ + type testCase struct { + t *testing.T + root *Template +diff --git a/src/text/template/exec.go b/src/text/template/exec.go +index ac3e741..7ac5175 100644 +--- a/src/text/template/exec.go ++++ b/src/text/template/exec.go +@@ -256,6 +256,7 @@ func (s *state) walk(dot reflect.Value, node parse.Node) { + if len(node.Pipe.Decl) == 0 { + s.printValue(node, val) + } ++ case *parse.CommentNode: + case *parse.IfNode: + s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) + case *parse.ListNode: +diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go +index 30371f2..e41373a 100644 +--- a/src/text/template/parse/lex.go ++++ b/src/text/template/parse/lex.go +@@ -41,6 +41,7 @@ const ( + itemBool // boolean constant + itemChar // printable ASCII character; grab bag for comma etc. + itemCharConstant // character constant ++ itemComment // comment text + itemComplex // complex constant (1+2i); imaginary is just a number + itemAssign // equals ('=') introducing an assignment + itemDeclare // colon-equals (':=') introducing a declaration +@@ -112,6 +113,7 @@ type lexer struct { + leftDelim string // start of action + rightDelim string // end of action + trimRightDelim string // end of action with trim marker ++ emitComment bool // emit itemComment tokens. + pos Pos // current position in the input + start Pos // start position of this item + width Pos // width of last rune read from input +@@ -203,7 +205,7 @@ func (l *lexer) drain() { + } + + // lex creates a new scanner for the input string. +-func lex(name, input, left, right string) *lexer { ++func lex(name, input, left, right string, emitComment bool) *lexer { + if left == "" { + left = leftDelim + } +@@ -216,6 +218,7 @@ func lex(name, input, left, right string) *lexer { + leftDelim: left, + rightDelim: right, + trimRightDelim: rightTrimMarker + right, ++ emitComment: emitComment, + items: make(chan item), + line: 1, + startLine: 1, +@@ -323,6 +326,9 @@ func lexComment(l *lexer) stateFn { + if !delim { + return l.errorf("comment ends before closing delimiter") + } ++ if l.emitComment { ++ l.emit(itemComment) ++ } + if trimSpace { + l.pos += trimMarkerLen + } +diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go +index 563c4fc..f6d5f28 100644 +--- a/src/text/template/parse/lex_test.go ++++ b/src/text/template/parse/lex_test.go +@@ -15,6 +15,7 @@ var itemName = map[itemType]string{ + itemBool: "bool", + itemChar: "char", + itemCharConstant: "charconst", ++ itemComment: "comment", + itemComplex: "complex", + itemDeclare: ":=", + itemEOF: "EOF", +@@ -90,6 +91,7 @@ var lexTests = []lexTest{ + {"text", `now is the time`, []item{mkItem(itemText, "now is the time"), tEOF}}, + {"text with comment", "hello-{{/* this is a comment */}}-world", []item{ + mkItem(itemText, "hello-"), ++ mkItem(itemComment, "/* this is a comment */"), + mkItem(itemText, "-world"), + tEOF, + }}, +@@ -311,6 +313,7 @@ var lexTests = []lexTest{ + }}, + {"trimming spaces before and after comment", "hello- {{- /* hello */ -}} -world", []item{ + mkItem(itemText, "hello-"), ++ mkItem(itemComment, "/* hello */"), + mkItem(itemText, "-world"), + tEOF, + }}, +@@ -389,7 +392,7 @@ var lexTests = []lexTest{ + + // collect gathers the emitted items into a slice. + func collect(t *lexTest, left, right string) (items []item) { +- l := lex(t.name, t.input, left, right) ++ l := lex(t.name, t.input, left, right, true) + for { + item := l.nextItem() + items = append(items, item) +@@ -529,7 +532,7 @@ func TestPos(t *testing.T) { + func TestShutdown(t *testing.T) { + // We need to duplicate template.Parse here to hold on to the lexer. + const text = "erroneous{{define}}{{else}}1234" +- lexer := lex("foo", text, "{{", "}}") ++ lexer := lex("foo", text, "{{", "}}", false) + _, err := New("root").parseLexer(lexer) + if err == nil { + t.Fatalf("expected error") +diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go +index 1c116ea..a9dad5e 100644 +--- a/src/text/template/parse/node.go ++++ b/src/text/template/parse/node.go +@@ -70,6 +70,7 @@ const ( + NodeTemplate // A template invocation action. + NodeVariable // A $ variable. + NodeWith // A with action. ++ NodeComment // A comment. + ) + + // Nodes. +@@ -149,6 +150,38 @@ func (t *TextNode) Copy() Node { + return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)} + } + ++// CommentNode holds a comment. ++type CommentNode struct { ++ NodeType ++ Pos ++ tr *Tree ++ Text string // Comment text. ++} ++ ++func (t *Tree) newComment(pos Pos, text string) *CommentNode { ++ return &CommentNode{tr: t, NodeType: NodeComment, Pos: pos, Text: text} ++} ++ ++func (c *CommentNode) String() string { ++ var sb strings.Builder ++ c.writeTo(&sb) ++ return sb.String() ++} ++ ++func (c *CommentNode) writeTo(sb *strings.Builder) { ++ sb.WriteString("{{") ++ sb.WriteString(c.Text) ++ sb.WriteString("}}") ++} ++ ++func (c *CommentNode) tree() *Tree { ++ return c.tr ++} ++ ++func (c *CommentNode) Copy() Node { ++ return &CommentNode{tr: c.tr, NodeType: NodeComment, Pos: c.Pos, Text: c.Text} ++} ++ + // PipeNode holds a pipeline with optional declaration + type PipeNode struct { + NodeType +diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go +index c9b80f4..496d8bf 100644 +--- a/src/text/template/parse/parse.go ++++ b/src/text/template/parse/parse.go +@@ -21,6 +21,7 @@ type Tree struct { + Name string // name of the template represented by the tree. + ParseName string // name of the top-level template during parsing, for error messages. + Root *ListNode // top-level root of the tree. ++ Mode Mode // parsing mode. + text string // text parsed to create the template (or its parent) + // Parsing only; cleared after parse. + funcs []map[string]interface{} +@@ -29,8 +30,16 @@ type Tree struct { + peekCount int + vars []string // variables defined at the moment. + treeSet map[string]*Tree ++ mode Mode + } + ++// A mode value is a set of flags (or 0). Modes control parser behavior. ++type Mode uint ++ ++const ( ++ ParseComments Mode = 1 << iota // parse comments and add them to AST ++) ++ + // Copy returns a copy of the Tree. Any parsing state is discarded. + func (t *Tree) Copy() *Tree { + if t == nil { +@@ -220,7 +229,8 @@ func (t *Tree) stopParse() { + func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) { + defer t.recover(&err) + t.ParseName = t.Name +- t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim), treeSet) ++ emitComment := t.Mode&ParseComments != 0 ++ t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet) + t.text = text + t.parse() + t.add() +@@ -240,12 +250,14 @@ func (t *Tree) add() { + } + } + +-// IsEmptyTree reports whether this tree (node) is empty of everything but space. ++// IsEmptyTree reports whether this tree (node) is empty of everything but space or comments. + func IsEmptyTree(n Node) bool { + switch n := n.(type) { + case nil: + return true + case *ActionNode: ++ case *CommentNode: ++ return true + case *IfNode: + case *ListNode: + for _, node := range n.Nodes { +@@ -276,6 +288,7 @@ func (t *Tree) parse() { + if t.nextNonSpace().typ == itemDefine { + newT := New("definition") // name will be updated once we know it. + newT.text = t.text ++ newT.Mode = t.Mode + newT.ParseName = t.ParseName + newT.startParse(t.funcs, t.lex, t.treeSet) + newT.parseDefinition() +@@ -331,13 +344,15 @@ func (t *Tree) itemList() (list *ListNode, next Node) { + } + + // textOrAction: +-// text | action ++// text | comment | action + func (t *Tree) textOrAction() Node { + switch token := t.nextNonSpace(); token.typ { + case itemText: + return t.newText(token.pos, token.val) + case itemLeftDelim: + return t.action() ++ case itemComment: ++ return t.newComment(token.pos, token.val) + default: + t.unexpected(token, "input") + } +@@ -539,6 +554,7 @@ func (t *Tree) blockControl() Node { + + block := New(name) // name will be updated once we know it. + block.text = t.text ++ block.Mode = t.Mode + block.ParseName = t.ParseName + block.startParse(t.funcs, t.lex, t.treeSet) + var end Node +diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go +index 4e09a78..d9c13c5 100644 +--- a/src/text/template/parse/parse_test.go ++++ b/src/text/template/parse/parse_test.go +@@ -348,6 +348,30 @@ func TestParseCopy(t *testing.T) { + testParse(true, t) + } + ++func TestParseWithComments(t *testing.T) { ++ textFormat = "%q" ++ defer func() { textFormat = "%s" }() ++ tests := [...]parseTest{ ++ {"comment", "{{/*\n\n\n*/}}", noError, "{{/*\n\n\n*/}}"}, ++ {"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"{{/* hi */}}`}, ++ {"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `{{/* hi */}}"y"`}, ++ {"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x"{{/* */}}"y"`}, ++ } ++ for _, test := range tests { ++ t.Run(test.name, func(t *testing.T) { ++ tr := New(test.name) ++ tr.Mode = ParseComments ++ tmpl, err := tr.Parse(test.input, "", "", make(map[string]*Tree)) ++ if err != nil { ++ t.Errorf("%q: expected error; got none", test.name) ++ } ++ if result := tmpl.Root.String(); result != test.result { ++ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.result) ++ } ++ }) ++ } ++} ++ + type isEmptyTest struct { + name string + input string +@@ -358,6 +382,7 @@ var isEmptyTests = []isEmptyTest{ + {"empty", ``, true}, + {"nonempty", `hello`, false}, + {"spaces only", " \t\n \t\n", true}, ++ {"comment only", "{{/* comment */}}", true}, + {"definition", `{{define "x"}}something{{end}}`, true}, + {"definitions and space", "{{define `x`}}something{{end}}\n\n{{define `y`}}something{{end}}\n\n", true}, + {"definitions and text", "{{define `x`}}something{{end}}\nx\n{{define `y`}}something{{end}}\ny\n", false}, +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch new file mode 100644 index 0000000000..d5e2eb6684 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch @@ -0,0 +1,497 @@ +From 760d88497091fb5d6d231a18e6f4e06ecb9af9b2 Mon Sep 17 00:00:00 2001 +From: Russ Cox +Date: Thu, 10 Sep 2020 18:53:26 -0400 +Subject: [PATCH 4/6] text/template: allow newlines inside action delimiters + +This allows multiline constructs like: + + {{"hello" | + printf}} + +Now that unclosed actions can span multiple lines, +track and report the start of the action when reporting errors. + +Also clean up a few "unexpected " to be just "". + +Fixes #29770. + +Change-Id: I54c6c016029a8328b7902a4b6d85eab713ec3285 +Reviewed-on: https://go-review.googlesource.com/c/go/+/254257 +Trust: Russ Cox +Run-TryBot: Russ Cox +TryBot-Result: Go Bot +Reviewed-by: Rob Pike + +Dependency Patch #4 + +Upstream-Status: Backport from https://github.com/golang/go/commit/9384d34c58099657bb1b133beaf3ff37ada9b017 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni +--- + src/text/template/doc.go | 21 ++++----- + src/text/template/exec_test.go | 2 +- + src/text/template/parse/lex.go | 84 +++++++++++++++++------------------ + src/text/template/parse/lex_test.go | 2 +- + src/text/template/parse/parse.go | 59 +++++++++++++----------- + src/text/template/parse/parse_test.go | 36 ++++++++++++--- + 6 files changed, 117 insertions(+), 87 deletions(-) + +diff --git a/src/text/template/doc.go b/src/text/template/doc.go +index 4b0efd2..7b30294 100644 +--- a/src/text/template/doc.go ++++ b/src/text/template/doc.go +@@ -40,16 +40,17 @@ More intricate examples appear below. + Text and spaces + + By default, all text between actions is copied verbatim when the template is +-executed. For example, the string " items are made of " in the example above appears +-on standard output when the program is run. +- +-However, to aid in formatting template source code, if an action's left delimiter +-(by default "{{") is followed immediately by a minus sign and ASCII space character +-("{{- "), all trailing white space is trimmed from the immediately preceding text. +-Similarly, if the right delimiter ("}}") is preceded by a space and minus sign +-(" -}}"), all leading white space is trimmed from the immediately following text. +-In these trim markers, the ASCII space must be present; "{{-3}}" parses as an +-action containing the number -3. ++executed. For example, the string " items are made of " in the example above ++appears on standard output when the program is run. ++ ++However, to aid in formatting template source code, if an action's left ++delimiter (by default "{{") is followed immediately by a minus sign and white ++space, all trailing white space is trimmed from the immediately preceding text. ++Similarly, if the right delimiter ("}}") is preceded by white space and a minus ++sign, all leading white space is trimmed from the immediately following text. ++In these trim markers, the white space must be present: ++"{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while ++"{{-3}}" parses as an action containing the number -3. + + For instance, when executing the template whose source is + +diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go +index b8a809e..3309b33 100644 +--- a/src/text/template/exec_test.go ++++ b/src/text/template/exec_test.go +@@ -1295,7 +1295,7 @@ func TestUnterminatedStringError(t *testing.T) { + t.Fatal("expected error") + } + str := err.Error() +- if !strings.Contains(str, "X:3: unexpected unterminated raw quoted string") { ++ if !strings.Contains(str, "X:3: unterminated raw quoted string") { + t.Fatalf("unexpected error: %s", str) + } + } +diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go +index e41373a..6784071 100644 +--- a/src/text/template/parse/lex.go ++++ b/src/text/template/parse/lex.go +@@ -92,15 +92,14 @@ const eof = -1 + // If the action begins "{{- " rather than "{{", then all space/tab/newlines + // preceding the action are trimmed; conversely if it ends " -}}" the + // leading spaces are trimmed. This is done entirely in the lexer; the +-// parser never sees it happen. We require an ASCII space to be +-// present to avoid ambiguity with things like "{{-3}}". It reads ++// parser never sees it happen. We require an ASCII space (' ', \t, \r, \n) ++// to be present to avoid ambiguity with things like "{{-3}}". It reads + // better with the space present anyway. For simplicity, only ASCII +-// space does the job. ++// does the job. + const ( +- spaceChars = " \t\r\n" // These are the space characters defined by Go itself. +- leftTrimMarker = "- " // Attached to left delimiter, trims trailing spaces from preceding text. +- rightTrimMarker = " -" // Attached to right delimiter, trims leading spaces from following text. +- trimMarkerLen = Pos(len(leftTrimMarker)) ++ spaceChars = " \t\r\n" // These are the space characters defined by Go itself. ++ trimMarker = '-' // Attached to left/right delimiter, trims trailing spaces from preceding/following text. ++ trimMarkerLen = Pos(1 + 1) // marker plus space before or after + ) + + // stateFn represents the state of the scanner as a function that returns the next state. +@@ -108,19 +107,18 @@ type stateFn func(*lexer) stateFn + + // lexer holds the state of the scanner. + type lexer struct { +- name string // the name of the input; used only for error reports +- input string // the string being scanned +- leftDelim string // start of action +- rightDelim string // end of action +- trimRightDelim string // end of action with trim marker +- emitComment bool // emit itemComment tokens. +- pos Pos // current position in the input +- start Pos // start position of this item +- width Pos // width of last rune read from input +- items chan item // channel of scanned items +- parenDepth int // nesting depth of ( ) exprs +- line int // 1+number of newlines seen +- startLine int // start line of this item ++ name string // the name of the input; used only for error reports ++ input string // the string being scanned ++ leftDelim string // start of action ++ rightDelim string // end of action ++ emitComment bool // emit itemComment tokens. ++ pos Pos // current position in the input ++ start Pos // start position of this item ++ width Pos // width of last rune read from input ++ items chan item // channel of scanned items ++ parenDepth int // nesting depth of ( ) exprs ++ line int // 1+number of newlines seen ++ startLine int // start line of this item + } + + // next returns the next rune in the input. +@@ -213,15 +211,14 @@ func lex(name, input, left, right string, emitComment bool) *lexer { + right = rightDelim + } + l := &lexer{ +- name: name, +- input: input, +- leftDelim: left, +- rightDelim: right, +- trimRightDelim: rightTrimMarker + right, +- emitComment: emitComment, +- items: make(chan item), +- line: 1, +- startLine: 1, ++ name: name, ++ input: input, ++ leftDelim: left, ++ rightDelim: right, ++ emitComment: emitComment, ++ items: make(chan item), ++ line: 1, ++ startLine: 1, + } + go l.run() + return l +@@ -251,7 +248,7 @@ func lexText(l *lexer) stateFn { + ldn := Pos(len(l.leftDelim)) + l.pos += Pos(x) + trimLength := Pos(0) +- if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) { ++ if hasLeftTrimMarker(l.input[l.pos+ldn:]) { + trimLength = rightTrimLength(l.input[l.start:l.pos]) + } + l.pos -= trimLength +@@ -280,7 +277,7 @@ func rightTrimLength(s string) Pos { + + // atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker. + func (l *lexer) atRightDelim() (delim, trimSpaces bool) { +- if strings.HasPrefix(l.input[l.pos:], l.trimRightDelim) { // With trim marker. ++ if hasRightTrimMarker(l.input[l.pos:]) && strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) { // With trim marker. + return true, true + } + if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker. +@@ -297,7 +294,7 @@ func leftTrimLength(s string) Pos { + // lexLeftDelim scans the left delimiter, which is known to be present, possibly with a trim marker. + func lexLeftDelim(l *lexer) stateFn { + l.pos += Pos(len(l.leftDelim)) +- trimSpace := strings.HasPrefix(l.input[l.pos:], leftTrimMarker) ++ trimSpace := hasLeftTrimMarker(l.input[l.pos:]) + afterMarker := Pos(0) + if trimSpace { + afterMarker = trimMarkerLen +@@ -342,7 +339,7 @@ func lexComment(l *lexer) stateFn { + + // lexRightDelim scans the right delimiter, which is known to be present, possibly with a trim marker. + func lexRightDelim(l *lexer) stateFn { +- trimSpace := strings.HasPrefix(l.input[l.pos:], rightTrimMarker) ++ trimSpace := hasRightTrimMarker(l.input[l.pos:]) + if trimSpace { + l.pos += trimMarkerLen + l.ignore() +@@ -369,7 +366,7 @@ func lexInsideAction(l *lexer) stateFn { + return l.errorf("unclosed left paren") + } + switch r := l.next(); { +- case r == eof || isEndOfLine(r): ++ case r == eof: + return l.errorf("unclosed action") + case isSpace(r): + l.backup() // Put space back in case we have " -}}". +@@ -439,7 +436,7 @@ func lexSpace(l *lexer) stateFn { + } + // Be careful about a trim-marked closing delimiter, which has a minus + // after a space. We know there is a space, so check for the '-' that might follow. +- if strings.HasPrefix(l.input[l.pos-1:], l.trimRightDelim) { ++ if hasRightTrimMarker(l.input[l.pos-1:]) && strings.HasPrefix(l.input[l.pos-1+trimMarkerLen:], l.rightDelim) { + l.backup() // Before the space. + if numSpaces == 1 { + return lexRightDelim // On the delim, so go right to that. +@@ -526,7 +523,7 @@ func lexFieldOrVariable(l *lexer, typ itemType) stateFn { + // day to implement arithmetic. + func (l *lexer) atTerminator() bool { + r := l.peek() +- if isSpace(r) || isEndOfLine(r) { ++ if isSpace(r) { + return true + } + switch r { +@@ -657,15 +654,18 @@ Loop: + + // isSpace reports whether r is a space character. + func isSpace(r rune) bool { +- return r == ' ' || r == '\t' +-} +- +-// isEndOfLine reports whether r is an end-of-line character. +-func isEndOfLine(r rune) bool { +- return r == '\r' || r == '\n' ++ return r == ' ' || r == '\t' || r == '\r' || r == '\n' + } + + // isAlphaNumeric reports whether r is an alphabetic, digit, or underscore. + func isAlphaNumeric(r rune) bool { + return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) + } ++ ++func hasLeftTrimMarker(s string) bool { ++ return len(s) >= 2 && s[0] == trimMarker && isSpace(rune(s[1])) ++} ++ ++func hasRightTrimMarker(s string) bool { ++ return len(s) >= 2 && isSpace(rune(s[0])) && s[1] == trimMarker ++} +diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go +index f6d5f28..6510eed 100644 +--- a/src/text/template/parse/lex_test.go ++++ b/src/text/template/parse/lex_test.go +@@ -323,7 +323,7 @@ var lexTests = []lexTest{ + tLeft, + mkItem(itemError, "unrecognized character in action: U+0001"), + }}, +- {"unclosed action", "{{\n}}", []item{ ++ {"unclosed action", "{{", []item{ + tLeft, + mkItem(itemError, "unclosed action"), + }}, +diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go +index 496d8bf..5e6e512 100644 +--- a/src/text/template/parse/parse.go ++++ b/src/text/template/parse/parse.go +@@ -24,13 +24,14 @@ type Tree struct { + Mode Mode // parsing mode. + text string // text parsed to create the template (or its parent) + // Parsing only; cleared after parse. +- funcs []map[string]interface{} +- lex *lexer +- token [3]item // three-token lookahead for parser. +- peekCount int +- vars []string // variables defined at the moment. +- treeSet map[string]*Tree +- mode Mode ++ funcs []map[string]interface{} ++ lex *lexer ++ token [3]item // three-token lookahead for parser. ++ peekCount int ++ vars []string // variables defined at the moment. ++ treeSet map[string]*Tree ++ actionLine int // line of left delim starting action ++ mode Mode + } + + // A mode value is a set of flags (or 0). Modes control parser behavior. +@@ -187,6 +188,16 @@ func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { + + // unexpected complains about the token and terminates processing. + func (t *Tree) unexpected(token item, context string) { ++ if token.typ == itemError { ++ extra := "" ++ if t.actionLine != 0 && t.actionLine != token.line { ++ extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine) ++ if strings.HasSuffix(token.val, " action") { ++ extra = extra[len(" in action"):] // avoid "action in action" ++ } ++ } ++ t.errorf("%s%s", token, extra) ++ } + t.errorf("unexpected %s in %s", token, context) + } + +@@ -350,6 +361,8 @@ func (t *Tree) textOrAction() Node { + case itemText: + return t.newText(token.pos, token.val) + case itemLeftDelim: ++ t.actionLine = token.line ++ defer t.clearActionLine() + return t.action() + case itemComment: + return t.newComment(token.pos, token.val) +@@ -359,6 +372,10 @@ func (t *Tree) textOrAction() Node { + return nil + } + ++func (t *Tree) clearActionLine() { ++ t.actionLine = 0 ++} ++ + // Action: + // control + // command ("|" command)* +@@ -384,12 +401,12 @@ func (t *Tree) action() (n Node) { + t.backup() + token := t.peek() + // Do not pop variables; they persist until "end". +- return t.newAction(token.pos, token.line, t.pipeline("command")) ++ return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) + } + + // Pipeline: + // declarations? command ('|' command)* +-func (t *Tree) pipeline(context string) (pipe *PipeNode) { ++func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { + token := t.peekNonSpace() + pipe = t.newPipeline(token.pos, token.line, nil) + // Are there declarations or assignments? +@@ -430,12 +447,9 @@ decls: + } + for { + switch token := t.nextNonSpace(); token.typ { +- case itemRightDelim, itemRightParen: ++ case end: + // At this point, the pipeline is complete + t.checkPipeline(pipe, context) +- if token.typ == itemRightParen { +- t.backup() +- } + return + case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, + itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: +@@ -464,7 +478,7 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) { + + func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { + defer t.popVars(len(t.vars)) +- pipe = t.pipeline(context) ++ pipe = t.pipeline(context, itemRightDelim) + var next Node + list, next = t.itemList() + switch next.Type() { +@@ -550,7 +564,7 @@ func (t *Tree) blockControl() Node { + + token := t.nextNonSpace() + name := t.parseTemplateName(token, context) +- pipe := t.pipeline(context) ++ pipe := t.pipeline(context, itemRightDelim) + + block := New(name) // name will be updated once we know it. + block.text = t.text +@@ -580,7 +594,7 @@ func (t *Tree) templateControl() Node { + if t.nextNonSpace().typ != itemRightDelim { + t.backup() + // Do not pop variables; they persist until "end". +- pipe = t.pipeline(context) ++ pipe = t.pipeline(context, itemRightDelim) + } + return t.newTemplate(token.pos, token.line, name, pipe) + } +@@ -614,13 +628,12 @@ func (t *Tree) command() *CommandNode { + switch token := t.next(); token.typ { + case itemSpace: + continue +- case itemError: +- t.errorf("%s", token.val) + case itemRightDelim, itemRightParen: + t.backup() + case itemPipe: ++ // nothing here; break loop below + default: +- t.errorf("unexpected %s in operand", token) ++ t.unexpected(token, "operand") + } + break + } +@@ -675,8 +688,6 @@ func (t *Tree) operand() Node { + // A nil return means the next item is not a term. + func (t *Tree) term() Node { + switch token := t.nextNonSpace(); token.typ { +- case itemError: +- t.errorf("%s", token.val) + case itemIdentifier: + if !t.hasFunction(token.val) { + t.errorf("function %q not defined", token.val) +@@ -699,11 +710,7 @@ func (t *Tree) term() Node { + } + return number + case itemLeftParen: +- pipe := t.pipeline("parenthesized pipeline") +- if token := t.next(); token.typ != itemRightParen { +- t.errorf("unclosed right paren: unexpected %s", token) +- } +- return pipe ++ return t.pipeline("parenthesized pipeline", itemRightParen) + case itemString, itemRawString: + s, err := strconv.Unquote(token.val) + if err != nil { +diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go +index d9c13c5..220f984 100644 +--- a/src/text/template/parse/parse_test.go ++++ b/src/text/template/parse/parse_test.go +@@ -250,6 +250,13 @@ var parseTests = []parseTest{ + {"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`}, + {"block definition", `{{block "foo" .}}hello{{end}}`, noError, + `{{template "foo" .}}`}, ++ ++ {"newline in assignment", "{{ $x \n := \n 1 \n }}", noError, "{{$x := 1}}"}, ++ {"newline in empty action", "{{\n}}", hasError, "{{\n}}"}, ++ {"newline in pipeline", "{{\n\"x\"\n|\nprintf\n}}", noError, `{{"x" | printf}}`}, ++ {"newline in comment", "{{/*\nhello\n*/}}", noError, ""}, ++ {"newline in comment", "{{-\n/*\nhello\n*/\n-}}", noError, ""}, ++ + // Errors. + {"unclosed action", "hello{{range", hasError, ""}, + {"unmatched end", "{{end}}", hasError, ""}, +@@ -426,23 +433,38 @@ var errorTests = []parseTest{ + // Check line numbers are accurate. + {"unclosed1", + "line1\n{{", +- hasError, `unclosed1:2: unexpected unclosed action in command`}, ++ hasError, `unclosed1:2: unclosed action`}, + {"unclosed2", + "line1\n{{define `x`}}line2\n{{", +- hasError, `unclosed2:3: unexpected unclosed action in command`}, ++ hasError, `unclosed2:3: unclosed action`}, ++ {"unclosed3", ++ "line1\n{{\"x\"\n\"y\"\n", ++ hasError, `unclosed3:4: unclosed action started at unclosed3:2`}, ++ {"unclosed4", ++ "{{\n\n\n\n\n", ++ hasError, `unclosed4:6: unclosed action started at unclosed4:1`}, ++ {"var1", ++ "line1\n{{\nx\n}}", ++ hasError, `var1:3: function "x" not defined`}, + // Specific errors. + {"function", + "{{foo}}", + hasError, `function "foo" not defined`}, +- {"comment", ++ {"comment1", + "{{/*}}", +- hasError, `unclosed comment`}, ++ hasError, `comment1:1: unclosed comment`}, ++ {"comment2", ++ "{{/*\nhello\n}}", ++ hasError, `comment2:1: unclosed comment`}, + {"lparen", + "{{.X (1 2 3}}", + hasError, `unclosed left paren`}, + {"rparen", +- "{{.X 1 2 3)}}", +- hasError, `unexpected ")"`}, ++ "{{.X 1 2 3 ) }}", ++ hasError, `unexpected ")" in command`}, ++ {"rparen2", ++ "{{(.X 1 2 3", ++ hasError, `unclosed action`}, + {"space", + "{{`x`3}}", + hasError, `in operand`}, +@@ -488,7 +510,7 @@ var errorTests = []parseTest{ + hasError, `missing value for parenthesized pipeline`}, + {"multilinerawstring", + "{{ $v := `\n` }} {{", +- hasError, `multilinerawstring:2: unexpected unclosed action`}, ++ hasError, `multilinerawstring:2: unclosed action`}, + {"rangeundefvar", + "{{range $k}}{{end}}", + hasError, `undefined variable`}, +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_5.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_5.patch new file mode 100644 index 0000000000..fc38929648 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_5.patch @@ -0,0 +1,585 @@ +From e0e6bca6ddc0e6d9fa3a5b644af9b446924fbf83 Mon Sep 17 00:00:00 2001 +From: Russ Cox +Date: Thu, 20 May 2021 12:46:33 -0400 +Subject: [PATCH 5/6] html/template, text/template: implement break and + continue for range loops + +Break and continue for range loops was accepted as a proposal in June 2017. +It was implemented in CL 66410 (Oct 2017) +but then rolled back in CL 92155 (Feb 2018) +because html/template changes had not been implemented. + +This CL reimplements break and continue in text/template +and then adds support for them in html/template as well. + +Fixes #20531. + +Change-Id: I05330482a976f1c078b4b49c2287bd9031bb7616 +Reviewed-on: https://go-review.googlesource.com/c/go/+/321491 +Trust: Russ Cox +Run-TryBot: Russ Cox +TryBot-Result: Go Bot +Reviewed-by: Rob Pike + +Dependency Patch #5 + +Upstream-Status: Backport from https://github.com/golang/go/commit/d0dd26a88c019d54f22463daae81e785f5867565 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni +--- + src/html/template/context.go | 4 ++ + src/html/template/escape.go | 71 ++++++++++++++++++++++++++++++++++- + src/html/template/escape_test.go | 24 ++++++++++++ + src/text/template/doc.go | 8 ++++ + src/text/template/exec.go | 24 +++++++++++- + src/text/template/exec_test.go | 2 + + src/text/template/parse/lex.go | 13 ++++++- + src/text/template/parse/lex_test.go | 2 + + src/text/template/parse/node.go | 36 ++++++++++++++++++ + src/text/template/parse/parse.go | 42 ++++++++++++++++++++- + src/text/template/parse/parse_test.go | 8 ++++ + 11 files changed, 230 insertions(+), 4 deletions(-) + +diff --git a/src/html/template/context.go b/src/html/template/context.go +index f7d4849..aaa7d08 100644 +--- a/src/html/template/context.go ++++ b/src/html/template/context.go +@@ -6,6 +6,7 @@ package template + + import ( + "fmt" ++ "text/template/parse" + ) + + // context describes the state an HTML parser must be in when it reaches the +@@ -22,6 +23,7 @@ type context struct { + jsCtx jsCtx + attr attr + element element ++ n parse.Node // for range break/continue + err *Error + } + +@@ -141,6 +143,8 @@ const ( + // stateError is an infectious error state outside any valid + // HTML/CSS/JS construct. + stateError ++ // stateDead marks unreachable code after a {{break}} or {{continue}}. ++ stateDead + ) + + // isComment is true for any state that contains content meant for template +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index 8739735..6dea79c 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -97,6 +97,15 @@ type escaper struct { + actionNodeEdits map[*parse.ActionNode][]string + templateNodeEdits map[*parse.TemplateNode]string + textNodeEdits map[*parse.TextNode][]byte ++ // rangeContext holds context about the current range loop. ++ rangeContext *rangeContext ++} ++ ++// rangeContext holds information about the current range loop. ++type rangeContext struct { ++ outer *rangeContext // outer loop ++ breaks []context // context at each break action ++ continues []context // context at each continue action + } + + // makeEscaper creates a blank escaper for the given set. +@@ -109,6 +118,7 @@ func makeEscaper(n *nameSpace) escaper { + map[*parse.ActionNode][]string{}, + map[*parse.TemplateNode]string{}, + map[*parse.TextNode][]byte{}, ++ nil, + } + } + +@@ -124,8 +134,16 @@ func (e *escaper) escape(c context, n parse.Node) context { + switch n := n.(type) { + case *parse.ActionNode: + return e.escapeAction(c, n) ++ case *parse.BreakNode: ++ c.n = n ++ e.rangeContext.breaks = append(e.rangeContext.breaks, c) ++ return context{state: stateDead} + case *parse.CommentNode: + return c ++ case *parse.ContinueNode: ++ c.n = n ++ e.rangeContext.continues = append(e.rangeContext.breaks, c) ++ return context{state: stateDead} + case *parse.IfNode: + return e.escapeBranch(c, &n.BranchNode, "if") + case *parse.ListNode: +@@ -427,6 +445,12 @@ func join(a, b context, node parse.Node, nodeName string) context { + if b.state == stateError { + return b + } ++ if a.state == stateDead { ++ return b ++ } ++ if b.state == stateDead { ++ return a ++ } + if a.eq(b) { + return a + } +@@ -466,14 +490,27 @@ func join(a, b context, node parse.Node, nodeName string) context { + + // escapeBranch escapes a branch template node: "if", "range" and "with". + func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context { ++ if nodeName == "range" { ++ e.rangeContext = &rangeContext{outer: e.rangeContext} ++ } + c0 := e.escapeList(c, n.List) +- if nodeName == "range" && c0.state != stateError { ++ if nodeName == "range" { ++ if c0.state != stateError { ++ c0 = joinRange(c0, e.rangeContext) ++ } ++ e.rangeContext = e.rangeContext.outer ++ if c0.state == stateError { ++ return c0 ++ } ++ + // The "true" branch of a "range" node can execute multiple times. + // We check that executing n.List once results in the same context + // as executing n.List twice. ++ e.rangeContext = &rangeContext{outer: e.rangeContext} + c1, _ := e.escapeListConditionally(c0, n.List, nil) + c0 = join(c0, c1, n, nodeName) + if c0.state == stateError { ++ e.rangeContext = e.rangeContext.outer + // Make clear that this is a problem on loop re-entry + // since developers tend to overlook that branch when + // debugging templates. +@@ -481,11 +518,39 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) + c0.err.Description = "on range loop re-entry: " + c0.err.Description + return c0 + } ++ c0 = joinRange(c0, e.rangeContext) ++ e.rangeContext = e.rangeContext.outer ++ if c0.state == stateError { ++ return c0 ++ } + } + c1 := e.escapeList(c, n.ElseList) + return join(c0, c1, n, nodeName) + } + ++func joinRange(c0 context, rc *rangeContext) context { ++ // Merge contexts at break and continue statements into overall body context. ++ // In theory we could treat breaks differently from continues, but for now it is ++ // enough to treat them both as going back to the start of the loop (which may then stop). ++ for _, c := range rc.breaks { ++ c0 = join(c0, c, c.n, "range") ++ if c0.state == stateError { ++ c0.err.Line = c.n.(*parse.BreakNode).Line ++ c0.err.Description = "at range loop break: " + c0.err.Description ++ return c0 ++ } ++ } ++ for _, c := range rc.continues { ++ c0 = join(c0, c, c.n, "range") ++ if c0.state == stateError { ++ c0.err.Line = c.n.(*parse.ContinueNode).Line ++ c0.err.Description = "at range loop continue: " + c0.err.Description ++ return c0 ++ } ++ } ++ return c0 ++} ++ + // escapeList escapes a list template node. + func (e *escaper) escapeList(c context, n *parse.ListNode) context { + if n == nil { +@@ -493,6 +558,9 @@ func (e *escaper) escapeList(c context, n *parse.ListNode) context { + } + for _, m := range n.Nodes { + c = e.escape(c, m) ++ if c.state == stateDead { ++ break ++ } + } + return c + } +@@ -503,6 +571,7 @@ func (e *escaper) escapeList(c context, n *parse.ListNode) context { + // which is the same as whether e was updated. + func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) { + e1 := makeEscaper(e.ns) ++ e1.rangeContext = e.rangeContext + // Make type inferences available to f. + for k, v := range e.output { + e1.output[k] = v +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index c709660..fa2b84a 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -920,6 +920,22 @@ func TestErrors(t *testing.T) { + "", + "", + }, ++ { ++ "{{range .Items}}{{end}}", ++ "", ++ }, ++ { ++ "{{range .Items}}{{continue}}{{end}}", ++ "", ++ }, ++ { ++ "{{range .Items}}{{break}}{{end}}", ++ "", ++ }, ++ { ++ "{{range .Items}}{{if .X}}{{break}}{{end}}{{end}}", ++ "", ++ }, + // Error cases. + { + "{{if .Cond}}{{end}}", ++ "z:1:29: at range loop break: {{range}} branches end in different contexts", ++ }, ++ { ++ "{{range .Items}}{{end}}", ++ "z:1:29: at range loop continue: {{range}} branches end in different contexts", ++ }, ++ { + " 1 { + s.setTopVar(2, index) + } ++ defer s.pop(mark) ++ defer func() { ++ // Consume panic(walkContinue) ++ if r := recover(); r != nil && r != walkContinue { ++ panic(r) ++ } ++ }() + s.walk(elem, r.List) +- s.pop(mark) + } + switch val.Kind() { + case reflect.Array, reflect.Slice: +diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go +index 3309b33..a639f44 100644 +--- a/src/text/template/exec_test.go ++++ b/src/text/template/exec_test.go +@@ -563,6 +563,8 @@ var execTests = []execTest{ + {"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true}, + {"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true}, + {"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true}, ++ {"range []int break else", "{{range .SI}}-{{.}}-{{break}}NOTREACHED{{else}}EMPTY{{end}}", "-3-", tVal, true}, ++ {"range []int continue else", "{{range .SI}}-{{.}}-{{continue}}NOTREACHED{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true}, + {"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true}, + {"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true}, + {"range map", "{{range .MSI}}-{{.}}-{{end}}", "-1--3--2-", tVal, true}, +diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go +index 6784071..95e3377 100644 +--- a/src/text/template/parse/lex.go ++++ b/src/text/template/parse/lex.go +@@ -62,6 +62,8 @@ const ( + // Keywords appear after all the rest. + itemKeyword // used only to delimit the keywords + itemBlock // block keyword ++ itemBreak // break keyword ++ itemContinue // continue keyword + itemDot // the cursor, spelled '.' + itemDefine // define keyword + itemElse // else keyword +@@ -76,6 +78,8 @@ const ( + var key = map[string]itemType{ + ".": itemDot, + "block": itemBlock, ++ "break": itemBreak, ++ "continue": itemContinue, + "define": itemDefine, + "else": itemElse, + "end": itemEnd, +@@ -119,6 +123,8 @@ type lexer struct { + parenDepth int // nesting depth of ( ) exprs + line int // 1+number of newlines seen + startLine int // start line of this item ++ breakOK bool // break keyword allowed ++ continueOK bool // continue keyword allowed + } + + // next returns the next rune in the input. +@@ -461,7 +467,12 @@ Loop: + } + switch { + case key[word] > itemKeyword: +- l.emit(key[word]) ++ item := key[word] ++ if item == itemBreak && !l.breakOK || item == itemContinue && !l.continueOK { ++ l.emit(itemIdentifier) ++ } else { ++ l.emit(item) ++ } + case word[0] == '.': + l.emit(itemField) + case word == "true", word == "false": +diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go +index 6510eed..df6aabf 100644 +--- a/src/text/template/parse/lex_test.go ++++ b/src/text/template/parse/lex_test.go +@@ -35,6 +35,8 @@ var itemName = map[itemType]string{ + // keywords + itemDot: ".", + itemBlock: "block", ++ itemBreak: "break", ++ itemContinue: "continue", + itemDefine: "define", + itemElse: "else", + itemIf: "if", +diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go +index a9dad5e..c398da0 100644 +--- a/src/text/template/parse/node.go ++++ b/src/text/template/parse/node.go +@@ -71,6 +71,8 @@ const ( + NodeVariable // A $ variable. + NodeWith // A with action. + NodeComment // A comment. ++ NodeBreak // A break action. ++ NodeContinue // A continue action. + ) + + // Nodes. +@@ -907,6 +909,40 @@ func (i *IfNode) Copy() Node { + return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList()) + } + ++// BreakNode represents a {{break}} action. ++type BreakNode struct { ++ tr *Tree ++ NodeType ++ Pos ++ Line int ++} ++ ++func (t *Tree) newBreak(pos Pos, line int) *BreakNode { ++ return &BreakNode{tr: t, NodeType: NodeBreak, Pos: pos, Line: line} ++} ++ ++func (b *BreakNode) Copy() Node { return b.tr.newBreak(b.Pos, b.Line) } ++func (b *BreakNode) String() string { return "{{break}}" } ++func (b *BreakNode) tree() *Tree { return b.tr } ++func (b *BreakNode) writeTo(sb *strings.Builder) { sb.WriteString("{{break}}") } ++ ++// ContinueNode represents a {{continue}} action. ++type ContinueNode struct { ++ tr *Tree ++ NodeType ++ Pos ++ Line int ++} ++ ++func (t *Tree) newContinue(pos Pos, line int) *ContinueNode { ++ return &ContinueNode{tr: t, NodeType: NodeContinue, Pos: pos, Line: line} ++} ++ ++func (c *ContinueNode) Copy() Node { return c.tr.newContinue(c.Pos, c.Line) } ++func (c *ContinueNode) String() string { return "{{continue}}" } ++func (c *ContinueNode) tree() *Tree { return c.tr } ++func (c *ContinueNode) writeTo(sb *strings.Builder) { sb.WriteString("{{continue}}") } ++ + // RangeNode represents a {{range}} action and its commands. + type RangeNode struct { + BranchNode +diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go +index 5e6e512..7f78b56 100644 +--- a/src/text/template/parse/parse.go ++++ b/src/text/template/parse/parse.go +@@ -31,6 +31,7 @@ type Tree struct { + vars []string // variables defined at the moment. + treeSet map[string]*Tree + actionLine int // line of left delim starting action ++ rangeDepth int + mode Mode + } + +@@ -223,6 +224,8 @@ func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet ma + t.vars = []string{"$"} + t.funcs = funcs + t.treeSet = treeSet ++ lex.breakOK = !t.hasFunction("break") ++ lex.continueOK = !t.hasFunction("continue") + } + + // stopParse terminates parsing. +@@ -385,6 +388,10 @@ func (t *Tree) action() (n Node) { + switch token := t.nextNonSpace(); token.typ { + case itemBlock: + return t.blockControl() ++ case itemBreak: ++ return t.breakControl(token.pos, token.line) ++ case itemContinue: ++ return t.continueControl(token.pos, token.line) + case itemElse: + return t.elseControl() + case itemEnd: +@@ -404,6 +411,32 @@ func (t *Tree) action() (n Node) { + return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) + } + ++// Break: ++// {{break}} ++// Break keyword is past. ++func (t *Tree) breakControl(pos Pos, line int) Node { ++ if token := t.next(); token.typ != itemRightDelim { ++ t.unexpected(token, "in {{break}}") ++ } ++ if t.rangeDepth == 0 { ++ t.errorf("{{break}} outside {{range}}") ++ } ++ return t.newBreak(pos, line) ++} ++ ++// Continue: ++// {{continue}} ++// Continue keyword is past. ++func (t *Tree) continueControl(pos Pos, line int) Node { ++ if token := t.next(); token.typ != itemRightDelim { ++ t.unexpected(token, "in {{continue}}") ++ } ++ if t.rangeDepth == 0 { ++ t.errorf("{{continue}} outside {{range}}") ++ } ++ return t.newContinue(pos, line) ++} ++ + // Pipeline: + // declarations? command ('|' command)* + func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { +@@ -479,8 +512,14 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) { + func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { + defer t.popVars(len(t.vars)) + pipe = t.pipeline(context, itemRightDelim) ++ if context == "range" { ++ t.rangeDepth++ ++ } + var next Node + list, next = t.itemList() ++ if context == "range" { ++ t.rangeDepth-- ++ } + switch next.Type() { + case nodeEnd: //done + case nodeElse: +@@ -522,7 +561,8 @@ func (t *Tree) ifControl() Node { + // {{range pipeline}} itemList {{else}} itemList {{end}} + // Range keyword is past. + func (t *Tree) rangeControl() Node { +- return t.newRange(t.parseControl(false, "range")) ++ r := t.newRange(t.parseControl(false, "range")) ++ return r + } + + // With: +diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go +index 220f984..ba45636 100644 +--- a/src/text/template/parse/parse_test.go ++++ b/src/text/template/parse/parse_test.go +@@ -230,6 +230,10 @@ var parseTests = []parseTest{ + `{{range $x := .SI}}{{.}}{{end}}`}, + {"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError, + `{{range $x, $y := .SI}}{{.}}{{end}}`}, ++ {"range with break", "{{range .SI}}{{.}}{{break}}{{end}}", noError, ++ `{{range .SI}}{{.}}{{break}}{{end}}`}, ++ {"range with continue", "{{range .SI}}{{.}}{{continue}}{{end}}", noError, ++ `{{range .SI}}{{.}}{{continue}}{{end}}`}, + {"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError, + `{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`}, + {"template", "{{template `x`}}", noError, +@@ -279,6 +283,10 @@ var parseTests = []parseTest{ + {"adjacent args", "{{printf 3`x`}}", hasError, ""}, + {"adjacent args with .", "{{printf `x`.}}", hasError, ""}, + {"extra end after if", "{{if .X}}a{{else if .Y}}b{{end}}{{end}}", hasError, ""}, ++ {"break outside range", "{{range .}}{{end}} {{break}}", hasError, ""}, ++ {"continue outside range", "{{range .}}{{end}} {{continue}}", hasError, ""}, ++ {"break in range else", "{{range .}}{{else}}{{break}}{{end}}", hasError, ""}, ++ {"continue in range else", "{{range .}}{{else}}{{continue}}{{end}}", hasError, ""}, + // Other kinds of assignments and operators aren't available yet. + {"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"}, + {"bug0b", "{{$x += 1}}{{$x}}", hasError, ""}, +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-3.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_6.patch similarity index 53% rename from meta/recipes-devtools/go/go-1.14/CVE-2023-24538-3.patch rename to meta/recipes-devtools/go/go-1.14/CVE-2023-24538_6.patch index d5bb33e091..baf400b891 100644 --- a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-3.patch +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_6.patch @@ -1,7 +1,7 @@ From 16f4882984569f179d73967c9eee679bb9b098c5 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 20 Mar 2023 11:01:13 -0700 -Subject: [PATCH 3/3] html/template: disallow actions in JS template literals +Subject: [PATCH 6/6] html/template: disallow actions in JS template literals ECMAScript 6 introduced template literals[0][1] which are delimited with backticks. These need to be escaped in a similar fashion to the @@ -52,12 +52,15 @@ CVE: CVE-2023-24538 Signed-off-by: Shubham Kulkarni --- src/html/template/context.go | 2 ++ - src/html/template/error.go | 13 +++++++++++++ - src/html/template/escape.go | 11 +++++++++++ + src/html/template/error.go | 13 ++++++++ + src/html/template/escape.go | 11 +++++++ + src/html/template/escape_test.go | 66 ++++++++++++++++++++++----------------- src/html/template/js.go | 2 ++ - src/html/template/jsctx_string.go | 9 +++++++++ - src/html/template/transition.go | 7 ++++++- - 6 files changed, 43 insertions(+), 1 deletion(-) + src/html/template/js_test.go | 2 +- + src/html/template/jsctx_string.go | 9 ++++++ + src/html/template/state_string.go | 37 ++++++++++++++++++++-- + src/html/template/transition.go | 7 ++++- + 9 files changed, 116 insertions(+), 33 deletions(-) diff --git a/src/html/template/context.go b/src/html/template/context.go index f7d4849..0b65313 100644 @@ -125,6 +128,104 @@ index f12dafa..29ca5b3 100644 case stateJSRegexp: s = append(s, "_html_template_jsregexpescaper") case stateCSS: +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index fa2b84a..1b150e9 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -681,35 +681,31 @@ func TestEscape(t *testing.T) { + } + + for _, test := range tests { +- tmpl := New(test.name) +- tmpl = Must(tmpl.Parse(test.input)) +- // Check for bug 6459: Tree field was not set in Parse. +- if tmpl.Tree != tmpl.text.Tree { +- t.Errorf("%s: tree not set properly", test.name) +- continue +- } +- b := new(bytes.Buffer) +- if err := tmpl.Execute(b, data); err != nil { +- t.Errorf("%s: template execution failed: %s", test.name, err) +- continue +- } +- if w, g := test.output, b.String(); w != g { +- t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) +- continue +- } +- b.Reset() +- if err := tmpl.Execute(b, pdata); err != nil { +- t.Errorf("%s: template execution failed for pointer: %s", test.name, err) +- continue +- } +- if w, g := test.output, b.String(); w != g { +- t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) +- continue +- } +- if tmpl.Tree != tmpl.text.Tree { +- t.Errorf("%s: tree mismatch", test.name) +- continue +- } ++ t.Run(test.name, func(t *testing.T) { ++ tmpl := New(test.name) ++ tmpl = Must(tmpl.Parse(test.input)) ++ // Check for bug 6459: Tree field was not set in Parse. ++ if tmpl.Tree != tmpl.text.Tree { ++ t.Fatalf("%s: tree not set properly", test.name) ++ } ++ b := new(strings.Builder) ++ if err := tmpl.Execute(b, data); err != nil { ++ t.Fatalf("%s: template execution failed: %s", test.name, err) ++ } ++ if w, g := test.output, b.String(); w != g { ++ t.Fatalf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) ++ } ++ b.Reset() ++ if err := tmpl.Execute(b, pdata); err != nil { ++ t.Fatalf("%s: template execution failed for pointer: %s", test.name, err) ++ } ++ if w, g := test.output, b.String(); w != g { ++ t.Fatalf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) ++ } ++ if tmpl.Tree != tmpl.text.Tree { ++ t.Fatalf("%s: tree mismatch", test.name) ++ } ++ }) + } + } + +@@ -936,6 +932,10 @@ func TestErrors(t *testing.T) { + "{{range .Items}}{{if .X}}{{break}}{{end}}{{end}}", + "", + }, ++ { ++ "`", ++ "", ++ }, + // Error cases. + { + "{{if .Cond}}var tmpl = `asd {{.}}`;", ++ `{{.}} appears in a JS template literal`, ++ }, + } + for _, test := range tests { + buf := new(bytes.Buffer) +@@ -1304,6 +1308,10 @@ func TestEscapeText(t *testing.T) { + context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript}, + }, + { ++ "= state(len(_state_index)-1) { diff --git a/src/html/template/transition.go b/src/html/template/transition.go index 06df679..92eb351 100644 --- a/src/html/template/transition.go diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-39318.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-39318.patch index 20e70c0485..00def8fcda 100644 --- a/meta/recipes-devtools/go/go-1.14/CVE-2023-39318.patch +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-39318.patch @@ -34,9 +34,9 @@ Signed-off-by: Siddharth Doshi src/html/template/context.go | 6 ++- src/html/template/escape.go | 5 +- src/html/template/escape_test.go | 10 ++++ - src/html/template/state_string.go | 4 +- + src/html/template/state_string.go | 26 +++++----- src/html/template/transition.go | 80 ++++++++++++++++++++----------- - 5 files changed, 72 insertions(+), 33 deletions(-) + 5 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/html/template/context.go b/src/html/template/context.go index 0b65313..4eb7891 100644 @@ -105,14 +105,38 @@ diff --git a/src/html/template/state_string.go b/src/html/template/state_string. index 05104be..b5cfe70 100644 --- a/src/html/template/state_string.go +++ b/src/html/template/state_string.go -@@ -4,9 +4,9 @@ package template - - import "strconv" +@@ -25,21 +25,23 @@ func _() { + _ = x[stateJSRegexp-14] + _ = x[stateJSBlockCmt-15] + _ = x[stateJSLineCmt-16] +- _ = x[stateCSS-17] +- _ = x[stateCSSDqStr-18] +- _ = x[stateCSSSqStr-19] +- _ = x[stateCSSDqURL-20] +- _ = x[stateCSSSqURL-21] +- _ = x[stateCSSURL-22] +- _ = x[stateCSSBlockCmt-23] +- _ = x[stateCSSLineCmt-24] +- _ = x[stateError-25] +- _ = x[stateDead-26] ++ _ = x[stateJSHTMLOpenCmt-17] ++ _ = x[stateJSHTMLCloseCmt-18] ++ _ = x[stateCSS-19] ++ _ = x[stateCSSDqStr-20] ++ _ = x[stateCSSSqStr-21] ++ _ = x[stateCSSDqURL-22] ++ _ = x[stateCSSSqURL-23] ++ _ = x[stateCSSURL-24] ++ _ = x[stateCSSBlockCmt-25] ++ _ = x[stateCSSLineCmt-26] ++ _ = x[stateError-27] ++ _ = x[stateDead-28] + } --const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateError" +-const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" +const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateJSHTMLOpenCmtstateJSHTMLCloseCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" --var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 155, 170, 184, 192, 205, 218, 231, 244, 255, 271, 286, 296} +-var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 154, 167, 182, 196, 204, 217, 230, 243, 256, 267, 283, 298, 308, 317} +var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 154, 167, 182, 196, 214, 233, 241, 254, 267, 280, 293, 304, 320, 335, 345, 354} func (i state) String() string {