mirror of
https://git.yoctoproject.org/poky
synced 2026-03-09 16:59:40 +01:00
Backport required patches from go1.21 to fix CVE-2023-24531. (From OE-Core rev: 6d892c52bd5806507a05e8b6f749c54bbd9e9da6) Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
253 lines
7.4 KiB
Diff
253 lines
7.4 KiB
Diff
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
|
|
|