]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: ensure abort actually crashes the process
authorAustin Clements <austin@google.com>
Thu, 18 Jan 2018 22:33:04 +0000 (17:33 -0500)
committerAustin Clements <austin@google.com>
Thu, 8 Mar 2018 22:55:55 +0000 (22:55 +0000)
On all non-x86 arches, runtime.abort simply reads from nil.
Unfortunately, if this happens on a user stack, the signal handler
will dutifully turn this into a panicmem, which lets user defers run
and which user code can even recover from.

To fix this, add an explicit check to the signal handler that turns
faults in abort into hard crashes directly in the signal handler. This
has the added benefit of giving a register dump at the abort point.

Change-Id: If26a7f13790745ee3867db7f53b72d8281176d70
Reviewed-on: https://go-review.googlesource.com/93661
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
16 files changed:
src/cmd/vet/all/whitelist/386.txt
src/cmd/vet/all/whitelist/amd64.txt
src/cmd/vet/all/whitelist/arm.txt
src/cmd/vet/all/whitelist/arm64.txt
src/cmd/vet/all/whitelist/mips64x.txt
src/cmd/vet/all/whitelist/mipsx.txt
src/cmd/vet/all/whitelist/nacl_amd64p32.txt
src/cmd/vet/all/whitelist/ppc64x.txt
src/cmd/vet/all/whitelist/s390x.txt
src/runtime/crash_test.go
src/runtime/os3_plan9.go
src/runtime/signal_sighandler.go
src/runtime/signal_windows.go
src/runtime/stubs.go
src/runtime/testdata/testprog/abort.go [new file with mode: 0644]
src/runtime/testdata/testprog/empty.s [new file with mode: 0644]

index 100ec974fb8ce0dd0dabeac4988847e0232ccd2c..76e82317edc6201dfc1b9d9a169f9709f95da365 100644 (file)
@@ -24,5 +24,3 @@ runtime/asm_386.s: [386] uint32tofloat64: function uint32tofloat64 missing Go de
 runtime/asm_386.s: [386] float64touint32: function float64touint32 missing Go declaration
 
 runtime/asm_386.s: [386] stackcheck: function stackcheck missing Go declaration
-
-runtime/asm_ARCHSUFF.s: [GOARCH] abort: function abort missing Go declaration
index 0b61bcaff3c59f574a2d01611bc8c5109cd5773e..2268b3935392055fd9163c557d9f09d53e175447 100644 (file)
@@ -21,4 +21,3 @@ runtime/asm_amd64.s: [amd64] addmoduledata: function addmoduledata missing Go de
 runtime/duff_amd64.s: [amd64] duffzero: function duffzero missing Go declaration
 runtime/duff_amd64.s: [amd64] duffcopy: function duffcopy missing Go declaration
 runtime/asm_amd64.s: [amd64] stackcheck: function stackcheck missing Go declaration
-runtime/asm_ARCHSUFF.s: [GOARCH] abort: function abort missing Go declaration
index 77f846037bdc9ea4663789d99e00d630db5b8ade..8f98782f9404a0377d8bff03afd13da958205873 100644 (file)
@@ -5,7 +5,6 @@ internal/bytealg/compare_arm.s: [arm] cannot check cross-package assembly functi
 
 // Intentionally missing declarations.
 runtime/asm_arm.s: [arm] emptyfunc: function emptyfunc missing Go declaration
-runtime/asm_arm.s: [arm] abort: function abort missing Go declaration
 runtime/asm_arm.s: [arm] armPublicationBarrier: function armPublicationBarrier missing Go declaration
 runtime/asm_arm.s: [arm] usplitR0: function usplitR0 missing Go declaration
 runtime/asm_arm.s: [arm] addmoduledata: function addmoduledata missing Go declaration
index e5ae6eab913731d8429c348bdc1843c858f45e0a..ee0292b41526081dce484eebf36fdc477efc624a 100644 (file)
@@ -4,7 +4,6 @@ internal/bytealg/compare_arm64.s: [arm64] cannot check cross-package assembly fu
 internal/bytealg/compare_arm64.s: [arm64] cannot check cross-package assembly function: cmpstring is in package runtime
 
 // Intentionally missing declarations.
-runtime/asm_arm64.s: [arm64] abort: function abort missing Go declaration
 runtime/asm_arm64.s: [arm64] addmoduledata: function addmoduledata missing Go declaration
 runtime/duff_arm64.s: [arm64] duffzero: function duffzero missing Go declaration
 runtime/duff_arm64.s: [arm64] duffcopy: function duffcopy missing Go declaration
index 5354d21c6428f628fa12c73c99e9eea34258ae4b..16877654458df87b90e49f57396e8291be7d7b6f 100644 (file)
@@ -1,6 +1,5 @@
 // mips64-specific vet whitelist. See readme.txt for details.
 
-runtime/asm_mips64x.s: [GOARCH] abort: function abort missing Go declaration
 runtime/duff_mips64x.s: [GOARCH] duffzero: function duffzero missing Go declaration
 runtime/tls_mips64x.s: [GOARCH] save_g: function save_g missing Go declaration
 runtime/tls_mips64x.s: [GOARCH] load_g: function load_g missing Go declaration
index 1488915d25d2f19fa48c18cd637dccc190ff9738..1a2cd3ff6242b8e9620349bf8cacbd3dd418313b 100644 (file)
@@ -3,7 +3,6 @@
 internal/bytealg/compare_mipsx.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
 internal/bytealg/compare_mipsx.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime
 
-runtime/asm_mipsx.s: [GOARCH] abort: function abort missing Go declaration
 runtime/tls_mipsx.s: [GOARCH] save_g: function save_g missing Go declaration
 runtime/tls_mipsx.s: [GOARCH] load_g: function load_g missing Go declaration
 runtime/sys_linux_mipsx.s: [GOARCH] clone: 12(R29) should be mp+8(FP)
index 021a01ace75a19e230d419b88ec3381fe9482c18..9280c68d2ca87f1113bbfa13feba329cd41a3627 100644 (file)
@@ -26,5 +26,3 @@ runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argv
 runtime/asm_amd64p32.s: [amd64p32] asmcgocall: RET without writing to 4-byte ret+8(FP)
 
 runtime/asm_amd64p32.s: [amd64p32] stackcheck: function stackcheck missing Go declaration
-
-runtime/asm_ARCHSUFF.s: [GOARCH] abort: function abort missing Go declaration
index bfa0fd9d6375893448eba1ca3dc05bfb5d003e24..65a904ed481fca1d6f01b7b233b37ed5ab5f66e6 100644 (file)
@@ -4,7 +4,6 @@ internal/bytealg/compare_ppc64x.s: [GOARCH] cannot check cross-package assembly
 internal/bytealg/compare_ppc64x.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime
 
 runtime/asm_ppc64x.s: [GOARCH] reginit: function reginit missing Go declaration
-runtime/asm_ppc64x.s: [GOARCH] abort: function abort missing Go declaration
 runtime/asm_ppc64x.s: [GOARCH] goexit: use of 24(R1) points beyond argument frame
 runtime/asm_ppc64x.s: [GOARCH] addmoduledata: function addmoduledata missing Go declaration
 runtime/duff_ppc64x.s: [GOARCH] duffzero: function duffzero missing Go declaration
index 57ff51f360a6e8530abbd941e07ea76e29eadeab..9fa49495752819d4e17be87f668d8e7f65425216 100644 (file)
@@ -1,4 +1,3 @@
-runtime/asm_s390x.s: [s390x] abort: function abort missing Go declaration
 internal/bytealg/compare_s390x.s: [s390x] cannot check cross-package assembly function: Compare is in package bytes
 internal/bytealg/compare_s390x.s: [s390x] cannot check cross-package assembly function: cmpstring is in package runtime
 runtime/asm_s390x.s: [s390x] addmoduledata: function addmoduledata missing Go declaration
index cd1aa51542ae77477add4418f578d1f00d9aa5d3..843b4150065d901a85f7107af387c06b2a38d2de 100644 (file)
@@ -637,3 +637,20 @@ func TestTimePprof(t *testing.T) {
                t.Error("profiler refers to ExternalCode")
        }
 }
+
+// Test that runtime.abort does so.
+func TestAbort(t *testing.T) {
+       output := runTestProg(t, "testprog", "Abort")
+       if want := "runtime.abort"; !strings.Contains(output, want) {
+               t.Errorf("output does not contain %q:\n%s", want, output)
+       }
+       if strings.Contains(output, "BAD") {
+               t.Errorf("output contains BAD:\n%s", output)
+       }
+       // Check that it's a signal-style traceback.
+       if runtime.GOOS != "windows" {
+               if want := "PC="; !strings.Contains(output, want) {
+                       t.Errorf("output does not contain %q:\n%s", want, output)
+               }
+       }
+}
index b05965b63d1aa0a8a3fc368e5fc448b917cbdb68..9158c44f2f0a8be26b8aabc3629599e7281c3a6d 100644 (file)
@@ -35,6 +35,10 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
                print("sighandler: note is longer than ERRMAX\n")
                goto Throw
        }
+       if c.pc() == funcPC(abort) || (GOARCH == "arm" && c.pc() == funcPC(abort)+4) {
+               // Never turn abort into a panic.
+               goto Throw
+       }
        // See if the note matches one of the patterns in sigtab.
        // Notes that do not match any pattern can be handled at a higher
        // level by the program but will otherwise be ignored.
index 13448929bcec3a07ae21fe2134a1137211bc9e8b..3004e36769181e8bd02abcb19b44e163f0979d69 100644 (file)
@@ -43,6 +43,11 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
                // stack. Abort in the signal handler instead.
                flags = (flags &^ _SigPanic) | _SigThrow
        }
+       if c.sigpc() == funcPC(abort) || (GOARCH == "arm" && c.sigpc() == funcPC(abort)+4) {
+               // On many architectures, the abort function just
+               // causes a memory fault. Don't turn that into a panic.
+               flags = _SigThrow
+       }
        if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
                // The signal is going to cause a panic.
                // Arrange the stack so that it looks like the point
index 518aac3c48ab8fc963b14385682e550dab4ddd09..4d55f0fe6c51af3caf2062a271dc27ce13f9e93e 100644 (file)
@@ -46,6 +46,11 @@ func isgoexception(info *exceptionrecord, r *context) bool {
                return false
        }
 
+       if r.ip() == funcPC(abort) || (GOARCH == "arm" && r.ip() == funcPC(abort)+4) {
+               // Never turn abort into a panic.
+               return false
+       }
+
        // Go will only handle some exceptions.
        switch info.exceptioncode {
        default:
index 6019005fbe211ff49e1ddc0412a1dc64028f8f5f..7818fd36839a624bc28e4e8ca375556d63b630fc 100644 (file)
@@ -313,3 +313,10 @@ func bool2int(x bool) int {
        // exactly what you would want it to.
        return int(uint8(*(*uint8)(unsafe.Pointer(&x))))
 }
+
+// abort crashes the runtime in situations where even throw might not
+// work. In general it should do something a debugger will recognize
+// (e.g., an INT3 on x86). A crash in abort is recognized by the
+// signal handler, which will attempt to tear down the runtime
+// immediately.
+func abort()
diff --git a/src/runtime/testdata/testprog/abort.go b/src/runtime/testdata/testprog/abort.go
new file mode 100644 (file)
index 0000000..9e79d4d
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2018 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 main
+
+import _ "unsafe" // for go:linkname
+
+func init() {
+       register("Abort", Abort)
+}
+
+//go:linkname runtimeAbort runtime.abort
+func runtimeAbort()
+
+func Abort() {
+       defer func() {
+               recover()
+               panic("BAD: recovered from abort")
+       }()
+       runtimeAbort()
+       println("BAD: after abort")
+}
diff --git a/src/runtime/testdata/testprog/empty.s b/src/runtime/testdata/testprog/empty.s
new file mode 100644 (file)
index 0000000..c5aa6f8
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2018 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.
+
+// This exists solely so we can linkname in symbols from runtime.