golang: upgrade to 1.15.7

This commit is contained in:
meilier 2021-01-28 16:36:59 +08:00
parent 8b174a38e5
commit fee2c79e99
15 changed files with 5 additions and 2090 deletions

View File

@ -1,41 +0,0 @@
From 817407fc2d6a861e65086388766f58082d38bc0b Mon Sep 17 00:00:00 2001
From: Michael Munday <munday@ca.ibm.com>
Date: Tue, 17 Jan 2017 11:33:38 -0500
Subject: [PATCH 2/3] syscall: expose IfInfomsg.X__ifi_pad on s390x
Exposing this field on s390x improves compatibility with the other
linux architectures, all of which already expose it.
Fixes #18628 and updates #18632.
Change-Id: I08e8e1eb705f898cd8822f8bee0d61ce11d514b5
---
src/syscall/ztypes_linux_s390x.go | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/syscall/ztypes_linux_s390x.go b/src/syscall/ztypes_linux_s390x.go
index 63c4a83b19..b5894255df 100644
--- a/src/syscall/ztypes_linux_s390x.go
+++ b/src/syscall/ztypes_linux_s390x.go
@@ -449,12 +449,12 @@ type RtAttr struct {
}
type IfInfomsg struct {
- Family uint8
- _ uint8
- Type uint16
- Index int32
- Flags uint32
- Change uint32
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
}
type IfAddrmsg struct {
--
2.14.3

View File

@ -1,44 +0,0 @@
From de4a8f2f1c0e7c30dc5f54d19212eb29d01871ed Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 27 Nov 2019 10:46:52 +0800
Subject: [PATCH 6/6] golang: delete pem files
Signed-off-by: jingrui <jingrui@huawei.com>
---
src/crypto/tls/testdata/example-cert.pem | 11 -----------
src/crypto/tls/testdata/example-key.pem | 5 -----
2 files changed, 16 deletions(-)
delete mode 100644 src/crypto/tls/testdata/example-cert.pem
delete mode 100644 src/crypto/tls/testdata/example-key.pem
diff --git a/src/crypto/tls/testdata/example-cert.pem b/src/crypto/tls/testdata/example-cert.pem
deleted file mode 100644
index e0bf7db..0000000
--- a/src/crypto/tls/testdata/example-cert.pem
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
-DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
-EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
-7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
-5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
-BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
-NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
-Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
-6MF9+Yw1Yy0t
------END CERTIFICATE-----
diff --git a/src/crypto/tls/testdata/example-key.pem b/src/crypto/tls/testdata/example-key.pem
deleted file mode 100644
index 104fb09..0000000
--- a/src/crypto/tls/testdata/example-key.pem
+++ /dev/null
@@ -1,5 +0,0 @@
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
-AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
-EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
------END EC PRIVATE KEY-----
--
2.17.1

View File

@ -1,101 +0,0 @@
From fa95a1d8e7eda9ab90a7fd29785cad0ae7d816e2 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 27 Nov 2019 09:54:22 +0800
Subject: [PATCH 1/6] syscall: implement rawVforkSyscall for linux/arm64
This allows the use of CLONE_VFORK and CLONE_VM for fork/exec, preventing
"fork/exec ...: cannot allocate memory" failures from occuring when attempting
to execute commands from a Go process that has a large memory footprint.
Additionally, this should reduce the latency of fork/exec on linux/arm64.
With CLONE_VM the child process shares the same memory with the parent
process. On its own this would lead to conflicting use of the same
memory, so CLONE_VFORK is used to suspend the parent process until the
child releases the memory when switching to the new program binary
via the exec syscall. When the parent process continues to run, one
has to consider the changes to memory that the child process did,
namely the return address of the syscall function needs to be restored
from a register.
exec.Command() callers can start in a faster manner, as child process who
do exec commands job can be cloned faster via vfork than via fork on arm64.
The same problem was addressed on linux/amd64 via issue #5838.
Updates #31936
Contributed by Howard Zhang <howard.zhang@arm.com> and Bin Lu <bin.lu@arm.com>
Change-Id: Ia99d81d877f564ec60d19f17e596276836576eaf
Reviewed-on: https://go-review.googlesource.com/c/go/+/189418
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
---
src/syscall/asm_linux_arm64.s | 23 +++++++++++++++++++++++
src/syscall/exec_linux.go | 2 +-
src/syscall/syscall_linux_arm64.go | 4 +---
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/src/syscall/asm_linux_arm64.s b/src/syscall/asm_linux_arm64.s
index 7edeafc..fb22f8d 100644
--- a/src/syscall/asm_linux_arm64.s
+++ b/src/syscall/asm_linux_arm64.s
@@ -103,6 +103,29 @@ ok:
MOVD ZR, err+72(FP) // errno
RET
+// func rawVforkSyscall(trap, a1 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-32
+ MOVD a1+8(FP), R0
+ MOVD $0, R1
+ MOVD $0, R2
+ MOVD $0, R3
+ MOVD $0, R4
+ MOVD $0, R5
+ MOVD trap+0(FP), R8 // syscall entry
+ SVC
+ CMN $4095, R0
+ BCC ok
+ MOVD $-1, R4
+ MOVD R4, r1+16(FP) // r1
+ NEG R0, R0
+ MOVD R0, err+24(FP) // errno
+ RET
+ok:
+ MOVD R0, r1+16(FP) // r1
+ MOVD ZR, err+24(FP) // errno
+ RET
+
+
// func rawSyscallNoError(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr);
TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R0
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index a2242b2..3540d51 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -196,7 +196,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
}
}
- hasRawVforkSyscall := runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "s390x"
+ hasRawVforkSyscall := runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "s390x" || runtime.GOARCH == "arm64"
// About to call fork.
// No more allocation or calls of non-assembly functions.
diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go
index 48ad0bb..89b2ab2 100644
--- a/src/syscall/syscall_linux_arm64.go
+++ b/src/syscall/syscall_linux_arm64.go
@@ -154,6 +154,4 @@ const (
SYS_EPOLL_WAIT = 1069
)
-func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
- panic("not implemented")
-}
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno)
--
2.17.1

View File

@ -1,191 +0,0 @@
From 8a755c0f0389dca42ec8caef0efa9b6ebe9d1e3c Mon Sep 17 00:00:00 2001
From: Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
Date: Wed, 11 Sep 2019 02:26:02 +0000
Subject: [PATCH 2/6] runtime: fix crash during VDSO calls on arm
As discussed in #32912, a crash occurs when go runtime calls a VDSO function (say
__vdso_clock_gettime) and a signal arrives to that thread.
Since VDSO functions temporarily destroy the G register (R10),
Go functions asynchronously executed in that thread (i.e. Go's signal
handler) can try to load data from the destroyed G, which causes
segmentation fault.
To fix the issue a guard is inserted in front of sigtrampgo, so that the control escapes from
signal handlers without touching G in case the signal occurred in the VDSO context.
The test case included in the patch is take from discussion in a relevant thread on github:
https://github.com/golang/go/issues/32912#issuecomment-517874531.
This patch not only fixes the issue on AArch64 but also that on 32bit ARM.
Fixes #32912
Change-Id: I657472e54b7aa3c617fabc5019ce63aa4105624a
GitHub-Last-Rev: 28ce42c4a02a060f08c1b0dd1c9a392123fd2ee9
GitHub-Pull-Request: golang/go#34030
Reviewed-on: https://go-review.googlesource.com/c/go/+/192937
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
---
src/runtime/crash_test.go | 9 +++++
src/runtime/signal_unix.go | 27 ++++++++++---
src/runtime/testdata/testprog/vdso.go | 55 +++++++++++++++++++++++++++
src/runtime/vdso_linux.go | 1 +
4 files changed, 86 insertions(+), 6 deletions(-)
create mode 100644 src/runtime/testdata/testprog/vdso.go
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index c54bb57..c2cab7c 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -143,6 +143,15 @@ func buildTestProg(t *testing.T, binary string, flags ...string) (string, error)
return exe, nil
}
+func TestVDSO(t *testing.T) {
+ t.Parallel()
+ output := runTestProg(t, "testprog", "SignalInVDSO")
+ want := "success\n"
+ if output != want {
+ t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want);
+ }
+}
+
var (
staleRuntimeOnce sync.Once // guards init of staleRuntimeErr
staleRuntimeErr error
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index ad51dc1..63fb07f 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -274,6 +274,21 @@ func sigpipe() {
dieFromSignal(_SIGPIPE)
}
+// sigFetchG fetches the value of G safely when running in a signal handler.
+// On some architectures, the g value may be clobbered when running in a VDSO.
+// See issue #32912.
+//
+//go:nosplit
+func sigFetchG(c *sigctxt) *g {
+ switch GOARCH {
+ case "arm", "arm64", "ppc64", "ppc64le":
+ if inVDSOPage(c.sigpc()) {
+ return nil
+ }
+ }
+ return getg()
+}
+
// sigtrampgo is called from the signal handler function, sigtramp,
// written in assembly code.
// This is called by the signal handler, and the world may be stopped.
@@ -289,9 +304,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
if sigfwdgo(sig, info, ctx) {
return
}
- g := getg()
+ c := &sigctxt{info, ctx}
+ g := sigFetchG(c)
if g == nil {
- c := &sigctxt{info, ctx}
if sig == _SIGPROF {
sigprofNonGoPC(c.sigpc())
return
@@ -347,7 +362,6 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
signalDuringFork(sig)
}
- c := &sigctxt{info, ctx}
c.fixsigcode(sig)
sighandler(sig, info, ctx, g)
setg(g)
@@ -650,9 +664,10 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
return false
}
// Determine if the signal occurred inside Go code. We test that:
- // (1) we were in a goroutine (i.e., m.curg != nil), and
- // (2) we weren't in CGO.
- g := getg()
+ // (1) we weren't in VDSO page,
+ // (2) we were in a goroutine (i.e., m.curg != nil), and
+ // (3) we weren't in CGO.
+ g := sigFetchG(c)
if g != nil && g.m != nil && g.m.curg != nil && !g.m.incgo {
return false
}
diff --git a/src/runtime/testdata/testprog/vdso.go b/src/runtime/testdata/testprog/vdso.go
new file mode 100644
index 0000000..6036f45
--- /dev/null
+++ b/src/runtime/testdata/testprog/vdso.go
@@ -0,0 +1,55 @@
+// Copyright 2019 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.
+
+// Invoke signal hander in the VDSO context (see issue 32912).
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime/pprof"
+ "time"
+)
+
+func init() {
+ register("SignalInVDSO", signalInVDSO)
+}
+
+func signalInVDSO() {
+ f, err := ioutil.TempFile("", "timeprofnow")
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ if err := pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ t0 := time.Now()
+ t1 := t0
+ // We should get a profiling signal 100 times a second,
+ // so running for 1 second should be sufficient.
+ for t1.Sub(t0) < time.Second {
+ t1 = time.Now()
+ }
+
+ pprof.StopCPUProfile()
+
+ name := f.Name()
+ if err := f.Close(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ if err := os.Remove(name); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ fmt.Println("success");
+}
diff --git a/src/runtime/vdso_linux.go b/src/runtime/vdso_linux.go
index 71ba4ce..8518276 100644
--- a/src/runtime/vdso_linux.go
+++ b/src/runtime/vdso_linux.go
@@ -281,6 +281,7 @@ func vdsoauxv(tag, val uintptr) {
}
// vdsoMarker reports whether PC is on the VDSO page.
+//go:nosplit
func inVDSOPage(pc uintptr) bool {
for _, k := range vdsoSymbolKeys {
if *k.ptr != 0 {
--
2.17.1

View File

@ -1,253 +0,0 @@
From 4717d9a1a21dfe051a14f033615218d833371d68 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 27 Nov 2019 10:19:13 +0800
Subject: [PATCH 3/6] runtime: save/fetch g register during VDSO on ARM and
ARM64
On ARM and ARM64, during a VDSO call, the g register may be
temporarily clobbered by the VDSO code. If a signal is received
during the execution of VDSO code, we may not find a valid g
reading the g register. In CL 192937, we conservatively assume
g is nil. But this approach has a problem: we cannot handle
the signal in this case. Further, if the signal is not a
profiling signal, we'll call badsignal, which calls needm, which
wants to get an extra m, but we don't have one in a non-cgo
binary, which cuases the program to hang.
This is even more of a problem with async preemption, where we
will receive more signals than before. I ran into this problem
while working on async preemption support on ARM64.
In this CL, before making a VDSO call, we save the g on the
gsignal stack. When we receive a signal, we will be running on
the gsignal stack, so we can fetch the g from there and move on.
We probably want to do the same for PPC64. Currently we rely on
that the VDSO code doesn't actually clobber the g register, but
this is not guaranteed and we don't have control with.
Idea from discussion with Dan Cross and Austin.
Should fix #34391.
Change-Id: Idbefc5e4c2f4373192c2be797be0140ae08b26e3
Reviewed-on: https://go-review.googlesource.com/c/go/+/202759
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Austin Clements <austin@google.com>
---
src/os/signal/signal_test.go | 49 +++++++++++++++++++++++++++++++++++
src/runtime/proc.go | 3 +++
src/runtime/signal_unix.go | 24 ++++++++++++-----
src/runtime/sys_linux_arm.s | 32 +++++++++++++++++++++++
src/runtime/sys_linux_arm64.s | 28 ++++++++++++++++++++
5 files changed, 129 insertions(+), 7 deletions(-)
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index 6ea59f4..c8274ea 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -453,3 +453,52 @@ func atomicStopTestProgram() {
os.Exit(0)
}
+
+func TestTime(t *testing.T) {
+ // Test that signal works fine when we are in a call to get time,
+ // which on some platforms is using VDSO. See issue #34391.
+ dur := 3 * time.Second
+ if testing.Short() {
+ dur = 100 * time.Millisecond
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ done := make(chan bool)
+ finished := make(chan bool)
+ go func() {
+ sig := make(chan os.Signal, 1)
+ Notify(sig, syscall.SIGUSR1)
+ defer Stop(sig)
+ Loop:
+ for {
+ select {
+ case <-sig:
+ case <-done:
+ break Loop
+ }
+ }
+ finished <- true
+ }()
+ go func() {
+ Loop:
+ for {
+ select {
+ case <-done:
+ break Loop
+ default:
+ syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
+ runtime.Gosched()
+ }
+ }
+ finished <- true
+ }()
+ t0 := time.Now()
+ for t1 := t0; t1.Sub(t0) < dur; t1 = time.Now() {
+ } // hammering on getting time
+ close(done)
+ <-finished
+ <-finished
+ // When run with 'go test -cpu=1,2,4' SIGUSR1 from this test can slip
+ // into subsequent TestSignal() causing failure.
+ // Sleep for a while to reduce the possibility of the failure.
+ time.Sleep(10 * time.Millisecond)
+}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 93d329d..1487647 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -3237,6 +3237,9 @@ func malg(stacksize int32) *g {
})
newg.stackguard0 = newg.stack.lo + _StackGuard
newg.stackguard1 = ^uintptr(0)
+ // Clear the bottom word of the stack. We record g
+ // there on gsignal stack during VDSO on ARM and ARM64.
+ *(*uintptr)(unsafe.Pointer(newg.stack.lo)) = 0
}
return newg
}
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 63fb07f..2cf1e3b 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -280,13 +280,23 @@ func sigpipe() {
//
//go:nosplit
func sigFetchG(c *sigctxt) *g {
- switch GOARCH {
- case "arm", "arm64", "ppc64", "ppc64le":
- if inVDSOPage(c.sigpc()) {
- return nil
- }
- }
- return getg()
+ switch GOARCH {
+ case "arm", "arm64":
+ if inVDSOPage(c.sigpc()) {
+ // Before making a VDSO call we save the g to the bottom of the
+ // signal stack. Fetch from there.
+ // TODO: in efence mode, stack is sysAlloc'd, so this wouldn't
+ // work.
+ sp := getcallersp()
+ s := spanOf(sp)
+ if s != nil && s.state == mSpanManual && s.base() < sp && sp < s.limit {
+ gp := *(**g)(unsafe.Pointer(s.base()))
+ return gp
+ }
+ return nil
+ }
+ }
+ return getg()
}
// sigtrampgo is called from the signal handler function, sigtramp,
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 9c73984..26e12a8 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -246,7 +246,23 @@ noswitch:
CMP $0, R11
B.EQ fallback
+ // Store g on gsignal's stack, so if we receive a signal
+ // during VDSO code we can find the g.
+ // If we don't have a signal stack, we won't receive signal,
+ // so don't bother saving g.
+ MOVW m_gsignal(R5), R6 // g.m.gsignal
+ CMP $0, R6
+ BEQ 3(PC)
+ MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
+ MOVW g, (R6)
+
BL (R11)
+
+ CMP $0, R6 // R6 is unchanged by C code
+ BEQ 3(PC)
+ MOVW $0, R1
+ MOVW R1, (R6) // clear g slot
+
JMP finish
fallback:
@@ -297,7 +313,23 @@ noswitch:
CMP $0, R11
B.EQ fallback
+ // Store g on gsignal's stack, so if we receive a signal
+ // during VDSO code we can find the g.
+ // If we don't have a signal stack, we won't receive signal,
+ // so don't bother saving g.
+ MOVW m_gsignal(R5), R6 // g.m.gsignal
+ CMP $0, R6
+ BEQ 3(PC)
+ MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
+ MOVW g, (R6)
+
BL (R11)
+
+ CMP $0, R6 // R6 is unchanged by C code
+ BEQ 3(PC)
+ MOVW $0, R1
+ MOVW R1, (R6) // clear g slot
+
JMP finish
fallback:
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 2835b6c..fd40bf9 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -207,7 +207,21 @@ noswitch:
MOVW $CLOCK_REALTIME, R0
MOVD runtime·vdsoClockgettimeSym(SB), R2
CBZ R2, fallback
+
+ // Store g on gsignal's stack, so if we receive a signal
+ // during VDSO code we can find the g.
+ // If we don't have a signal stack, we won't receive signal,
+ // so don't bother saving g.
+ MOVD m_gsignal(R21), R22 // g.m.gsignal
+ CBZ R22, 3(PC)
+ MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
+ MOVD g, (R22)
+
BL (R2)
+
+ CBZ R22, 2(PC) // R22 is unchanged by C code
+ MOVD ZR, (R22) // clear g slot
+
B finish
fallback:
@@ -250,7 +264,21 @@ noswitch:
MOVW $CLOCK_MONOTONIC, R0
MOVD runtime·vdsoClockgettimeSym(SB), R2
CBZ R2, fallback
+
+ // Store g on gsignal's stack, so if we receive a signal
+ // during VDSO code we can find the g.
+ // If we don't have a signal stack, we won't receive signal,
+ // so don't bother saving g.
+ MOVD m_gsignal(R21), R22 // g.m.gsignal
+ CBZ R22, 3(PC)
+ MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
+ MOVD g, (R22)
+
BL (R2)
+
+ CBZ R22, 2(PC) // R22 is unchanged by C code
+ MOVD ZR, (R22) // clear g slot
+
B finish
fallback:
--
2.17.1

View File

@ -1,179 +0,0 @@
From fce0a59fc370634fcd7de8f8691e918cdf122f7d Mon Sep 17 00:00:00 2001
From: Cherry Zhang <cherryyz@google.com>
Date: Thu, 31 Oct 2019 10:32:31 -0400
Subject: [PATCH 4/6] runtime: don't fetch G from signal stack when using cgo
When using cgo, we save G to TLS, and when a signal happens, we
load G from TLS in sigtramp. This should give us a valid G. Don't
try to fetch from the signal stack. In particular, C code may
change the signal stack or call our signal handler directly (e.g.
TSAN), so we are not necessarily running on the original gsignal
stack where we saved G.
Also skip saving G on the signal stack when using cgo.
Updates #35249.
Change-Id: I40749ce6682709bd4ebfdfd9f23bd0f317fc197d
Reviewed-on: https://go-review.googlesource.com/c/go/+/204519
Reviewed-by: Ian Lance Taylor <iant@golang.org>
---
src/runtime/signal_unix.go | 8 +++++---
src/runtime/sys_linux_arm.s | 30 ++++++++++++++++++++++--------
src/runtime/sys_linux_arm64.s | 26 ++++++++++++++++++++------
3 files changed, 47 insertions(+), 17 deletions(-)
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 2cf1e3b..721edb5 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -282,9 +282,11 @@ func sigpipe() {
func sigFetchG(c *sigctxt) *g {
switch GOARCH {
case "arm", "arm64":
- if inVDSOPage(c.sigpc()) {
- // Before making a VDSO call we save the g to the bottom of the
- // signal stack. Fetch from there.
+ if !iscgo && inVDSOPage(c.sigpc()) {
+ // When using cgo, we save the g on TLS and load it from there
+ // in sigtramp. Just use that.
+ // Otherwise, before making a VDSO call we save the g to the
+ // bottom of the signal stack. Fetch from there.
// TODO: in efence mode, stack is sysAlloc'd, so this wouldn't
// work.
sp := getcallersp()
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 26e12a8..a47ac5f 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -250,21 +250,28 @@ noswitch:
// during VDSO code we can find the g.
// If we don't have a signal stack, we won't receive signal,
// so don't bother saving g.
+ // When using cgo, we already saved g on TLS, also don't save
+ // g here.
+ MOVB runtime·iscgo(SB), R6
+ CMP $0, R6
+ BNE nosaveg
MOVW m_gsignal(R5), R6 // g.m.gsignal
CMP $0, R6
- BEQ 3(PC)
+ BEQ nosaveg
MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
MOVW g, (R6)
BL (R11)
- CMP $0, R6 // R6 is unchanged by C code
- BEQ 3(PC)
MOVW $0, R1
- MOVW R1, (R6) // clear g slot
+ MOVW R1, (R6) // clear g slot, R6 is unchanged by C code
JMP finish
+nosaveg:
+ BL (R11)
+ JMP finish
+
fallback:
MOVW $SYS_clock_gettime, R7
SWI $0
@@ -317,21 +324,28 @@ noswitch:
// during VDSO code we can find the g.
// If we don't have a signal stack, we won't receive signal,
// so don't bother saving g.
+ // When using cgo, we already saved g on TLS, also don't save
+ // g here.
+ MOVB runtime·iscgo(SB), R6
+ CMP $0, R6
+ BNE nosaveg
MOVW m_gsignal(R5), R6 // g.m.gsignal
CMP $0, R6
- BEQ 3(PC)
+ BEQ nosaveg
MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
MOVW g, (R6)
BL (R11)
- CMP $0, R6 // R6 is unchanged by C code
- BEQ 3(PC)
MOVW $0, R1
- MOVW R1, (R6) // clear g slot
+ MOVW R1, (R6) // clear g slot, R6 is unchanged by C code
JMP finish
+nosaveg:
+ BL (R11)
+ JMP finish
+
fallback:
MOVW $SYS_clock_gettime, R7
SWI $0
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index fd40bf9..94c93ca 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -212,18 +212,25 @@ noswitch:
// during VDSO code we can find the g.
// If we don't have a signal stack, we won't receive signal,
// so don't bother saving g.
+ // When using cgo, we already saved g on TLS, also don't save
+ // g here.
+ MOVBU runtime·iscgo(SB), R22
+ CBNZ R22, nosaveg
MOVD m_gsignal(R21), R22 // g.m.gsignal
- CBZ R22, 3(PC)
+ CBZ R22, nosaveg
MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
MOVD g, (R22)
BL (R2)
- CBZ R22, 2(PC) // R22 is unchanged by C code
- MOVD ZR, (R22) // clear g slot
+ MOVD ZR, (R22) // clear g slot, R22 is unchanged by C code
B finish
+nosaveg:
+ BL (R2)
+ B finish
+
fallback:
MOVD $SYS_clock_gettime, R8
SVC
@@ -269,18 +276,25 @@ noswitch:
// during VDSO code we can find the g.
// If we don't have a signal stack, we won't receive signal,
// so don't bother saving g.
+ // When using cgo, we already saved g on TLS, also don't save
+ // g here.
+ MOVBU runtime·iscgo(SB), R22
+ CBNZ R22, nosaveg
MOVD m_gsignal(R21), R22 // g.m.gsignal
- CBZ R22, 3(PC)
+ CBZ R22, nosaveg
MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
MOVD g, (R22)
BL (R2)
- CBZ R22, 2(PC) // R22 is unchanged by C code
- MOVD ZR, (R22) // clear g slot
+ MOVD ZR, (R22) // clear g slot, R22 is unchanged by C code
B finish
+nosaveg:
+ BL (R2)
+ B finish
+
fallback:
MOVD $SYS_clock_gettime, R8
SVC
--
2.17.1

View File

@ -1,107 +0,0 @@
From e83074ea52287115b85002a6b72137c72f6d7ecc Mon Sep 17 00:00:00 2001
From: Cherry Zhang <cherryyz@google.com>
Date: Sun, 10 Nov 2019 13:18:06 -0500
Subject: [PATCH 5/6] runtime: don't save G during VDSO if we're handling
signal
On some platforms (currently ARM and ARM64), when calling into
VDSO we store the G to the gsignal stack, if there is one, so if
we receive a signal during VDSO we can find the G.
If we receive a signal during VDSO, and within the signal handler
we call nanotime again (e.g. when handling profiling signal),
we'll save/clear the G slot on the gsignal stack again, which
clobbers the original saved G. If we receive a second signal
during the same VDSO execution, we will fetch a nil G, which will
lead to bad things such as deadlock.
Don't save G if we're calling VDSO code from the gsignal stack.
Saving G is not necessary as we won't receive a nested signal.
Fixes #35473.
Change-Id: Ibfd8587a3c70c2f1533908b056e81b94d75d65a5
Reviewed-on: https://go-review.googlesource.com/c/go/+/206397
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
---
src/runtime/sys_linux_arm.s | 8 ++++++++
src/runtime/sys_linux_arm64.s | 8 ++++++++
2 files changed, 16 insertions(+)
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index a47ac5f..577faac 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -252,12 +252,16 @@ noswitch:
// so don't bother saving g.
// When using cgo, we already saved g on TLS, also don't save
// g here.
+ // Also don't save g if we are already on the signal stack.
+ // We won't get a nested signal.
MOVB runtime·iscgo(SB), R6
CMP $0, R6
BNE nosaveg
MOVW m_gsignal(R5), R6 // g.m.gsignal
CMP $0, R6
BEQ nosaveg
+ CMP g, R6
+ BEQ nosaveg
MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
MOVW g, (R6)
@@ -326,12 +330,16 @@ noswitch:
// so don't bother saving g.
// When using cgo, we already saved g on TLS, also don't save
// g here.
+ // Also don't save g if we are already on the signal stack.
+ // We won't get a nested signal.
MOVB runtime·iscgo(SB), R6
CMP $0, R6
BNE nosaveg
MOVW m_gsignal(R5), R6 // g.m.gsignal
CMP $0, R6
BEQ nosaveg
+ CMP g, R6
+ BEQ nosaveg
MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
MOVW g, (R6)
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 94c93ca..a076744 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -214,10 +214,14 @@ noswitch:
// so don't bother saving g.
// When using cgo, we already saved g on TLS, also don't save
// g here.
+ // Also don't save g if we are already on the signal stack.
+ // We won't get a nested signal.
MOVBU runtime·iscgo(SB), R22
CBNZ R22, nosaveg
MOVD m_gsignal(R21), R22 // g.m.gsignal
CBZ R22, nosaveg
+ CMP g, R22
+ BEQ nosaveg
MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
MOVD g, (R22)
@@ -278,10 +282,14 @@ noswitch:
// so don't bother saving g.
// When using cgo, we already saved g on TLS, also don't save
// g here.
+ // Also don't save g if we are already on the signal stack.
+ // We won't get a nested signal.
MOVBU runtime·iscgo(SB), R22
CBNZ R22, nosaveg
MOVD m_gsignal(R21), R22 // g.m.gsignal
CBZ R22, nosaveg
+ CMP g, R22
+ BEQ nosaveg
MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
MOVD g, (R22)
--
2.17.1

View File

@ -1,135 +0,0 @@
From 2720067ebfb7568792bb0c8fe3fbf095c89b77a9 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Tue, 17 Mar 2020 17:43:33 +0800
Subject: [PATCH] drop hard-code cert
Signed-off-by: jingrui <jingrui@huawei.com>
---
src/crypto/x509/test-file.crt | 32 ---------------------------
src/crypto/x509/testdata/test-dir.crt | 31 --------------------------
src/net/http/internal/testcert.go | 31 ++------------------------
3 files changed, 2 insertions(+), 92 deletions(-)
delete mode 100644 src/crypto/x509/test-file.crt
delete mode 100644 src/crypto/x509/testdata/test-dir.crt
diff --git a/src/crypto/x509/test-file.crt b/src/crypto/x509/test-file.crt
deleted file mode 100644
index caa83b9..0000000
--- a/src/crypto/x509/test-file.crt
+++ /dev/null
@@ -1,32 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFbTCCA1WgAwIBAgIJAN338vEmMtLsMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
-BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
-dHMxEjAQBgNVBAMMCXRlc3QtZmlsZTAeFw0xNzAyMDEyMzUyMDhaFw0yNzAxMzAy
-MzUyMDhaME0xCzAJBgNVBAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYD
-VQQKDAxHb2xhbmcgVGVzdHMxEjAQBgNVBAMMCXRlc3QtZmlsZTCCAiIwDQYJKoZI
-hvcNAQEBBQADggIPADCCAgoCggIBAPMGiLjdiffQo3Xc8oUe7wsDhSaAJFOhO6Qs
-i0xYrYl7jmCuz9rGD2fdgk5cLqGazKuQ6fIFzHXFU2BKs4CWXt9KO0KFEhfvZeuW
-jG5d7C1ZUiuKOrPqjKVu8SZtFPc7y7Ke7msXzY+Z2LLyiJJ93LCMq4+cTSGNXVlI
-KqUxhxeoD5/QkUPyQy/ilu3GMYfx/YORhDP6Edcuskfj8wRh1UxBejP8YPMvI6St
-cE2GkxoEGqDWnQ/61F18te6WI3MD29tnKXOkXVhnSC+yvRLljotW2/tAhHKBG4tj
-iQWT5Ri4Wrw2tXxPKRLsVWc7e1/hdxhnuvYpXkWNhKsm002jzkFXlzfEwPd8nZdw
-5aT6gPUBN2AAzdoqZI7E200i0orEF7WaSoMfjU1tbHvExp3vyAPOfJ5PS2MQ6W03
-Zsy5dTVH+OBH++rkRzQCFcnIv/OIhya5XZ9KX9nFPgBEP7Xq2A+IjH7B6VN/S/bv
-8lhp2V+SQvlew9GttKC4hKuPsl5o7+CMbcqcNUdxm9gGkN8epGEKCuix97bpNlxN
-fHZxHE5+8GMzPXMkCD56y5TNKR6ut7JGHMPtGl5lPCLqzG/HzYyFgxsDfDUu2B0A
-GKj0lGpnLfGqwhs2/s3jpY7+pcvVQxEpvVTId5byDxu1ujP4HjO/VTQ2P72rE8Ft
-C6J2Av0tAgMBAAGjUDBOMB0GA1UdDgQWBBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAf
-BgNVHSMEGDAWgBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAMBgNVHRMEBTADAQH/MA0G
-CSqGSIb3DQEBCwUAA4ICAQB3sCntCcQwhMgRPPyvOCMyTcQ/Iv+cpfxz2Ck14nlx
-AkEAH2CH0ov5GWTt07/ur3aa5x+SAKi0J3wTD1cdiw4U/6Uin6jWGKKxvoo4IaeK
-SbM8w/6eKx6UbmHx7PA/eRABY9tTlpdPCVgw7/o3WDr03QM+IAtatzvaCPPczake
-pbdLwmBZB/v8V+6jUajy6jOgdSH0PyffGnt7MWgDETmNC6p/Xigp5eh+C8Fb4NGT
-xgHES5PBC+sruWp4u22bJGDKTvYNdZHsnw/CaKQWNsQqwisxa3/8N5v+PCff/pxl
-r05pE3PdHn9JrCl4iWdVlgtiI9BoPtQyDfa/OEFaScE8KYR8LxaAgdgp3zYncWls
-BpwQ6Y/A2wIkhlD9eEp5Ib2hz7isXOs9UwjdriKqrBXqcIAE5M+YIk3+KAQKxAtd
-4YsK3CSJ010uphr12YKqlScj4vuKFjuOtd5RyyMIxUG3lrrhAu2AzCeKCLdVgA8+
-75FrYMApUdvcjp4uzbBoED4XRQlx9kdFHVbYgmE/+yddBYJM8u4YlgAL0hW2/D8p
-z9JWIfxVmjJnBnXaKGBuiUyZ864A3PJndP6EMMo7TzS2CDnfCYuJjvI0KvDjFNmc
-rQA04+qfMSEz3nmKhbbZu4eYLzlADhfH8tT4GMtXf71WLA5AUHGf2Y4+HIHTsmHG
-vQ==
------END CERTIFICATE-----
diff --git a/src/crypto/x509/testdata/test-dir.crt b/src/crypto/x509/testdata/test-dir.crt
deleted file mode 100644
index b7fc9c5..0000000
--- a/src/crypto/x509/testdata/test-dir.crt
+++ /dev/null
@@ -1,31 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFazCCA1OgAwIBAgIJAL8a/lsnspOqMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
-BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
-dHMxETAPBgNVBAMMCHRlc3QtZGlyMB4XDTE3MDIwMTIzNTAyN1oXDTI3MDEzMDIz
-NTAyN1owTDELMAkGA1UEBhMCVUsxEzARBgNVBAgMClRlc3QtU3RhdGUxFTATBgNV
-BAoMDEdvbGFuZyBUZXN0czERMA8GA1UEAwwIdGVzdC1kaXIwggIiMA0GCSqGSIb3
-DQEBAQUAA4ICDwAwggIKAoICAQDzBoi43Yn30KN13PKFHu8LA4UmgCRToTukLItM
-WK2Je45grs/axg9n3YJOXC6hmsyrkOnyBcx1xVNgSrOAll7fSjtChRIX72Xrloxu
-XewtWVIrijqz6oylbvEmbRT3O8uynu5rF82Pmdiy8oiSfdywjKuPnE0hjV1ZSCql
-MYcXqA+f0JFD8kMv4pbtxjGH8f2DkYQz+hHXLrJH4/MEYdVMQXoz/GDzLyOkrXBN
-hpMaBBqg1p0P+tRdfLXuliNzA9vbZylzpF1YZ0gvsr0S5Y6LVtv7QIRygRuLY4kF
-k+UYuFq8NrV8TykS7FVnO3tf4XcYZ7r2KV5FjYSrJtNNo85BV5c3xMD3fJ2XcOWk
-+oD1ATdgAM3aKmSOxNtNItKKxBe1mkqDH41NbWx7xMad78gDznyeT0tjEOltN2bM
-uXU1R/jgR/vq5Ec0AhXJyL/ziIcmuV2fSl/ZxT4ARD+16tgPiIx+welTf0v27/JY
-adlfkkL5XsPRrbSguISrj7JeaO/gjG3KnDVHcZvYBpDfHqRhCgrosfe26TZcTXx2
-cRxOfvBjMz1zJAg+esuUzSkerreyRhzD7RpeZTwi6sxvx82MhYMbA3w1LtgdABio
-9JRqZy3xqsIbNv7N46WO/qXL1UMRKb1UyHeW8g8btboz+B4zv1U0Nj+9qxPBbQui
-dgL9LQIDAQABo1AwTjAdBgNVHQ4EFgQUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwHwYD
-VR0jBBgwFoAUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwDAYDVR0TBAUwAwEB/zANBgkq
-hkiG9w0BAQsFAAOCAgEAvEVnUYsIOt87rggmLPqEueynkuQ+562M8EDHSQl82zbe
-xDCxeg3DvPgKb+RvaUdt1362z/szK10SoeMgx6+EQLoV9LiVqXwNqeYfixrhrdw3
-ppAhYYhymdkbUQCEMHypmXP1vPhAz4o8Bs+eES1M+zO6ErBiD7SqkmBElT+GixJC
-6epC9ZQFs+dw3lPlbiZSsGE85sqc3VAs0/JgpL/pb1/Eg4s0FUhZD2C2uWdSyZGc
-g0/v3aXJCp4j/9VoNhI1WXz3M45nysZIL5OQgXymLqJElQa1pZ3Wa4i/nidvT4AT
-Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt
-3UFGzYXDjxYnK2frQfjLS8stOQIqSrGthW6x0fdkVx0y8BByvd5J6+JmZl4UZfzA
-m99VxXSt4B9x6BvnY7ktzcFDOjtuLc4B/7yg9fv1eQuStA4cHGGAttsCg1X/Kx8W
-PvkkeH0UWDZ9vhH9K36703z89da6MWF+bz92B0+4HoOmlVaXRkvblsNaynJnL0LC
-Ayry7QBxuh5cMnDdRwJB3AVJIiJ1GVpb7aGvBOnx+s2lwRv9HWtghb+cbwwktx1M
-JHyBf3GZNSWTpKY7cD8V+NnBv3UuioOVVo+XAU4LF/bYUjdRpxWADJizNtZrtFo=
------END CERTIFICATE-----
diff --git a/src/net/http/internal/testcert.go b/src/net/http/internal/testcert.go
index 2284a83..a33d06b 100644
--- a/src/net/http/internal/testcert.go
+++ b/src/net/http/internal/testcert.go
@@ -10,36 +10,9 @@ import "strings"
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
// generated from src/crypto/tls:
// go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
-var LocalhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
-MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
-MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
-iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
-rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
-BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
-AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
-AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
-tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
-h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
-fblo6RBxUQ==
------END CERTIFICATE-----`)
+var LocalhostCert = []byte(``)
// LocalhostKey is the private key for localhostCert.
-var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
-MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
-SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
-l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
-AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
-3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
-uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
-qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
-jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
-fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
-fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
-y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
-qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
-f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
------END RSA TESTING KEY-----`))
+var LocalhostKey = []byte(testingKey(``))
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
--
2.17.1

View File

@ -1,363 +0,0 @@
From 2ad2c042555908cfd791b7e6a3318c1d3df10aeb Mon Sep 17 00:00:00 2001
From: Roberto Clapis <roberto@golang.org>
Date: Wed, 26 Aug 2020 08:53:03 +0200
Subject: [PATCH] net/http/cgi,net/http/fcgi: add Content-Type detection
This CL ensures that responses served via CGI and FastCGI
have a Content-Type header based on the content of the
response if not explicitly set by handlers.
If the implementers of the handler did not explicitly
specify a Content-Type both CGI implementations would default
to "text/html", potentially causing cross-site scripting.
Thanks to RedTeam Pentesting GmbH for reporting this.
Fixes #40928
Fixes CVE-2020-24553
Change-Id: I82cfc396309b5ab2e8d6e9a87eda8ea7e3799473
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/823217
Reviewed-by: Russ Cox <rsc@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/252179
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
---
src/net/http/cgi/child.go | 36 ++++++++++++------
src/net/http/cgi/child_test.go | 58 +++++++++++++++++++++++++++++
src/net/http/cgi/matryoshka_test.go | 8 +++-
src/net/http/fcgi/child.go | 39 ++++++++++++++-----
src/net/http/fcgi/fcgi_test.go | 52 ++++++++++++++++++++++++++
5 files changed, 171 insertions(+), 22 deletions(-)
diff --git a/src/net/http/cgi/child.go b/src/net/http/cgi/child.go
index cb140f8f2f..2b210ea4a1 100644
--- a/src/net/http/cgi/child.go
+++ b/src/net/http/cgi/child.go
@@ -165,10 +165,12 @@ func Serve(handler http.Handler) error {
}
type response struct {
- req *http.Request
- header http.Header
- bufw *bufio.Writer
- headerSent bool
+ req *http.Request
+ header http.Header
+ code int
+ wroteHeader bool
+ wroteCGIHeader bool
+ bufw *bufio.Writer
}
func (r *response) Flush() {
@@ -180,26 +182,38 @@ func (r *response) Header() http.Header {
}
func (r *response) Write(p []byte) (n int, err error) {
- if !r.headerSent {
+ if !r.wroteHeader {
r.WriteHeader(http.StatusOK)
}
+ if !r.wroteCGIHeader {
+ r.writeCGIHeader(p)
+ }
return r.bufw.Write(p)
}
func (r *response) WriteHeader(code int) {
- if r.headerSent {
+ if r.wroteHeader {
// Note: explicitly using Stderr, as Stdout is our HTTP output.
fmt.Fprintf(os.Stderr, "CGI attempted to write header twice on request for %s", r.req.URL)
return
}
- r.headerSent = true
- fmt.Fprintf(r.bufw, "Status: %d %s\r\n", code, http.StatusText(code))
+ r.wroteHeader = true
+ r.code = code
+}
- // Set a default Content-Type
+// writeCGIHeader finalizes the header sent to the client and writes it to the output.
+// p is not written by writeHeader, but is the first chunk of the body
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly.
+func (r *response) writeCGIHeader(p []byte) {
+ if r.wroteCGIHeader {
+ return
+ }
+ r.wroteCGIHeader = true
+ fmt.Fprintf(r.bufw, "Status: %d %s\r\n", r.code, http.StatusText(r.code))
if _, hasType := r.header["Content-Type"]; !hasType {
- r.header.Add("Content-Type", "text/html; charset=utf-8")
+ r.header.Set("Content-Type", http.DetectContentType(p))
}
-
r.header.Write(r.bufw)
r.bufw.WriteString("\r\n")
r.bufw.Flush()
diff --git a/src/net/http/cgi/child_test.go b/src/net/http/cgi/child_test.go
index 14e0af475f..18cf789bd5 100644
--- a/src/net/http/cgi/child_test.go
+++ b/src/net/http/cgi/child_test.go
@@ -7,6 +7,11 @@
package cgi
import (
+ "bufio"
+ "bytes"
+ "net/http"
+ "net/http/httptest"
+ "strings"
"testing"
)
@@ -148,3 +153,56 @@ func TestRequestWithoutRemotePort(t *testing.T) {
t.Errorf("RemoteAddr: got %q; want %q", g, e)
}
}
+
+func TestResponse(t *testing.T) {
+ var tests = []struct {
+ name string
+ body string
+ wantCT string
+ }{
+ {
+ name: "no body",
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "html",
+ body: "<html><head><title>test page</title></head><body>This is a body</body></html>",
+ wantCT: "text/html; charset=utf-8",
+ },
+ {
+ name: "text",
+ body: strings.Repeat("gopher", 86),
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "jpg",
+ body: "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+ wantCT: "image/jpeg",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ var buf bytes.Buffer
+ resp := response{
+ req: httptest.NewRequest("GET", "/", nil),
+ header: http.Header{},
+ bufw: bufio.NewWriter(&buf),
+ }
+ n, err := resp.Write([]byte(tt.body))
+ if err != nil {
+ t.Errorf("Write: unexpected %v", err)
+ }
+ if want := len(tt.body); n != want {
+ t.Errorf("reported short Write: got %v want %v", n, want)
+ }
+ resp.writeCGIHeader(nil)
+ resp.Flush()
+ if got := resp.Header().Get("Content-Type"); got != tt.wantCT {
+ t.Errorf("wrong content-type: got %q, want %q", got, tt.wantCT)
+ }
+ if !bytes.HasSuffix(buf.Bytes(), []byte(tt.body)) {
+ t.Errorf("body was not correctly written")
+ }
+ })
+ }
+}
diff --git a/src/net/http/cgi/matryoshka_test.go b/src/net/http/cgi/matryoshka_test.go
index 32d59c09a3..41a27889f2 100644
--- a/src/net/http/cgi/matryoshka_test.go
+++ b/src/net/http/cgi/matryoshka_test.go
@@ -16,7 +16,9 @@ import (
"io"
"net/http"
"net/http/httptest"
+ "net/url"
"os"
+ "strings"
"testing"
"time"
)
@@ -52,7 +54,7 @@ func TestHostingOurselves(t *testing.T) {
}
replay := runCgiTest(t, h, "GET /test.go?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
- if expected, got := "text/html; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
+ if expected, got := "text/plain; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
t.Errorf("got a Content-Type of %q; expected %q", got, expected)
}
if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
@@ -203,6 +205,10 @@ func TestBeChildCGIProcess(t *testing.T) {
if req.FormValue("no-body") == "1" {
return
}
+ if eb, ok := req.Form["exact-body"]; ok {
+ io.WriteString(rw, eb[0])
+ return
+ }
if req.FormValue("write-forever") == "1" {
io.Copy(rw, neverEnding('a'))
for {
diff --git a/src/net/http/fcgi/child.go b/src/net/http/fcgi/child.go
index 30a6b2ce2d..a31273b3ec 100644
--- a/src/net/http/fcgi/child.go
+++ b/src/net/http/fcgi/child.go
@@ -74,10 +74,12 @@ func (r *request) parseParams() {
// response implements http.ResponseWriter.
type response struct {
- req *request
- header http.Header
- w *bufWriter
- wroteHeader bool
+ req *request
+ header http.Header
+ code int
+ wroteHeader bool
+ wroteCGIHeader bool
+ w *bufWriter
}
func newResponse(c *child, req *request) *response {
@@ -92,11 +94,14 @@ func (r *response) Header() http.Header {
return r.header
}
-func (r *response) Write(data []byte) (int, error) {
+func (r *response) Write(p []byte) (n int, err error) {
if !r.wroteHeader {
r.WriteHeader(http.StatusOK)
}
- return r.w.Write(data)
+ if !r.wroteCGIHeader {
+ r.writeCGIHeader(p)
+ }
+ return r.w.Write(p)
}
func (r *response) WriteHeader(code int) {
@@ -104,22 +109,34 @@ func (r *response) WriteHeader(code int) {
return
}
r.wroteHeader = true
+ r.code = code
if code == http.StatusNotModified {
// Must not have body.
r.header.Del("Content-Type")
r.header.Del("Content-Length")
r.header.Del("Transfer-Encoding")
- } else if r.header.Get("Content-Type") == "" {
- r.header.Set("Content-Type", "text/html; charset=utf-8")
}
-
if r.header.Get("Date") == "" {
r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
}
+}
- fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
+// writeCGIHeader finalizes the header sent to the client and writes it to the output.
+// p is not written by writeHeader, but is the first chunk of the body
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly.
+func (r *response) writeCGIHeader(p []byte) {
+ if r.wroteCGIHeader {
+ return
+ }
+ r.wroteCGIHeader = true
+ fmt.Fprintf(r.w, "Status: %d %s\r\n", r.code, http.StatusText(r.code))
+ if _, hasType := r.header["Content-Type"]; r.code != http.StatusNotModified && !hasType {
+ r.header.Set("Content-Type", http.DetectContentType(p))
+ }
r.header.Write(r.w)
r.w.WriteString("\r\n")
+ r.w.Flush()
}
func (r *response) Flush() {
@@ -290,6 +307,8 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
httpReq = httpReq.WithContext(envVarCtx)
c.handler.ServeHTTP(r, httpReq)
}
+ // Make sure we serve something even if nothing was written to r
+ r.Write(nil)
r.Close()
c.mu.Lock()
delete(c.requests, req.reqId)
diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go
index e9d2b34023..4a27a12c35 100644
--- a/src/net/http/fcgi/fcgi_test.go
+++ b/src/net/http/fcgi/fcgi_test.go
@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"net/http"
+ "strings"
"testing"
)
@@ -344,3 +345,54 @@ func TestChildServeReadsEnvVars(t *testing.T) {
<-done
}
}
+
+func TestResponseWriterSniffsContentType(t *testing.T) {
+ var tests = []struct {
+ name string
+ body string
+ wantCT string
+ }{
+ {
+ name: "no body",
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "html",
+ body: "<html><head><title>test page</title></head><body>This is a body</body></html>",
+ wantCT: "text/html; charset=utf-8",
+ },
+ {
+ name: "text",
+ body: strings.Repeat("gopher", 86),
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "jpg",
+ body: "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+ wantCT: "image/jpeg",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ input := make([]byte, len(streamFullRequestStdin))
+ copy(input, streamFullRequestStdin)
+ rc := nopWriteCloser{bytes.NewBuffer(input)}
+ done := make(chan bool)
+ var resp *response
+ c := newChild(rc, http.HandlerFunc(func(
+ w http.ResponseWriter,
+ r *http.Request,
+ ) {
+ io.WriteString(w, tt.body)
+ resp = w.(*response)
+ done <- true
+ }))
+ defer c.cleanUp()
+ go c.serve()
+ <-done
+ if got := resp.Header().Get("Content-Type"); got != tt.wantCT {
+ t.Errorf("got a Content-Type of %q; expected it to start with %q", got, tt.wantCT)
+ }
+ })
+ }
+}
--
2.17.1

View File

@ -1,413 +0,0 @@
From 24fb490f5c5ba855ad9feba179f820a835f68d66 Mon Sep 17 00:00:00 2001
From: liuzekun <liuzekun@huawei.com>
Date: Tue, 1 Dec 2020 22:50:08 -0500
Subject: [PATCH] golang: fix CVE-2020-28366
Upstream: https://github.com/golang/go/commit/062e0e5ce6df339dc26732438ad771f73dbf2292
cmd/go, cmd/cgo: don't let bogus symbol set cgo_ldflag
A hand-edited object file can have a symbol name that uses newline and
other normally invalid characters. The cgo tool will generate Go files
containing symbol names, unquoted. That can permit those symbol names
to inject Go code into a cgo-generated file. If that Go code uses the
//go:cgo_ldflag pragma, it can cause the C linker to run arbitrary
code when building a package. If you build an imported package we
permit arbitrary code at run time, but we don't want to permit it at
package build time. This CL prevents this in two ways.
In cgo, reject invalid symbols that contain non-printable or space
characters, or that contain anything that looks like a Go comment.
In the go tool, double check all //go:cgo_ldflag directives in
generated code, to make sure they follow the existing LDFLAG restrictions.
Thanks to Imre Rad / https://www.linkedin.com/in/imre-rad-2358749b for
reporting this.
Fixes CVE-2020-28367
Change-Id: Ia1ad8f3791ea79612690fa7d26ac451d0f6df7c1
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/895832
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/269658
Trust: Katie Hockman <katie@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Signed-off-by: liuzekun <liuzekun@huawei.com>
---
misc/cgo/errors/badsym_test.go | 216 +++++++++++++++++++++++++++++++
src/cmd/cgo/out.go | 24 ++++
src/cmd/go/internal/work/exec.go | 60 +++++++++
3 files changed, 300 insertions(+)
create mode 100644 misc/cgo/errors/badsym_test.go
diff --git a/misc/cgo/errors/badsym_test.go b/misc/cgo/errors/badsym_test.go
new file mode 100644
index 0000000..b2701bf
--- /dev/null
+++ b/misc/cgo/errors/badsym_test.go
@@ -0,0 +1,216 @@
+// Copyright 2020 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.
+
+package errorstest
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+ "unicode"
+)
+
+// A manually modified object file could pass unexpected characters
+// into the files generated by cgo.
+
+const magicInput = "abcdefghijklmnopqrstuvwxyz0123"
+const magicReplace = "\n//go:cgo_ldflag \"-badflag\"\n//"
+
+const cSymbol = "BadSymbol" + magicInput + "Name"
+const cDefSource = "int " + cSymbol + " = 1;"
+const cRefSource = "extern int " + cSymbol + "; int F() { return " + cSymbol + "; }"
+
+// goSource is the source code for the trivial Go file we use.
+// We will replace TMPDIR with the temporary directory name.
+const goSource = `
+package main
+
+// #cgo LDFLAGS: TMPDIR/cbad.o TMPDIR/cbad.so
+// extern int F();
+import "C"
+
+func main() {
+ println(C.F())
+}
+`
+
+func TestBadSymbol(t *testing.T) {
+ dir := t.TempDir()
+
+ mkdir := func(base string) string {
+ ret := filepath.Join(dir, base)
+ if err := os.Mkdir(ret, 0755); err != nil {
+ t.Fatal(err)
+ }
+ return ret
+ }
+
+ cdir := mkdir("c")
+ godir := mkdir("go")
+
+ makeFile := func(mdir, base, source string) string {
+ ret := filepath.Join(mdir, base)
+ if err := ioutil.WriteFile(ret, []byte(source), 0644); err != nil {
+ t.Fatal(err)
+ }
+ return ret
+ }
+
+ cDefFile := makeFile(cdir, "cdef.c", cDefSource)
+ cRefFile := makeFile(cdir, "cref.c", cRefSource)
+
+ ccCmd := cCompilerCmd(t)
+
+ cCompile := func(arg, base, src string) string {
+ out := filepath.Join(cdir, base)
+ run := append(ccCmd, arg, "-o", out, src)
+ output, err := exec.Command(run[0], run[1:]...).CombinedOutput()
+ if err != nil {
+ t.Log(run)
+ t.Logf("%s", output)
+ t.Fatal(err)
+ }
+ if err := os.Remove(src); err != nil {
+ t.Fatal(err)
+ }
+ return out
+ }
+
+ // Build a shared library that defines a symbol whose name
+ // contains magicInput.
+
+ cShared := cCompile("-shared", "c.so", cDefFile)
+
+ // Build an object file that refers to the symbol whose name
+ // contains magicInput.
+
+ cObj := cCompile("-c", "c.o", cRefFile)
+
+ // Rewrite the shared library and the object file, replacing
+ // magicInput with magicReplace. This will have the effect of
+ // introducing a symbol whose name looks like a cgo command.
+ // The cgo tool will use that name when it generates the
+ // _cgo_import.go file, thus smuggling a magic //go:cgo_ldflag
+ // pragma into a Go file. We used to not check the pragmas in
+ // _cgo_import.go.
+
+ rewrite := func(from, to string) {
+ obj, err := ioutil.ReadFile(from)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if bytes.Count(obj, []byte(magicInput)) == 0 {
+ t.Fatalf("%s: did not find magic string", from)
+ }
+
+ if len(magicInput) != len(magicReplace) {
+ t.Fatalf("internal test error: different magic lengths: %d != %d", len(magicInput), len(magicReplace))
+ }
+
+ obj = bytes.ReplaceAll(obj, []byte(magicInput), []byte(magicReplace))
+
+ if err := ioutil.WriteFile(to, obj, 0644); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ cBadShared := filepath.Join(godir, "cbad.so")
+ rewrite(cShared, cBadShared)
+
+ cBadObj := filepath.Join(godir, "cbad.o")
+ rewrite(cObj, cBadObj)
+
+ goSourceBadObject := strings.ReplaceAll(goSource, "TMPDIR", godir)
+ makeFile(godir, "go.go", goSourceBadObject)
+
+ makeFile(godir, "go.mod", "module badsym")
+
+ // Try to build our little package.
+ cmd := exec.Command("go", "build", "-ldflags=-v")
+ cmd.Dir = godir
+ output, err := cmd.CombinedOutput()
+
+ // The build should fail, but we want it to fail because we
+ // detected the error, not because we passed a bad flag to the
+ // C linker.
+
+ if err == nil {
+ t.Errorf("go build succeeded unexpectedly")
+ }
+
+ t.Logf("%s", output)
+
+ for _, line := range bytes.Split(output, []byte("\n")) {
+ if bytes.Contains(line, []byte("dynamic symbol")) && bytes.Contains(line, []byte("contains unsupported character")) {
+ // This is the error from cgo.
+ continue
+ }
+
+ // We passed -ldflags=-v to see the external linker invocation,
+ // which should not include -badflag.
+ if bytes.Contains(line, []byte("-badflag")) {
+ t.Error("output should not mention -badflag")
+ }
+
+ // Also check for compiler errors, just in case.
+ // GCC says "unrecognized command line option".
+ // clang says "unknown argument".
+ if bytes.Contains(line, []byte("unrecognized")) || bytes.Contains(output, []byte("unknown")) {
+ t.Error("problem should have been caught before invoking C linker")
+ }
+ }
+}
+
+func cCompilerCmd(t *testing.T) []string {
+ cc := []string{goEnv(t, "CC")}
+
+ out := goEnv(t, "GOGCCFLAGS")
+ quote := '\000'
+ start := 0
+ lastSpace := true
+ backslash := false
+ s := string(out)
+ for i, c := range s {
+ if quote == '\000' && unicode.IsSpace(c) {
+ if !lastSpace {
+ cc = append(cc, s[start:i])
+ lastSpace = true
+ }
+ } else {
+ if lastSpace {
+ start = i
+ lastSpace = false
+ }
+ if quote == '\000' && !backslash && (c == '"' || c == '\'') {
+ quote = c
+ backslash = false
+ } else if !backslash && quote == c {
+ quote = '\000'
+ } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
+ backslash = true
+ } else {
+ backslash = false
+ }
+ }
+ }
+ if !lastSpace {
+ cc = append(cc, s[start:])
+ }
+ return cc
+}
+
+func goEnv(t *testing.T, key string) string {
+ out, err := exec.Command("go", "env", key).CombinedOutput()
+ if err != nil {
+ t.Logf("go env %s\n", key)
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+ return strings.TrimSpace(string(out))
+}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 1fddbb6..65a8d66 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -22,6 +22,7 @@ import (
"regexp"
"sort"
"strings"
+ "unicode"
)
var (
@@ -325,6 +326,8 @@ func dynimport(obj string) {
if s.Version != "" {
targ += "#" + s.Version
}
+ checkImportSymName(s.Name)
+ checkImportSymName(targ)
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
}
lib, _ := f.ImportedLibraries()
@@ -340,6 +343,7 @@ func dynimport(obj string) {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
+ checkImportSymName(s)
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
}
lib, _ := f.ImportedLibraries()
@@ -354,6 +358,8 @@ func dynimport(obj string) {
for _, s := range sym {
ss := strings.Split(s, ":")
name := strings.Split(ss[0], "@")[0]
+ checkImportSymName(name)
+ checkImportSymName(ss[0])
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
}
return
@@ -371,6 +377,7 @@ func dynimport(obj string) {
// Go symbols.
continue
}
+ checkImportSymName(s.Name)
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
}
lib, err := f.ImportedLibraries()
@@ -386,6 +393,23 @@ func dynimport(obj string) {
fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
}
+// checkImportSymName checks a symbol name we are going to emit as part
+// of a //go:cgo_import_dynamic pragma. These names come from object
+// files, so they may be corrupt. We are going to emit them unquoted,
+// so while they don't need to be valid symbol names (and in some cases,
+// involving symbol versions, they won't be) they must contain only
+// graphic characters and must not contain Go comments.
+func checkImportSymName(s string) {
+ for _, c := range s {
+ if !unicode.IsGraphic(c) || unicode.IsSpace(c) {
+ fatalf("dynamic symbol %q contains unsupported character", s)
+ }
+ }
+ if strings.Index(s, "//") >= 0 || strings.Index(s, "/*") >= 0 {
+ fatalf("dynamic symbol %q contains Go comment")
+ }
+}
+
// Construct a gcc struct matching the gc argument frame.
// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
// These assumptions are checked by the gccProlog.
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 7dd9a90..0e5c34f 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2630,6 +2630,66 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
noCompiler()
}
+ // Double check the //go:cgo_ldflag comments in the generated files.
+ // The compiler only permits such comments in files whose base name
+ // starts with "_cgo_". Make sure that the comments in those files
+ // are safe. This is a backstop against people somehow smuggling
+ // such a comment into a file generated by cgo.
+ if cfg.BuildToolchainName == "gc" && !cfg.BuildN {
+ var flags []string
+ for _, f := range outGo {
+ if !strings.HasPrefix(filepath.Base(f), "_cgo_") {
+ continue
+ }
+
+ src, err := ioutil.ReadFile(f)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ const cgoLdflag = "//go:cgo_ldflag"
+ idx := bytes.Index(src, []byte(cgoLdflag))
+ for idx >= 0 {
+ // We are looking at //go:cgo_ldflag.
+ // Find start of line.
+ start := bytes.LastIndex(src[:idx], []byte("\n"))
+ if start == -1 {
+ start = 0
+ }
+
+ // Find end of line.
+ end := bytes.Index(src[idx:], []byte("\n"))
+ if end == -1 {
+ end = len(src)
+ } else {
+ end += idx
+ }
+
+ // Check for first line comment in line.
+ // We don't worry about /* */ comments,
+ // which normally won't appear in files
+ // generated by cgo.
+ commentStart := bytes.Index(src[start:], []byte("//"))
+ commentStart += start
+ // If that line comment is //go:cgo_ldflag,
+ // it's a match.
+ if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) {
+ // Pull out the flag, and unquote it.
+ // This is what the compiler does.
+ flag := string(src[idx+len(cgoLdflag) : end])
+ flag = strings.TrimSpace(flag)
+ flag = strings.Trim(flag, `"`)
+ flags = append(flags, flag)
+ }
+ src = src[end:]
+ idx = bytes.Index(src, []byte(cgoLdflag))
+ }
+ }
+ if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil {
+ return nil, nil, err
+ }
+ }
+
return outGo, outObj, nil
}
--
2.19.1

View File

@ -1,67 +0,0 @@
From ac9a264a575bbbc9de2374a65a6c8fd50c32000d Mon Sep 17 00:00:00 2001
From: liuzekun <liuzekun@huawei.com>
Date: Mon, 30 Nov 2020 22:18:43 -0500
Subject: [PATCH] golang: fix CVE-2020-28367
Upstream: https://github.com/golang/go/commit/da7aa86917811a571e6634b45a457f918b8e6561
cmd/go: in cgoflags, permit -DX1, prohibit -Wp,-D,opt
Restrict -D and -U to ASCII C identifiers, but do permit trailing digits.
When using -Wp, prohibit commas in -D values.
Change-Id: Ibfc4dfdd6e6c258e131448e7682610c44eee9492
Reviewed-on: https://go-review.googlesource.com/c/go/+/267277
Trust: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
---
src/cmd/go/internal/work/security.go | 4 ++--
src/cmd/go/internal/work/security_test.go | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
index 0d8da21..b00c21e 100644
--- a/src/cmd/go/internal/work/security.go
+++ b/src/cmd/go/internal/work/security.go
@@ -42,7 +42,7 @@ import (
var re = lazyregexp.New
var validCompilerFlags = []*lazyregexp.Regexp{
- re(`-D([A-Za-z_].*)`),
+ re(`-D([A-Za-z_][A-Za-z0-9_]*)(=[^@\-]*)?`),
re(`-F([^@\-].*)`),
re(`-I([^@\-].*)`),
re(`-O`),
@@ -50,7 +50,7 @@ var validCompilerFlags = []*lazyregexp.Regexp{
re(`-W`),
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
re(`-Wa,-mbig-obj`),
- re(`-Wp,-D([A-Za-z_].*)`),
+ re(`-Wp,-D([A-Za-z_][A-Za-z0-9_]*)(=[^@,\-]*)?`),
re(`-ansi`),
re(`-f(no-)?asynchronous-unwind-tables`),
re(`-f(no-)?blocks`),
diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go
index fd8caea..eac029d 100644
--- a/src/cmd/go/internal/work/security_test.go
+++ b/src/cmd/go/internal/work/security_test.go
@@ -21,6 +21,7 @@ var goodCompilerFlags = [][]string{
{"-Osmall"},
{"-W"},
{"-Wall"},
+ {"-Wp,-Dfoo1"},
{"-fobjc-arc"},
{"-fno-objc-arc"},
{"-fomit-frame-pointer"},
@@ -70,6 +71,7 @@ var badCompilerFlags = [][]string{
{"-I-dir"},
{"-O@1"},
{"-Wa,-foo"},
+ {"-Wp,-DX,-D@X"},
{"-W@foo"},
{"-g@gdb"},
{"-g-gdb"},
--
2.19.1

View File

@ -1,118 +0,0 @@
From 96ffe2941c07e4a6b92357b6eb8739304f839bef Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 23 Dec 2020 15:58:14 +0800
Subject: [PATCH 1/2] encoding/xml: handle leading, trailing, or double colons
in names
Before this change, <:name> would parse as <name>, which could cause
issues in applications that rely on the parse-encode cycle to
round-trip. Similarly, <x name:=""> would parse as expected but then
have the attribute dropped when serializing because its name was empty.
Finally, <a:b:c> would parse and get serialized incorrectly. All these
values are invalid XML, but to minimize the impact of this change, we
parse them whole into Name.Local.
This issue was reported by Juho Nurminen of Mattermost as it leads to
round-trip mismatches. See #43168. It's not being fixed in a security
release because round-trip stability is not a currently supported
security property of encoding/xml, and we don't believe these fixes
would be sufficient to reliably guarantee it in the future.
Fixes CVE-2020-29509
Fixes CVE-2020-29511
Updates #43168
Conflict: NA
Reference: https://go-review.googlesource.com/c/go/+/277892
Change-Id: I68321c4d867305046f664347192948a889af3c7f
Signed-off-by: jingrui <jingrui@huawei.com>
---
src/encoding/xml/xml.go | 5 ++--
src/encoding/xml/xml_test.go | 58 ++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go
index ca059440a1..073ceee1b2 100644
--- a/src/encoding/xml/xml.go
+++ b/src/encoding/xml/xml.go
@@ -1152,8 +1152,9 @@ func (d *Decoder) nsname() (name Name, ok bool) {
if !ok {
return
}
- i := strings.Index(s, ":")
- if i < 0 {
+ if strings.Count(s, ":") > 1 {
+ name.Local = s
+ } else if i := strings.Index(s, ":"); i < 1 || i > len(s)-2 {
name.Local = s
} else {
name.Space = s[0:i]
diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go
index ee4ffa2420..eef4dc3001 100644
--- a/src/encoding/xml/xml_test.go
+++ b/src/encoding/xml/xml_test.go
@@ -898,3 +898,61 @@ func TestTokenUnmarshaler(t *testing.T) {
d := NewTokenDecoder(tokReader{})
d.Decode(&Failure{})
}
+
+func testRoundTrip(t *testing.T, input string) {
+ t.Logf("input: %q", input)
+ d := NewDecoder(strings.NewReader(input))
+ var tokens []Token
+ var buf bytes.Buffer
+ e := NewEncoder(&buf)
+ for {
+ tok, err := d.Token()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatalf("invalid input: %v", err)
+ }
+ if err := e.EncodeToken(tok); err != nil {
+ t.Fatalf("failed to re-encode input: %v", err)
+ }
+ tokens = append(tokens, CopyToken(tok))
+ }
+ if err := e.Flush(); err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("output: %q", buf.String())
+
+ d = NewDecoder(&buf)
+ for {
+ tok, err := d.Token()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatalf("failed to decode output: %v", err)
+ }
+ if len(tokens) == 0 {
+ t.Fatalf("unexpected token: %#v", tok)
+ }
+ a, b := tokens[0], tok
+ if !reflect.DeepEqual(a, b) {
+ t.Fatalf("token mismatch: %#v vs %#v", a, b)
+ }
+ tokens = tokens[1:]
+ }
+ if len(tokens) > 0 {
+ t.Fatalf("lost tokens: %#v", tokens)
+ }
+}
+
+func TestRoundTrip(t *testing.T) {
+ tests := map[string]string{
+ "leading colon": `<::Test ::foo="bar"><:::Hello></:::Hello><Hello></Hello></::Test>`,
+ "trailing colon": `<foo abc:="x"></foo>`,
+ "double colon": `<x:y:foo></x:y:foo>`,
+ }
+ for name, input := range tests {
+ t.Run(name, func(t *testing.T) { testRoundTrip(t, input) })
+ }
+}
--
2.17.1

View File

@ -1,62 +0,0 @@
From e2710c3983b3249ba30f2d21802c984aef5fb163 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 23 Dec 2020 16:03:15 +0800
Subject: [PATCH 2/2] encoding/xml: replace comments inside directives with a
space
A Directive (like <!ENTITY xxx []>) can't have other nodes nested inside
it (in our data structure representation), so there is no way to
preserve comments. The previous behavior was to just elide them, which
however might change the semantic meaning of the surrounding markup.
Instead, replace them with a space which hopefully has the same semantic
effect of the comment.
Directives are not actually a node type in the XML spec, which instead
specifies each of them separately (<!ENTITY, <!DOCTYPE, etc.), each with
its own grammar. The rules for where and when the comments are allowed
are not straightforward, and can't be implemented without implementing
custom logic for each of the directives.
Simply preserving the comments in the body of the directive would be
problematic, as there can be unmatched quotes inside the comment.
Whether those quotes are considered meaningful semantically or not,
other parsers might disagree and interpret the output differently.
This issue was reported by Juho Nurminen of Mattermost as it leads to
round-trip mismatches. See #43168. It's not being fixed in a security
release because round-trip stability is not a currently supported
security property of encoding/xml, and we don't believe these fixes
would be sufficient to reliably guarantee it in the future.
Fixes CVE-2020-29510
Updates #43168
Conflict: NA
Reference: https://go-review.googlesource.com/c/go/+/277893/1
Change-Id: Icd86c75beff3e1e0689543efebdad10ed5178ce3
Signed-off-by: jingrui <jingrui@huawei.com>
---
src/encoding/xml/xml.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go
index 073ceee1b2..3746018613 100644
--- a/src/encoding/xml/xml.go
+++ b/src/encoding/xml/xml.go
@@ -764,6 +764,12 @@ func (d *Decoder) rawToken() (Token, error) {
}
b0, b1 = b1, b
}
+
+ // Replace the comment with a space in the returned Directive
+ // body, so that markup parts that were separated by the comment
+ // (like a "<" and a "!") don't get joined when re-encoding the
+ // Directive, taking new semantic meaning.
+ d.buf.WriteByte(' ')
}
}
return Directive(d.buf.Bytes()), nil
--
2.17.1

View File

@ -61,8 +61,8 @@
%endif
Name: golang
Version: 1.13.15
Release: 2
Version: 1.15.7
Release: 1
Summary: The Go Programming Language
License: BSD and Public Domain
URL: https://golang.org/
@ -149,20 +149,6 @@ Obsoletes: %{name}-vim < 1.4
Obsoletes: emacs-%{name} < 1.4
Requires: openEuler-rpm-config
Patch6002: 0002-syscall-expose-IfInfomsg.X__ifi_pad-on-s390x.patch
Patch6003: 0003-golang-delete-pem-files.patch
Patch6004: 0004-syscall-implement-rawVforkSyscall-for-linux-arm64.patch
Patch6005: 0005-runtime-fix-crash-during-VDSO-calls-on-arm.patch
Patch6006: 0006-runtime-save-fetch-g-register-during-VDSO-on-ARM-and.patch
Patch6007: 0007-runtime-don-t-fetch-G-from-signal-stack-when-using-c.patch
Patch6008: 0008-runtime-don-t-save-G-during-VDSO-if-we-re-handling-s.patch
Patch6013: 0013-drop-hard-code-cert.patch
Patch6019: 0019-net-http-cgi-net-http-fcgi-add-Content-Type-detectio.patch
Patch6020: 0020-golang-fix-CVE-2020-28366.patch
Patch6021: 0021-golang-fix-CVE-2020-28367.patch
Patch6022: 0022-fix-CVE-2020-29509-CVE-2020-29511.patch
Patch6023: 0023-fix-CVE-2020-29510.patch
ExclusiveArch: %{golang_arches}
@ -395,6 +381,9 @@ fi
%files devel -f go-tests.list -f go-misc.list -f go-src.list
%changelog
* Thu Jan 28 2021 xingweizheng <xingweizheng@huawei.com> - 1.15.7-1
- upgrade to 1.15.7
* Mon Jan 18 2021 jingrui<jingrui@huawei.com> - 1.13.15-2
- sync cve fix