golang: upgrade to 1.15.7
Fixes: #I3B1LK Signed-off-by: DCCooper <1866858@gmail.com>
This commit is contained in:
parent
9ec5fee370
commit
76c5ebd313
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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-----
|
||||
-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
-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
-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
-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
-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
-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
-i0xYrYl7jmCuz9rGD2fdgk5cLqGazKuQ6fIFzHXFU2BKs4CWXt9KO0KFEhfvZeuW
|
||||
-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
-KqUxhxeoD5/QkUPyQy/ilu3GMYfx/YORhDP6Edcuskfj8wRh1UxBejP8YPMvI6St
|
||||
-cE2GkxoEGqDWnQ/61F18te6WI3MD29tnKXOkXVhnSC+yvRLljotW2/tAhHKBG4tj
|
||||
-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
-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
-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
-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
-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
-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
-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
-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
-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
-AkEAH2CH0ov5GWTt07/ur3aa5x+SAKi0J3wTD1cdiw4U/6Uin6jWGKKxvoo4IaeK
|
||||
-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
-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
-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
-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
-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
-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
-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
-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
-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
|
||||
-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-----
|
||||
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-+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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt
|
||||
-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
-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
-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
-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
-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
|
||||
------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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,457 +0,0 @@
|
||||
From dcfa9752c3b187ac5b6c232b36f208dbd23918e9 Mon Sep 17 00:00:00 2001
|
||||
From: Filippo Valsorda <filippo@golang.org>
|
||||
Date: Fri, 8 Jan 2021 03:56:58 +0100
|
||||
Subject: [PATCH] crypto/elliptic: fix P-224 field reduction
|
||||
|
||||
This patch fixes two independent bugs in p224Contract, the function that
|
||||
performs the final complete reduction in the P-224 field. Incorrect
|
||||
outputs due to these bugs were observable from a high-level
|
||||
P224().ScalarMult() call.
|
||||
|
||||
The first bug was in the calculation of out3GT. That mask was supposed
|
||||
to be all ones if the third limb of the value is greater than the third
|
||||
limb of P (out[3] > 0xffff000). Instead, it was also set if they are
|
||||
equal. That meant that if the third limb was equal, the value was always
|
||||
considered greater than or equal to P, even when the three bottom limbs
|
||||
were all zero. There is exactly one affected value, P - 1, which would
|
||||
trigger the subtraction by P even if it's lower than P already.
|
||||
|
||||
The second bug was more easily hit, and is the one that caused the known
|
||||
high-level incorrect output: after the conditional subtraction by P, a
|
||||
potential underflow of the lowest limb was not handled. Any values that
|
||||
trigger the subtraction by P (values between P and 2^224-1, and P - 1
|
||||
due to the bug above) but have a zero lowest limb would produce invalid
|
||||
outputs. Those conditions apply to the intermediate representation
|
||||
before the subtraction, so they are hard to trace to precise inputs.
|
||||
|
||||
This patch also adds a test suite for the P-224 field arithmetic,
|
||||
including a custom fuzzer that automatically explores potential edge
|
||||
cases by combining limb values that have various meanings in the code.
|
||||
contractMatchesBigInt in TestP224Contract finds the second bug in less
|
||||
than a second without being tailored to it, and could eventually find
|
||||
the first one too by combining 0, (1 << 28) - 1, and the difference of
|
||||
(1 << 28) and (1 << 12).
|
||||
|
||||
The incorrect P224().ScalarMult() output was found by the
|
||||
elliptic-curve-differential-fuzzer project running on OSS-Fuzz and
|
||||
reported by Philippe Antoine (Catena cyber).
|
||||
|
||||
Fixes CVE-2021-3114
|
||||
|
||||
Change-Id: I50176602d544de3da854270d66a293bcaca57ad7
|
||||
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/947792
|
||||
Reviewed-by: Katie Hockman <katiehockman@google.com>
|
||||
(cherry picked from commit 5fa534e9c7eaeaf875e53b98eac9342b0855b283)
|
||||
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/955175
|
||||
---
|
||||
src/crypto/elliptic/p224.go | 41 +++--
|
||||
src/crypto/elliptic/p224_test.go | 277 ++++++++++++++++++++++++++++++-
|
||||
2 files changed, 298 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go
|
||||
index 2ea63f3..8c76021 100644
|
||||
--- a/src/crypto/elliptic/p224.go
|
||||
+++ b/src/crypto/elliptic/p224.go
|
||||
@@ -386,10 +386,11 @@ func p224Invert(out, in *p224FieldElement) {
|
||||
// p224Contract converts a FieldElement to its unique, minimal form.
|
||||
//
|
||||
// On entry, in[i] < 2**29
|
||||
-// On exit, in[i] < 2**28
|
||||
+// On exit, out[i] < 2**28 and out < p
|
||||
func p224Contract(out, in *p224FieldElement) {
|
||||
copy(out[:], in[:])
|
||||
|
||||
+ // First, carry the bits above 28 to the higher limb.
|
||||
for i := 0; i < 7; i++ {
|
||||
out[i+1] += out[i] >> 28
|
||||
out[i] &= bottom28Bits
|
||||
@@ -397,10 +398,13 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
top := out[7] >> 28
|
||||
out[7] &= bottom28Bits
|
||||
|
||||
+ // Use the reduction identity to carry the overflow.
|
||||
+ //
|
||||
+ // a + top * 2²²⁴ = a + top * 2⁹⁶ - top
|
||||
out[0] -= top
|
||||
out[3] += top << 12
|
||||
|
||||
- // We may just have made out[i] negative. So we carry down. If we made
|
||||
+ // We may just have made out[0] negative. So we carry down. If we made
|
||||
// out[0] negative then we know that out[3] is sufficiently positive
|
||||
// because we just added to it.
|
||||
for i := 0; i < 3; i++ {
|
||||
@@ -425,13 +429,12 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
// There are two cases to consider for out[3]:
|
||||
// 1) The first time that we eliminated top, we didn't push out[3] over
|
||||
// 2**28. In this case, the partial carry chain didn't change any values
|
||||
- // and top is zero.
|
||||
+ // and top is now zero.
|
||||
// 2) We did push out[3] over 2**28 the first time that we eliminated top.
|
||||
- // The first value of top was in [0..16), therefore, prior to eliminating
|
||||
- // the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
|
||||
- // overflowing and being reduced by the second carry chain, out[3] <=
|
||||
- // 0xf000. Thus it cannot have overflowed when we eliminated top for the
|
||||
- // second time.
|
||||
+ // The first value of top was in [0..2], therefore, after overflowing
|
||||
+ // and being reduced by the second carry chain, out[3] <= 2<<12 - 1.
|
||||
+ // In both cases, out[3] cannot have overflowed when we eliminated top for
|
||||
+ // the second time.
|
||||
|
||||
// Again, we may just have made out[0] negative, so do the same carry down.
|
||||
// As before, if we made out[0] negative then we know that out[3] is
|
||||
@@ -470,12 +473,11 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
bottom3NonZero |= bottom3NonZero >> 1
|
||||
bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31)
|
||||
|
||||
- // Everything depends on the value of out[3].
|
||||
- // If it's > 0xffff000 and top4AllOnes != 0 then the whole value is >= p
|
||||
- // If it's = 0xffff000 and top4AllOnes != 0 and bottom3NonZero != 0,
|
||||
- // then the whole value is >= p
|
||||
+ // Assuming top4AllOnes != 0, everything depends on the value of out[3].
|
||||
+ // If it's > 0xffff000 then the whole value is > p
|
||||
+ // If it's = 0xffff000 and bottom3NonZero != 0, then the whole value is >= p
|
||||
// If it's < 0xffff000, then the whole value is < p
|
||||
- n := out[3] - 0xffff000
|
||||
+ n := 0xffff000 - out[3]
|
||||
out3Equal := n
|
||||
out3Equal |= out3Equal >> 16
|
||||
out3Equal |= out3Equal >> 8
|
||||
@@ -484,8 +486,8 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
out3Equal |= out3Equal >> 1
|
||||
out3Equal = ^uint32(int32(out3Equal<<31) >> 31)
|
||||
|
||||
- // If out[3] > 0xffff000 then n's MSB will be zero.
|
||||
- out3GT := ^uint32(int32(n) >> 31)
|
||||
+ // If out[3] > 0xffff000 then n's MSB will be one.
|
||||
+ out3GT := uint32(int32(n) >> 31)
|
||||
|
||||
mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)
|
||||
out[0] -= 1 & mask
|
||||
@@ -494,6 +496,15 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
out[5] -= 0xfffffff & mask
|
||||
out[6] -= 0xfffffff & mask
|
||||
out[7] -= 0xfffffff & mask
|
||||
+
|
||||
+ // Do one final carry down, in case we made out[0] negative. One of
|
||||
+ // out[0..3] needs to be positive and able to absorb the -1 or the value
|
||||
+ // would have been < p, and the subtraction wouldn't have happened.
|
||||
+ for i := 0; i < 3; i++ {
|
||||
+ mask := uint32(int32(out[i]) >> 31)
|
||||
+ out[i] += (1 << 28) & mask
|
||||
+ out[i+1] -= 1 & mask
|
||||
+ }
|
||||
}
|
||||
|
||||
// Group element functions.
|
||||
diff --git a/src/crypto/elliptic/p224_test.go b/src/crypto/elliptic/p224_test.go
|
||||
index 8b4fa04..eeb24d9 100644
|
||||
--- a/src/crypto/elliptic/p224_test.go
|
||||
+++ b/src/crypto/elliptic/p224_test.go
|
||||
@@ -6,7 +6,11 @@ package elliptic
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
+ "math/bits"
|
||||
+ "math/rand"
|
||||
+ "reflect"
|
||||
"testing"
|
||||
+ "testing/quick"
|
||||
)
|
||||
|
||||
var toFromBigTests = []string{
|
||||
@@ -21,16 +25,16 @@ func p224AlternativeToBig(in *p224FieldElement) *big.Int {
|
||||
ret := new(big.Int)
|
||||
tmp := new(big.Int)
|
||||
|
||||
- for i := uint(0); i < 8; i++ {
|
||||
+ for i := len(in) - 1; i >= 0; i-- {
|
||||
+ ret.Lsh(ret, 28)
|
||||
tmp.SetInt64(int64(in[i]))
|
||||
- tmp.Lsh(tmp, 28*i)
|
||||
ret.Add(ret, tmp)
|
||||
}
|
||||
- ret.Mod(ret, p224.P)
|
||||
+ ret.Mod(ret, P224().Params().P)
|
||||
return ret
|
||||
}
|
||||
|
||||
-func TestToFromBig(t *testing.T) {
|
||||
+func TestP224ToFromBig(t *testing.T) {
|
||||
for i, test := range toFromBigTests {
|
||||
n, _ := new(big.Int).SetString(test, 16)
|
||||
var x p224FieldElement
|
||||
@@ -41,7 +45,270 @@ func TestToFromBig(t *testing.T) {
|
||||
}
|
||||
q := p224AlternativeToBig(&x)
|
||||
if n.Cmp(q) != 0 {
|
||||
- t.Errorf("#%d: %x != %x (alternative)", i, n, m)
|
||||
+ t.Errorf("#%d: %x != %x (alternative)", i, n, q)
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+// quickCheckConfig32 will make each quickcheck test run (32 * -quickchecks)
|
||||
+// times. The default value of -quickchecks is 100.
|
||||
+var quickCheckConfig32 = &quick.Config{MaxCountScale: 32}
|
||||
+
|
||||
+// weirdLimbs can be combined to generate a range of edge-case field elements.
|
||||
+var weirdLimbs = [...]uint32{
|
||||
+ 0, 1, (1 << 29) - 1,
|
||||
+ (1 << 12), (1 << 12) - 1,
|
||||
+ (1 << 28), (1 << 28) - 1,
|
||||
+}
|
||||
+
|
||||
+func generateLimb(rand *rand.Rand) uint32 {
|
||||
+ const bottom29Bits = 0x1fffffff
|
||||
+ n := rand.Intn(len(weirdLimbs) + 3)
|
||||
+ switch n {
|
||||
+ case len(weirdLimbs):
|
||||
+ // Random value.
|
||||
+ return uint32(rand.Int31n(1 << 29))
|
||||
+ case len(weirdLimbs) + 1:
|
||||
+ // Sum of two values.
|
||||
+ k := generateLimb(rand) + generateLimb(rand)
|
||||
+ return k & bottom29Bits
|
||||
+ case len(weirdLimbs) + 2:
|
||||
+ // Difference of two values.
|
||||
+ k := generateLimb(rand) - generateLimb(rand)
|
||||
+ return k & bottom29Bits
|
||||
+ default:
|
||||
+ return weirdLimbs[n]
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func (p224FieldElement) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
+ return reflect.ValueOf(p224FieldElement{
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+func isInBounds(x *p224FieldElement) bool {
|
||||
+ return bits.Len32(x[0]) <= 29 &&
|
||||
+ bits.Len32(x[1]) <= 29 &&
|
||||
+ bits.Len32(x[2]) <= 29 &&
|
||||
+ bits.Len32(x[3]) <= 29 &&
|
||||
+ bits.Len32(x[4]) <= 29 &&
|
||||
+ bits.Len32(x[5]) <= 29 &&
|
||||
+ bits.Len32(x[6]) <= 29 &&
|
||||
+ bits.Len32(x[7]) <= 29
|
||||
+}
|
||||
+
|
||||
+func TestP224Mul(t *testing.T) {
|
||||
+ mulMatchesBigInt := func(a, b, out p224FieldElement) bool {
|
||||
+ var tmp p224LargeFieldElement
|
||||
+ p224Mul(&out, &a, &b, &tmp)
|
||||
+
|
||||
+ exp := new(big.Int).Mul(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
|
||||
+ exp.Mod(exp, P224().Params().P)
|
||||
+ got := p224AlternativeToBig(&out)
|
||||
+ if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||
+ t.Logf("a = %x", a)
|
||||
+ t.Logf("b = %x", b)
|
||||
+ t.Logf("p224Mul(a, b) = %x = %v", out, got)
|
||||
+ t.Logf("a * b = %v", exp)
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
+ return true
|
||||
+ }
|
||||
+
|
||||
+ a := p224FieldElement{0xfffffff, 0xfffffff, 0xf00ffff, 0x20f, 0x0, 0x0, 0x0, 0x0}
|
||||
+ b := p224FieldElement{1, 0, 0, 0, 0, 0, 0, 0}
|
||||
+ if !mulMatchesBigInt(a, b, p224FieldElement{}) {
|
||||
+ t.Fail()
|
||||
+ }
|
||||
+
|
||||
+ if err := quick.Check(mulMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
+ t.Error(err)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestP224Square(t *testing.T) {
|
||||
+ squareMatchesBigInt := func(a, out p224FieldElement) bool {
|
||||
+ var tmp p224LargeFieldElement
|
||||
+ p224Square(&out, &a, &tmp)
|
||||
+
|
||||
+ exp := p224AlternativeToBig(&a)
|
||||
+ exp.Mul(exp, exp)
|
||||
+ exp.Mod(exp, P224().Params().P)
|
||||
+ got := p224AlternativeToBig(&out)
|
||||
+ if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||
+ t.Logf("a = %x", a)
|
||||
+ t.Logf("p224Square(a, b) = %x = %v", out, got)
|
||||
+ t.Logf("a * a = %v", exp)
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
+ return true
|
||||
+ }
|
||||
+
|
||||
+ if err := quick.Check(squareMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
+ t.Error(err)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestP224Add(t *testing.T) {
|
||||
+ addMatchesBigInt := func(a, b, out p224FieldElement) bool {
|
||||
+ p224Add(&out, &a, &b)
|
||||
+
|
||||
+ exp := new(big.Int).Add(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
|
||||
+ exp.Mod(exp, P224().Params().P)
|
||||
+ got := p224AlternativeToBig(&out)
|
||||
+ if exp.Cmp(got) != 0 {
|
||||
+ t.Logf("a = %x", a)
|
||||
+ t.Logf("b = %x", b)
|
||||
+ t.Logf("p224Add(a, b) = %x = %v", out, got)
|
||||
+ t.Logf("a + b = %v", exp)
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
+ return true
|
||||
+ }
|
||||
+
|
||||
+ if err := quick.Check(addMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
+ t.Error(err)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestP224Reduce(t *testing.T) {
|
||||
+ reduceMatchesBigInt := func(a p224FieldElement) bool {
|
||||
+ out := a
|
||||
+ // TODO: generate higher values for functions like p224Reduce that are
|
||||
+ // expected to work with higher input bounds.
|
||||
+ p224Reduce(&out)
|
||||
+
|
||||
+ exp := p224AlternativeToBig(&a)
|
||||
+ got := p224AlternativeToBig(&out)
|
||||
+ if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||
+ t.Logf("a = %x = %v", a, exp)
|
||||
+ t.Logf("p224Reduce(a) = %x = %v", out, got)
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
+ return true
|
||||
+ }
|
||||
+
|
||||
+ if err := quick.Check(reduceMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
+ t.Error(err)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestP224Contract(t *testing.T) {
|
||||
+ contractMatchesBigInt := func(a, out p224FieldElement) bool {
|
||||
+ p224Contract(&out, &a)
|
||||
+
|
||||
+ exp := p224AlternativeToBig(&a)
|
||||
+ got := p224AlternativeToBig(&out)
|
||||
+ if exp.Cmp(got) != 0 {
|
||||
+ t.Logf("a = %x = %v", a, exp)
|
||||
+ t.Logf("p224Contract(a) = %x = %v", out, got)
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
+ // Check that out < P.
|
||||
+ for i := range p224P {
|
||||
+ k := 8 - i - 1
|
||||
+ if out[k] > p224P[k] {
|
||||
+ t.Logf("p224Contract(a) = %x", out)
|
||||
+ return false
|
||||
+ }
|
||||
+ if out[k] < p224P[k] {
|
||||
+ return true
|
||||
+ }
|
||||
+ }
|
||||
+ t.Logf("p224Contract(a) = %x", out)
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
+ if !contractMatchesBigInt(p224P, p224FieldElement{}) {
|
||||
+ t.Error("p224Contract(p) is broken")
|
||||
+ }
|
||||
+ pMinus1 := p224FieldElement{0, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||
+ if !contractMatchesBigInt(pMinus1, p224FieldElement{}) {
|
||||
+ t.Error("p224Contract(p - 1) is broken")
|
||||
+ }
|
||||
+ // Check that we can handle input above p, but lowest limb zero.
|
||||
+ a := p224FieldElement{0, 1, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||
+ if !contractMatchesBigInt(a, p224FieldElement{}) {
|
||||
+ t.Error("p224Contract(p + 2²⁸) is broken")
|
||||
+ }
|
||||
+ // Check that we can handle input above p, but lowest three limbs zero.
|
||||
+ b := p224FieldElement{0, 0, 0, 0xffff001, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||
+ if !contractMatchesBigInt(b, p224FieldElement{}) {
|
||||
+ t.Error("p224Contract(p + 2⁸⁴) is broken")
|
||||
+ }
|
||||
+
|
||||
+ if err := quick.Check(contractMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
+ t.Error(err)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestP224IsZero(t *testing.T) {
|
||||
+ if got := p224IsZero(&p224FieldElement{}); got != 1 {
|
||||
+ t.Errorf("p224IsZero(0) = %d, expected 1", got)
|
||||
+ }
|
||||
+ if got := p224IsZero((*p224FieldElement)(&p224P)); got != 1 {
|
||||
+ t.Errorf("p224IsZero(p) = %d, expected 1", got)
|
||||
+ }
|
||||
+ if got := p224IsZero(&p224FieldElement{1}); got != 0 {
|
||||
+ t.Errorf("p224IsZero(1) = %d, expected 0", got)
|
||||
+ }
|
||||
+
|
||||
+ isZeroMatchesBigInt := func(a p224FieldElement) bool {
|
||||
+ isZero := p224IsZero(&a)
|
||||
+
|
||||
+ big := p224AlternativeToBig(&a)
|
||||
+ if big.Sign() == 0 && isZero != 1 {
|
||||
+ return false
|
||||
+ }
|
||||
+ if big.Sign() != 0 && isZero != 0 {
|
||||
+ return false
|
||||
+ }
|
||||
+ return true
|
||||
+ }
|
||||
+
|
||||
+ if err := quick.Check(isZeroMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
+ t.Error(err)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestP224Invert(t *testing.T) {
|
||||
+ var out p224FieldElement
|
||||
+
|
||||
+ p224Invert(&out, &p224FieldElement{})
|
||||
+ if got := p224IsZero(&out); got != 1 {
|
||||
+ t.Errorf("p224Invert(0) = %x, expected 0", out)
|
||||
+ }
|
||||
+
|
||||
+ p224Invert(&out, (*p224FieldElement)(&p224P))
|
||||
+ if got := p224IsZero(&out); got != 1 {
|
||||
+ t.Errorf("p224Invert(p) = %x, expected 0", out)
|
||||
+ }
|
||||
+
|
||||
+ p224Invert(&out, &p224FieldElement{1})
|
||||
+ p224Contract(&out, &out)
|
||||
+ if out != (p224FieldElement{1}) {
|
||||
+ t.Errorf("p224Invert(1) = %x, expected 1", out)
|
||||
+ }
|
||||
+
|
||||
+ var tmp p224LargeFieldElement
|
||||
+ a := p224FieldElement{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
+ p224Invert(&out, &a)
|
||||
+ p224Mul(&out, &out, &a, &tmp)
|
||||
+ p224Contract(&out, &out)
|
||||
+ if out != (p224FieldElement{1}) {
|
||||
+ t.Errorf("p224Invert(a) * a = %x, expected 1", out)
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.17.1
|
||||
|
||||
Binary file not shown.
23
golang.spec
23
golang.spec
@ -61,8 +61,8 @@
|
||||
%endif
|
||||
|
||||
Name: golang
|
||||
Version: 1.13.15
|
||||
Release: 4
|
||||
Version: 1.15.7
|
||||
Release: 1
|
||||
Summary: The Go Programming Language
|
||||
License: BSD and Public Domain
|
||||
URL: https://golang.org/
|
||||
@ -149,21 +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
|
||||
Patch6024: 0024-crypto-elliptic-fix-P-224-field-reduction.patch
|
||||
|
||||
ExclusiveArch: %{golang_arches}
|
||||
|
||||
|
||||
@ -396,8 +381,8 @@ fi
|
||||
%files devel -f go-tests.list -f go-misc.list -f go-src.list
|
||||
|
||||
%changelog
|
||||
* Thu Feb 18 2021 jingrui<jingrui@huawei.com> - 1.13.15-3
|
||||
- fix CVE-2021-3114
|
||||
* 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user