summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/go/go-1.21
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/go/go-1.21')
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2023-24531_1.patch252
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2023-24531_2.patch47
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2023-39318.patch262
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2023-45289.patch121
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2023-45290.patch270
5 files changed, 952 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2023-24531_1.patch b/meta/recipes-devtools/go/go-1.21/CVE-2023-24531_1.patch
new file mode 100644
index 0000000000..5f6d7e16a8
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.21/CVE-2023-24531_1.patch
@@ -0,0 +1,252 @@
+From 0f717b5f7d32bb660c01ec0366bd53c9b4c5ab5d Mon Sep 17 00:00:00 2001
+From: Michael Matloob <matloob@golang.org>
+Date: Mon, 24 Apr 2023 16:57:28 -0400
+Subject: [PATCH 1/2] cmd/go: sanitize go env outputs
+
+go env, without any arguments, outputs the environment variables in
+the form of a script that can be run on the host OS. On Unix, single
+quote the strings and place single quotes themselves outside the
+single quoted strings. On windows use the set "var=val" syntax with
+the quote starting before the variable.
+
+Fixes #58508
+
+Change-Id: Iecd379a4af7285ea9b2024f0202250c74fd9a2bd
+Reviewed-on: https://go-review.googlesource.com/c/go/+/488375
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Reviewed-by: Michael Matloob <matloob@golang.org>
+Reviewed-by: Damien Neil <dneil@google.com>
+Run-TryBot: Michael Matloob <matloob@golang.org>
+Reviewed-by: Bryan Mills <bcmills@google.com>
+Reviewed-by: Quim Muntal <quimmuntal@gmail.com>
+
+CVE: CVE-2023-24531
+Upstream-Status: Backport [f379e78951a405e7e99a60fb231eeedbf976c108]
+
+Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
+---
+ src/cmd/go/internal/envcmd/env.go | 60 ++++++++++++-
+ src/cmd/go/internal/envcmd/env_test.go | 94 +++++++++++++++++++++
+ src/cmd/go/testdata/script/env_sanitize.txt | 5 ++
+ 3 files changed, 157 insertions(+), 2 deletions(-)
+ create mode 100644 src/cmd/go/internal/envcmd/env_test.go
+ create mode 100644 src/cmd/go/testdata/script/env_sanitize.txt
+
+diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
+index 43b94e7..0ce8843 100644
+--- a/src/cmd/go/internal/envcmd/env.go
++++ b/src/cmd/go/internal/envcmd/env.go
+@@ -6,6 +6,7 @@
+ package envcmd
+
+ import (
++ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+@@ -17,6 +18,7 @@ import (
+ "runtime"
+ "sort"
+ "strings"
++ "unicode"
+ "unicode/utf8"
+
+ "cmd/go/internal/base"
+@@ -379,9 +381,12 @@ func checkBuildConfig(add map[string]string, del map[string]bool) error {
+ func PrintEnv(w io.Writer, env []cfg.EnvVar) {
+ for _, e := range env {
+ if e.Name != "TERM" {
++ if runtime.GOOS != "plan9" && bytes.Contains([]byte(e.Value), []byte{0}) {
++ base.Fatalf("go: internal error: encountered null byte in environment variable %s on non-plan9 platform", e.Name)
++ }
+ switch runtime.GOOS {
+ default:
+- fmt.Fprintf(w, "%s=\"%s\"\n", e.Name, e.Value)
++ fmt.Fprintf(w, "%s=%s\n", e.Name, shellQuote(e.Value))
+ case "plan9":
+ if strings.IndexByte(e.Value, '\x00') < 0 {
+ fmt.Fprintf(w, "%s='%s'\n", e.Name, strings.ReplaceAll(e.Value, "'", "''"))
+@@ -392,17 +397,68 @@ func PrintEnv(w io.Writer, env []cfg.EnvVar) {
+ if x > 0 {
+ fmt.Fprintf(w, " ")
+ }
++ // TODO(#59979): Does this need to be quoted like above?
+ fmt.Fprintf(w, "%s", s)
+ }
+ fmt.Fprintf(w, ")\n")
+ }
+ case "windows":
+- fmt.Fprintf(w, "set %s=%s\n", e.Name, e.Value)
++ if hasNonGraphic(e.Value) {
++ base.Errorf("go: stripping unprintable or unescapable characters from %%%q%%", e.Name)
++ }
++ fmt.Fprintf(w, "set %s=%s\n", e.Name, batchEscape(e.Value))
+ }
+ }
+ }
+ }
+
++func hasNonGraphic(s string) bool {
++ for _, c := range []byte(s) {
++ if c == '\r' || c == '\n' || (!unicode.IsGraphic(rune(c)) && !unicode.IsSpace(rune(c))) {
++ return true
++ }
++ }
++ return false
++}
++
++func shellQuote(s string) string {
++ var b bytes.Buffer
++ b.WriteByte('\'')
++ for _, x := range []byte(s) {
++ if x == '\'' {
++ // Close the single quoted string, add an escaped single quote,
++ // and start another single quoted string.
++ b.WriteString(`'\''`)
++ } else {
++ b.WriteByte(x)
++ }
++ }
++ b.WriteByte('\'')
++ return b.String()
++}
++
++func batchEscape(s string) string {
++ var b bytes.Buffer
++ for _, x := range []byte(s) {
++ if x == '\r' || x == '\n' || (!unicode.IsGraphic(rune(x)) && !unicode.IsSpace(rune(x))) {
++ b.WriteRune(unicode.ReplacementChar)
++ continue
++ }
++ switch x {
++ case '%':
++ b.WriteString("%%")
++ case '<', '>', '|', '&', '^':
++ // These are special characters that need to be escaped with ^. See
++ // https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/set_1.
++ b.WriteByte('^')
++ b.WriteByte(x)
++ default:
++ b.WriteByte(x)
++ }
++ }
++ return b.String()
++}
++
+ func printEnvAsJSON(env []cfg.EnvVar) {
+ m := make(map[string]string)
+ for _, e := range env {
+diff --git a/src/cmd/go/internal/envcmd/env_test.go b/src/cmd/go/internal/envcmd/env_test.go
+new file mode 100644
+index 0000000..32d99fd
+--- /dev/null
++++ b/src/cmd/go/internal/envcmd/env_test.go
+@@ -0,0 +1,94 @@
++// Copyright 2022 The Go Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style
++// license that can be found in the LICENSE file.
++
++//go:build unix || windows
++
++package envcmd
++
++import (
++ "bytes"
++ "cmd/go/internal/cfg"
++ "fmt"
++ "internal/testenv"
++ "os"
++ "os/exec"
++ "path/filepath"
++ "runtime"
++ "testing"
++ "unicode"
++)
++
++func FuzzPrintEnvEscape(f *testing.F) {
++ f.Add(`$(echo 'cc"'; echo 'OOPS="oops')`)
++ f.Add("$(echo shell expansion 1>&2)")
++ f.Add("''")
++ f.Add(`C:\"Program Files"\`)
++ f.Add(`\\"Quoted Host"\\share`)
++ f.Add("\xfb")
++ f.Add("0")
++ f.Add("")
++ f.Add("''''''''")
++ f.Add("\r")
++ f.Add("\n")
++ f.Add("E,%")
++ f.Fuzz(func(t *testing.T, s string) {
++ t.Parallel()
++
++ for _, c := range []byte(s) {
++ if c == 0 {
++ t.Skipf("skipping %q: contains a null byte. Null bytes can't occur in the environment"+
++ " outside of Plan 9, which has different code path than Windows and Unix that this test"+
++ " isn't testing.", s)
++ }
++ if c > unicode.MaxASCII {
++ t.Skipf("skipping %#q: contains a non-ASCII character %q", s, c)
++ }
++ if !unicode.IsGraphic(rune(c)) && !unicode.IsSpace(rune(c)) {
++ t.Skipf("skipping %#q: contains non-graphic character %q", s, c)
++ }
++ if runtime.GOOS == "windows" && c == '\r' || c == '\n' {
++ t.Skipf("skipping %#q on Windows: contains unescapable character %q", s, c)
++ }
++ }
++
++ var b bytes.Buffer
++ if runtime.GOOS == "windows" {
++ b.WriteString("@echo off\n")
++ }
++ PrintEnv(&b, []cfg.EnvVar{{Name: "var", Value: s}})
++ var want string
++ if runtime.GOOS == "windows" {
++ fmt.Fprintf(&b, "echo \"%%var%%\"\n")
++ want += "\"" + s + "\"\r\n"
++ } else {
++ fmt.Fprintf(&b, "printf '%%s\\n' \"$var\"\n")
++ want += s + "\n"
++ }
++ scriptfilename := "script.sh"
++ if runtime.GOOS == "windows" {
++ scriptfilename = "script.bat"
++ }
++ scriptfile := filepath.Join(t.TempDir(), scriptfilename)
++ if err := os.WriteFile(scriptfile, b.Bytes(), 0777); err != nil {
++ t.Fatal(err)
++ }
++ t.Log(b.String())
++ var cmd *exec.Cmd
++ if runtime.GOOS == "windows" {
++ cmd = testenv.Command(t, "cmd.exe", "/C", scriptfile)
++ } else {
++ cmd = testenv.Command(t, "sh", "-c", scriptfile)
++ }
++ out, err := cmd.Output()
++ t.Log(string(out))
++ if err != nil {
++ t.Fatal(err)
++ }
++
++ if string(out) != want {
++ t.Fatalf("output of running PrintEnv script and echoing variable: got: %q, want: %q",
++ string(out), want)
++ }
++ })
++}
+diff --git a/src/cmd/go/testdata/script/env_sanitize.txt b/src/cmd/go/testdata/script/env_sanitize.txt
+new file mode 100644
+index 0000000..cc4d23a
+--- /dev/null
++++ b/src/cmd/go/testdata/script/env_sanitize.txt
+@@ -0,0 +1,5 @@
++env GOFLAGS='$(echo ''cc"''; echo ''OOPS="oops'')'
++go env
++[GOOS:darwin] stdout 'GOFLAGS=''\$\(echo ''\\''''cc"''\\''''; echo ''\\''''OOPS="oops''\\''''\)'''
++[GOOS:linux] stdout 'GOFLAGS=''\$\(echo ''\\''''cc"''\\''''; echo ''\\''''OOPS="oops''\\''''\)'''
++[GOOS:windows] stdout 'set GOFLAGS=\$\(echo ''cc"''; echo ''OOPS="oops''\)'
+--
+2.35.5
+
diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2023-24531_2.patch b/meta/recipes-devtools/go/go-1.21/CVE-2023-24531_2.patch
new file mode 100644
index 0000000000..eecc04c2e3
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.21/CVE-2023-24531_2.patch
@@ -0,0 +1,47 @@
+From b2624f973692ca093348395c2418d1c422f2a162 Mon Sep 17 00:00:00 2001
+From: miller <millerresearch@gmail.com>
+Date: Mon, 8 May 2023 16:56:21 +0100
+Subject: [PATCH 2/2] cmd/go: quote entries in list-valued variables for go env
+ in plan9
+
+When 'go env' without an argument prints environment variables as
+a script which can be executed by the shell, variables with a
+list value in Plan 9 (such as GOPATH) need to be printed with each
+element enclosed in single quotes in case it contains characters
+significant to the Plan 9 shell (such as ' ' or '=').
+
+For #58508
+
+Change-Id: Ia30f51307cc6d07a7e3ada6bf9d60bf9951982ff
+Reviewed-on: https://go-review.googlesource.com/c/go/+/493535
+Run-TryBot: Cherry Mui <cherryyz@google.com>
+Reviewed-by: Cherry Mui <cherryyz@google.com>
+Reviewed-by: Russ Cox <rsc@golang.org>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
+
+CVE: CVE-2023-24531
+Upstream-Status: Backport [05cc9e55876874462a4726ca0101c970838c80e5]
+
+Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
+---
+ src/cmd/go/internal/envcmd/env.go | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
+index 0ce8843..b48d0bd 100644
+--- a/src/cmd/go/internal/envcmd/env.go
++++ b/src/cmd/go/internal/envcmd/env.go
+@@ -397,8 +397,7 @@ func PrintEnv(w io.Writer, env []cfg.EnvVar) {
+ if x > 0 {
+ fmt.Fprintf(w, " ")
+ }
+- // TODO(#59979): Does this need to be quoted like above?
+- fmt.Fprintf(w, "%s", s)
++ fmt.Fprintf(w, "'%s'", strings.ReplaceAll(s, "'", "''"))
+ }
+ fmt.Fprintf(w, ")\n")
+ }
+--
+2.35.5
+
diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2023-39318.patch b/meta/recipes-devtools/go/go-1.21/CVE-2023-39318.patch
new file mode 100644
index 0000000000..503a4a288a
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.21/CVE-2023-39318.patch
@@ -0,0 +1,262 @@
+From 023b542edf38e2a1f87fcefb9f75ff2f99401b4c Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Thu, 3 Aug 2023 12:24:13 -0700
+Subject: [PATCH] [release-branch.go1.20] html/template: support HTML-like
+ comments in script contexts
+
+Per Appendix B.1.1 of the ECMAScript specification, support HTML-like
+comments in script contexts. Also per section 12.5, support hashbang
+comments. This brings our parsing in-line with how browsers treat these
+comment types.
+
+Thanks to Takeshi Kaneko (GMO Cybersecurity by Ierae, Inc.) for
+reporting this issue.
+
+Fixes #62196
+Fixes #62395
+Fixes CVE-2023-39318
+
+Change-Id: Id512702c5de3ae46cf648e268cb10e1eb392a181
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1976593
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2014620
+Reviewed-on: https://go-review.googlesource.com/c/go/+/526098
+Run-TryBot: Cherry Mui <cherryyz@google.com>
+TryBot-Result: Gopher Robot <gobot@golang.org>
+
+Upstream-Status: Backport from [https://github.com/golang/go/commit/023b542edf38e2a1f87fcefb9f75ff2f99401b4c]
+CVE: CVE-2023-39318
+Signed-off-by: Siddharth Doshi <sdoshi@mvista.com>
+---
+ 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 | 26 +++++++------
+ src/html/template/transition.go | 80 +++++++++++++++++++++++++--------------
+ 5 files changed, 84 insertions(+), 43 deletions(-)
+
+diff --git a/src/html/template/context.go b/src/html/template/context.go
+index f5f44a1..feb6517 100644
+--- a/src/html/template/context.go
++++ b/src/html/template/context.go
+@@ -124,6 +124,10 @@ const (
+ stateJSBlockCmt
+ // stateJSLineCmt occurs inside a JavaScript // line comment.
+ stateJSLineCmt
++ // stateJSHTMLOpenCmt occurs inside a JavaScript <!-- HTML-like comment.
++ stateJSHTMLOpenCmt
++ // stateJSHTMLCloseCmt occurs inside a JavaScript --> HTML-like comment.
++ stateJSHTMLCloseCmt
+ // stateCSS occurs inside a <style> element or style attribute.
+ stateCSS
+ // stateCSSDqStr occurs inside a CSS double quoted string.
+@@ -149,7 +153,7 @@ const (
+ // authors & maintainers, not for end-users or machines.
+ func isComment(s state) bool {
+ switch s {
+- case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateCSSBlockCmt, stateCSSLineCmt:
++ case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateJSHTMLOpenCmt, stateJSHTMLCloseCmt, stateCSSBlockCmt, stateCSSLineCmt:
+ return true
+ }
+ return false
+diff --git a/src/html/template/escape.go b/src/html/template/escape.go
+index 1747ec9..b0085ce 100644
+--- a/src/html/template/escape.go
++++ b/src/html/template/escape.go
+@@ -721,9 +721,12 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context {
+ if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone {
+ // Preserve the portion between written and the comment start.
+ cs := i1 - 2
+- if c1.state == stateHTMLCmt {
++ if c1.state == stateHTMLCmt || c1.state == stateJSHTMLOpenCmt {
+ // "<!--" instead of "/*" or "//"
+ cs -= 2
++ } else if c1.state == stateJSHTMLCloseCmt {
++ // "-->" instead of "/*" or "//"
++ cs -= 1
+ }
+ b.Write(s[written:cs])
+ written = i1
+diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
+index 7853daa..bff38c6 100644
+--- a/src/html/template/escape_test.go
++++ b/src/html/template/escape_test.go
+@@ -503,6 +503,16 @@ func TestEscape(t *testing.T) {
+ "<script>var a/*b*///c\nd</script>",
+ "<script>var a \nd</script>",
+ },
++ {
++ "JS HTML-like comments",
++ "<script>before <!-- beep\nbetween\nbefore-->boop\n</script>",
++ "<script>before \nbetween\nbefore\n</script>",
++ },
++ {
++ "JS hashbang comment",
++ "<script>#! beep\n</script>",
++ "<script>\n</script>",
++ },
+ {
+ "Special tags in <script> string literals",
+ `<script>var a = "asd < 123 <!-- 456 < fgh <script jkl < 789 </script"</script>`,
+diff --git a/src/html/template/state_string.go b/src/html/template/state_string.go
+index 05104be..b5cfe70 100644
+--- a/src/html/template/state_string.go
++++ b/src/html/template/state_string.go
+@@ -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 = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead"
++const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateJSHTMLOpenCmtstateJSHTMLCloseCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead"
+
+-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 {
+ if i >= state(len(_state_index)-1) {
+diff --git a/src/html/template/transition.go b/src/html/template/transition.go
+index e2660cc..3d2a37c 100644
+--- a/src/html/template/transition.go
++++ b/src/html/template/transition.go
+@@ -14,32 +14,34 @@ import (
+ // the updated context and the number of bytes consumed from the front of the
+ // input.
+ var transitionFunc = [...]func(context, []byte) (context, int){
+- stateText: tText,
+- stateTag: tTag,
+- stateAttrName: tAttrName,
+- stateAfterName: tAfterName,
+- stateBeforeValue: tBeforeValue,
+- stateHTMLCmt: tHTMLCmt,
+- stateRCDATA: tSpecialTagEnd,
+- stateAttr: tAttr,
+- stateURL: tURL,
+- stateSrcset: tURL,
+- stateJS: tJS,
+- stateJSDqStr: tJSDelimited,
+- stateJSSqStr: tJSDelimited,
+- stateJSBqStr: tJSDelimited,
+- stateJSRegexp: tJSDelimited,
+- stateJSBlockCmt: tBlockCmt,
+- stateJSLineCmt: tLineCmt,
+- stateCSS: tCSS,
+- stateCSSDqStr: tCSSStr,
+- stateCSSSqStr: tCSSStr,
+- stateCSSDqURL: tCSSStr,
+- stateCSSSqURL: tCSSStr,
+- stateCSSURL: tCSSStr,
+- stateCSSBlockCmt: tBlockCmt,
+- stateCSSLineCmt: tLineCmt,
+- stateError: tError,
++ stateText: tText,
++ stateTag: tTag,
++ stateAttrName: tAttrName,
++ stateAfterName: tAfterName,
++ stateBeforeValue: tBeforeValue,
++ stateHTMLCmt: tHTMLCmt,
++ stateRCDATA: tSpecialTagEnd,
++ stateAttr: tAttr,
++ stateURL: tURL,
++ stateSrcset: tURL,
++ stateJS: tJS,
++ stateJSDqStr: tJSDelimited,
++ stateJSSqStr: tJSDelimited,
++ stateJSBqStr: tJSDelimited,
++ stateJSRegexp: tJSDelimited,
++ stateJSBlockCmt: tBlockCmt,
++ stateJSLineCmt: tLineCmt,
++ stateJSHTMLOpenCmt: tLineCmt,
++ stateJSHTMLCloseCmt: tLineCmt,
++ stateCSS: tCSS,
++ stateCSSDqStr: tCSSStr,
++ stateCSSSqStr: tCSSStr,
++ stateCSSDqURL: tCSSStr,
++ stateCSSSqURL: tCSSStr,
++ stateCSSURL: tCSSStr,
++ stateCSSBlockCmt: tBlockCmt,
++ stateCSSLineCmt: tLineCmt,
++ stateError: tError,
+ }
+
+ var commentStart = []byte("<!--")
+@@ -268,7 +270,7 @@ func tURL(c context, s []byte) (context, int) {
+
+ // tJS is the context transition function for the JS state.
+ func tJS(c context, s []byte) (context, int) {
+- i := bytes.IndexAny(s, "\"`'/")
++ i := bytes.IndexAny(s, "\"`'/<-#")
+ if i == -1 {
+ // Entire input is non string, comment, regexp tokens.
+ c.jsCtx = nextJSCtx(s, c.jsCtx)
+@@ -298,6 +300,26 @@ func tJS(c context, s []byte) (context, int) {
+ err: errorf(ErrSlashAmbig, nil, 0, "'/' could start a division or regexp: %.32q", s[i:]),
+ }, len(s)
+ }
++ // ECMAScript supports HTML style comments for legacy reasons, see Appendix
++ // B.1.1 "HTML-like Comments". The handling of these comments is somewhat
++ // confusing. Multi-line comments are not supported, i.e. anything on lines
++ // between the opening and closing tokens is not considered a comment, but
++ // anything following the opening or closing token, on the same line, is
++ // ignored. As such we simply treat any line prefixed with "<!--" or "-->"
++ // as if it were actually prefixed with "//" and move on.
++ case '<':
++ if i+3 < len(s) && bytes.Equal(commentStart, s[i:i+4]) {
++ c.state, i = stateJSHTMLOpenCmt, i+3
++ }
++ case '-':
++ if i+2 < len(s) && bytes.Equal(commentEnd, s[i:i+3]) {
++ c.state, i = stateJSHTMLCloseCmt, i+2
++ }
++ // ECMAScript also supports "hashbang" comment lines, see Section 12.5.
++ case '#':
++ if i+1 < len(s) && s[i+1] == '!' {
++ c.state, i = stateJSLineCmt, i+1
++ }
+ default:
+ panic("unreachable")
+ }
+@@ -387,12 +409,12 @@ func tBlockCmt(c context, s []byte) (context, int) {
+ return c, i + 2
+ }
+
+-// tLineCmt is the context transition function for //comment states.
++// tLineCmt is the context transition function for //comment states, and the JS HTML-like comment state.
+ func tLineCmt(c context, s []byte) (context, int) {
+ var lineTerminators string
+ var endState state
+ switch c.state {
+- case stateJSLineCmt:
++ case stateJSLineCmt, stateJSHTMLOpenCmt, stateJSHTMLCloseCmt:
+ lineTerminators, endState = "\n\r\u2028\u2029", stateJS
+ case stateCSSLineCmt:
+ lineTerminators, endState = "\n\f\r", stateCSS
+--
+2.35.7
+
diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2023-45289.patch b/meta/recipes-devtools/go/go-1.21/CVE-2023-45289.patch
new file mode 100644
index 0000000000..f8ac64472f
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.21/CVE-2023-45289.patch
@@ -0,0 +1,121 @@
+From 3a855208e3efed2e9d7c20ad023f1fa78afcc0be Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 11 Jan 2024 11:31:57 -0800
+Subject: [PATCH] [release-branch.go1.22] net/http, net/http/cookiejar: avoid
+ subdomain matches on IPv6 zones
+
+When deciding whether to forward cookies or sensitive headers
+across a redirect, do not attempt to interpret an IPv6 address
+as a domain name.
+
+Avoids a case where a maliciously-crafted redirect to an
+IPv6 address with a scoped addressing zone could be
+misinterpreted as a within-domain redirect. For example,
+we could interpret "::1%.www.example.com" as a subdomain
+of "www.example.com".
+
+Thanks to Juho Nurminen of Mattermost for reporting this issue.
+
+Fixes CVE-2023-45289
+Fixes #65859
+For #65065
+
+Change-Id: I8f463f59f0e700c8a18733d2b264a8bcb3a19599
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2131938
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2174344
+Reviewed-by: Carlos Amedee <amedee@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/569236
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+
+Upstream-Status: Backport [https://github.com/golang/go/commit/3a855208e3efed2e9d7c20ad023f1fa78afcc0be]
+CVE: CVE-2023-45289
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ src/net/http/client.go | 6 ++++++
+ src/net/http/client_test.go | 1 +
+ src/net/http/cookiejar/jar.go | 7 +++++++
+ src/net/http/cookiejar/jar_test.go | 10 ++++++++++
+ 4 files changed, 24 insertions(+)
+
+diff --git a/src/net/http/client.go b/src/net/http/client.go
+index 22db96b..b2dd445 100644
+--- a/src/net/http/client.go
++++ b/src/net/http/client.go
+@@ -1015,6 +1015,12 @@ func isDomainOrSubdomain(sub, parent string) bool {
+ if sub == parent {
+ return true
+ }
++ // If sub contains a :, it's probably an IPv6 address (and is definitely not a hostname).
++ // Don't check the suffix in this case, to avoid matching the contents of a IPv6 zone.
++ // For example, "::1%.www.example.com" is not a subdomain of "www.example.com".
++ if strings.ContainsAny(sub, ":%") {
++ return false
++ }
+ // If sub is "foo.example.com" and parent is "example.com",
+ // that means sub must end in "."+parent.
+ // Do it without allocating.
+diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
+index 9788c7a..7a0aa53 100644
+--- a/src/net/http/client_test.go
++++ b/src/net/http/client_test.go
+@@ -1729,6 +1729,7 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
+ {"cookie2", "http://foo.com/", "http://bar.com/", false},
+ {"authorization", "http://foo.com/", "http://bar.com/", false},
+ {"www-authenticate", "http://foo.com/", "http://bar.com/", false},
++ {"authorization", "http://foo.com/", "http://[::1%25.foo.com]/", false},
+
+ // But subdomains should work:
+ {"www-authenticate", "http://foo.com/", "http://foo.com/", true},
+diff --git a/src/net/http/cookiejar/jar.go b/src/net/http/cookiejar/jar.go
+index e6583da..f2cf9c2 100644
+--- a/src/net/http/cookiejar/jar.go
++++ b/src/net/http/cookiejar/jar.go
+@@ -362,6 +362,13 @@ func jarKey(host string, psl PublicSuffixList) string {
+
+ // isIP reports whether host is an IP address.
+ func isIP(host string) bool {
++ if strings.ContainsAny(host, ":%") {
++ // Probable IPv6 address.
++ // Hostnames can't contain : or %, so this is definitely not a valid host.
++ // Treating it as an IP is the more conservative option, and avoids the risk
++ // of interpeting ::1%.www.example.com as a subtomain of www.example.com.
++ return true
++ }
+ return net.ParseIP(host) != nil
+ }
+
+diff --git a/src/net/http/cookiejar/jar_test.go b/src/net/http/cookiejar/jar_test.go
+index 47fb1ab..fd8d40e 100644
+--- a/src/net/http/cookiejar/jar_test.go
++++ b/src/net/http/cookiejar/jar_test.go
+@@ -251,6 +251,7 @@ var isIPTests = map[string]bool{
+ "127.0.0.1": true,
+ "1.2.3.4": true,
+ "2001:4860:0:2001::68": true,
++ "::1%zone": true,
+ "example.com": false,
+ "1.1.1.300": false,
+ "www.foo.bar.net": false,
+@@ -613,6 +614,15 @@ var basicsTests = [...]jarTest{
+ {"http://www.host.test:1234/", "a=1"},
+ },
+ },
++ {
++ "IPv6 zone is not treated as a host.",
++ "https://example.com/",
++ []string{"a=1"},
++ "a=1",
++ []query{
++ {"https://[::1%25.example.com]:80/", ""},
++ },
++ },
+ }
+
+ func TestBasics(t *testing.T) {
+--
+2.25.1
+
diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2023-45290.patch b/meta/recipes-devtools/go/go-1.21/CVE-2023-45290.patch
new file mode 100644
index 0000000000..81f2123f34
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.21/CVE-2023-45290.patch
@@ -0,0 +1,270 @@
+From 041a47712e765e94f86d841c3110c840e76d8f82 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Tue, 16 Jan 2024 15:37:52 -0800
+Subject: [PATCH] [release-branch.go1.22] net/textproto, mime/multipart: avoid
+ unbounded read in MIME header
+
+mime/multipart.Reader.ReadForm allows specifying the maximum amount
+of memory that will be consumed by the form. While this limit is
+correctly applied to the parsed form data structure, it was not
+being applied to individual header lines in a form.
+
+For example, when presented with a form containing a header line
+that never ends, ReadForm will continue to read the line until it
+runs out of memory.
+
+Limit the amount of data consumed when reading a header.
+
+Fixes CVE-2023-45290
+Fixes #65850
+For #65383
+
+Change-Id: I7f9264d25752009e95f6b2c80e3d76aaf321d658
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2134435
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2174345
+Reviewed-by: Carlos Amedee <amedee@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/569237
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+
+Upstream-Status: Backport [https://github.com/golang/go/commit/041a47712e765e94f86d841c3110c840e76d8f82]
+CVE: CVE-2023-45290
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>---
+ src/mime/multipart/formdata_test.go | 42 +++++++++++++++++++++++++
+ src/net/textproto/reader.go | 48 ++++++++++++++++++++---------
+ src/net/textproto/reader_test.go | 12 ++++++++
+ 3 files changed, 87 insertions(+), 15 deletions(-)
+
+diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
+index c78eeb7..f729da6 100644
+--- a/src/mime/multipart/formdata_test.go
++++ b/src/mime/multipart/formdata_test.go
+@@ -421,6 +421,48 @@ func TestReadFormLimits(t *testing.T) {
+ }
+ }
+
++func TestReadFormEndlessHeaderLine(t *testing.T) {
++ for _, test := range []struct {
++ name string
++ prefix string
++ }{{
++ name: "name",
++ prefix: "X-",
++ }, {
++ name: "value",
++ prefix: "X-Header: ",
++ }, {
++ name: "continuation",
++ prefix: "X-Header: foo\r\n ",
++ }} {
++ t.Run(test.name, func(t *testing.T) {
++ const eol = "\r\n"
++ s := `--boundary` + eol
++ s += `Content-Disposition: form-data; name="a"` + eol
++ s += `Content-Type: text/plain` + eol
++ s += test.prefix
++ fr := io.MultiReader(
++ strings.NewReader(s),
++ neverendingReader('X'),
++ )
++ r := NewReader(fr, "boundary")
++ _, err := r.ReadForm(1 << 20)
++ if err != ErrMessageTooLarge {
++ t.Fatalf("ReadForm(1 << 20): %v, want ErrMessageTooLarge", err)
++ }
++ })
++ }
++}
++
++type neverendingReader byte
++
++func (r neverendingReader) Read(p []byte) (n int, err error) {
++ for i := range p {
++ p[i] = byte(r)
++ }
++ return len(p), nil
++}
++
+ func BenchmarkReadForm(b *testing.B) {
+ for _, test := range []struct {
+ name string
+diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
+index c6569c8..3ac4d4d 100644
+--- a/src/net/textproto/reader.go
++++ b/src/net/textproto/reader.go
+@@ -16,6 +16,10 @@ import (
+ "sync"
+ )
+
++// TODO: This should be a distinguishable error (ErrMessageTooLarge)
++// to allow mime/multipart to detect it.
++var errMessageTooLarge = errors.New("message too large")
++
+ // A Reader implements convenience methods for reading requests
+ // or responses from a text protocol network connection.
+ type Reader struct {
+@@ -37,13 +41,13 @@ func NewReader(r *bufio.Reader) *Reader {
+ // ReadLine reads a single line from r,
+ // eliding the final \n or \r\n from the returned string.
+ func (r *Reader) ReadLine() (string, error) {
+- line, err := r.readLineSlice()
++ line, err := r.readLineSlice(-1)
+ return string(line), err
+ }
+
+ // ReadLineBytes is like ReadLine but returns a []byte instead of a string.
+ func (r *Reader) ReadLineBytes() ([]byte, error) {
+- line, err := r.readLineSlice()
++ line, err := r.readLineSlice(-1)
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+@@ -52,7 +56,10 @@ func (r *Reader) ReadLineBytes() ([]byte, error) {
+ return line, err
+ }
+
+-func (r *Reader) readLineSlice() ([]byte, error) {
++// readLineSlice reads a single line from r,
++// up to lim bytes long (or unlimited if lim is less than 0),
++// eliding the final \r or \r\n from the returned string.
++func (r *Reader) readLineSlice(lim int64) ([]byte, error) {
+ r.closeDot()
+ var line []byte
+ for {
+@@ -60,6 +67,9 @@ func (r *Reader) readLineSlice() ([]byte, error) {
+ if err != nil {
+ return nil, err
+ }
++ if lim >= 0 && int64(len(line))+int64(len(l)) > lim {
++ return nil, errMessageTooLarge
++ }
+ // Avoid the copy if the first call produced a full line.
+ if line == nil && !more {
+ return l, nil
+@@ -92,7 +102,7 @@ func (r *Reader) readLineSlice() ([]byte, error) {
+ // Empty lines are never continued.
+ //
+ func (r *Reader) ReadContinuedLine() (string, error) {
+- line, err := r.readContinuedLineSlice(noValidation)
++ line, err := r.readContinuedLineSlice(-1, noValidation)
+ return string(line), err
+ }
+
+@@ -113,7 +123,7 @@ func trim(s []byte) []byte {
+ // ReadContinuedLineBytes is like ReadContinuedLine but
+ // returns a []byte instead of a string.
+ func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
+- line, err := r.readContinuedLineSlice(noValidation)
++ line, err := r.readContinuedLineSlice(-1, noValidation)
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+@@ -126,13 +136,14 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
+ // returning a byte slice with all lines. The validateFirstLine function
+ // is run on the first read line, and if it returns an error then this
+ // error is returned from readContinuedLineSlice.
+-func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([]byte, error) {
++// It reads up to lim bytes of data (or unlimited if lim is less than 0).
++func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) {
+ if validateFirstLine == nil {
+ return nil, fmt.Errorf("missing validateFirstLine func")
+ }
+
+ // Read the first line.
+- line, err := r.readLineSlice()
++ line, err := r.readLineSlice(lim)
+ if err != nil {
+ return nil, err
+ }
+@@ -160,13 +171,21 @@ func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([
+ // copy the slice into buf.
+ r.buf = append(r.buf[:0], trim(line)...)
+
++ if lim < 0 {
++ lim = math.MaxInt64
++ }
++ lim -= int64(len(r.buf))
++
+ // Read continuation lines.
+ for r.skipSpace() > 0 {
+- line, err := r.readLineSlice()
++ r.buf = append(r.buf, ' ')
++ if int64(len(r.buf)) >= lim {
++ return nil, errMessageTooLarge
++ }
++ line, err := r.readLineSlice(lim - int64(len(r.buf)))
+ if err != nil {
+ break
+ }
+- r.buf = append(r.buf, ' ')
+ r.buf = append(r.buf, trim(line)...)
+ }
+ return r.buf, nil
+@@ -511,7 +530,8 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+
+ // The first line cannot start with a leading space.
+ if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
+- line, err := r.readLineSlice()
++ const errorLimit = 80 // arbitrary limit on how much of the line we'll quote
++ line, err := r.readLineSlice(errorLimit)
+ if err != nil {
+ return m, err
+ }
+@@ -519,7 +539,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+ }
+
+ for {
+- kv, err := r.readContinuedLineSlice(mustHaveFieldNameColon)
++ kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon)
+ if len(kv) == 0 {
+ return m, err
+ }
+@@ -540,7 +560,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+
+ maxHeaders--
+ if maxHeaders < 0 {
+- return nil, errors.New("message too large")
++ return nil, errMessageTooLarge
+ }
+
+ // backport 5c55ac9bf1e5f779220294c843526536605f42ab
+@@ -567,9 +587,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+ }
+ maxMemory -= int64(len(value))
+ if maxMemory < 0 {
+- // TODO: This should be a distinguishable error (ErrMessageTooLarge)
+- // to allow mime/multipart to detect it.
+- return m, errors.New("message too large")
++ return m, errMessageTooLarge
+ }
+ if vv == nil && len(strs) > 0 {
+ // More than likely this will be a single-element key.
+diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
+index 3ae0de1..db1ed91 100644
+--- a/src/net/textproto/reader_test.go
++++ b/src/net/textproto/reader_test.go
+@@ -34,6 +34,18 @@ func TestReadLine(t *testing.T) {
+ }
+ }
+
++func TestReadLineLongLine(t *testing.T) {
++ line := strings.Repeat("12345", 10000)
++ r := reader(line + "\r\n")
++ s, err := r.ReadLine()
++ if err != nil {
++ t.Fatalf("Line 1: %v", err)
++ }
++ if s != line {
++ t.Fatalf("%v-byte line does not match expected %v-byte line", len(s), len(line))
++ }
++}
++
+ func TestReadContinuedLine(t *testing.T) {
+ r := reader("line1\nline\n 2\nline3\n")
+ s, err := r.ReadContinuedLine()
+--
+2.25.1
+