aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2018-12-14 19:35:04 -0500
committerFilippo Valsorda <filippo@golang.org>2018-12-14 19:35:04 -0500
commit8b246fe0f5950315035944868b0523e6d75d1171 (patch)
treef9f1cd3c07a5e51b24e3aae67efb454ba582adc4
parent2e2a04a605b6c3fc6e733810bdcd0200d8ed25a8 (diff)
parentf5ff72d62301c4e9d0a78167fab5914ca12919bd (diff)
downloadgo-8b246fe0f5950315035944868b0523e6d75d1171.tar.gz
go-8b246fe0f5950315035944868b0523e6d75d1171.zip
[dev.boringcrypto.go1.10] all: merge go1.10.7 into dev.boringcrypto.go1.10
Change-Id: Ifcd17a46d9f3bfaf64fe3d3e633b44f560dc6e10
-rw-r--r--doc/devel/release.html22
-rw-r--r--src/cmd/compile/internal/gc/const.go11
-rw-r--r--src/cmd/compile/internal/gc/walk.go6
-rw-r--r--src/cmd/go/internal/get/get.go23
-rw-r--r--src/cmd/go/internal/get/path.go192
-rw-r--r--src/cmd/go/internal/get/vcs.go18
-rw-r--r--src/cmd/go/internal/work/exec.go4
-rw-r--r--src/cmd/go/internal/work/security.go1
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go11
-rw-r--r--src/cmd/internal/obj/arm64/asm_test.go1
-rw-r--r--src/cmd/link/internal/ld/lib.go4
-rw-r--r--src/crypto/x509/cert_pool.go28
-rw-r--r--src/crypto/x509/verify.go86
-rw-r--r--src/crypto/x509/verify_test.go119
-rw-r--r--src/database/sql/sql.go2
-rw-r--r--src/internal/poll/sendfile_windows.go16
-rw-r--r--src/net/sendfile_test.go62
-rw-r--r--src/runtime/asm_ppc64x.s1
-rw-r--r--test/fixedbugs/issue27143.go17
19 files changed, 548 insertions, 76 deletions
diff --git a/doc/devel/release.html b/doc/devel/release.html
index e5d834e928..9f4500ac79 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -65,6 +65,28 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.4">Go
1.10.4 milestone</a> on our issue tracker for details.
</p>
+<p>
+go1.10.5 (released 2018/11/02) includes fixes to the go command, linker, runtime
+and the <code>database/sql</code> package.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.5">Go
+1.10.5 milestone</a> on our issue tracker for details.
+</p>
+
+<p>
+go1.10.6 (released 2018/12/12) includes three security fixes to "go get" and
+the <code>crypto/x509</code> package.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.6">Go
+1.10.6 milestone</a> on our issue tracker for details.
+</p>
+
+<p>
+go1.10.7 (released 2018/12/14) includes a fix to a bug introduced in Go 1.10.6
+that broke <code>go</code> <code>get</code> for import path patterns containing
+"<code>...</code>".
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.7+label%3ACherryPickApproved">
+Go 1.10.7 milestone</a> on our issue tracker for details.
+</p>
+
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
<p>
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index dcc16b6dec..32af1fb3fa 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -122,6 +122,17 @@ func (n *Node) Int64() int64 {
return n.Val().U.(*Mpint).Int64()
}
+// CanInt64 reports whether it is safe to call Int64() on n.
+func (n *Node) CanInt64() bool {
+ if !Isconst(n, CTINT) {
+ return false
+ }
+
+ // if the value inside n cannot be represented as an int64, the
+ // return value of Int64 is undefined
+ return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
+}
+
// Bool returns n as a bool.
// n must be a boolean constant.
func (n *Node) Bool() bool {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index ca3025bbaa..79134067c6 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -3561,6 +3561,12 @@ func walkinrange(n *Node, init *Nodes) *Node {
return n
}
+ // Ensure that Int64() does not overflow on a and c (it'll happen
+ // for any const above 2**63; see issue #27143).
+ if !a.CanInt64() || !c.CanInt64() {
+ return n
+ }
+
if opl == OLT {
// We have a < b && ...
// We need a ≤ b && ... to safely use unsigned comparison tricks.
diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go
index 5bfeac387c..0d9fd61fc1 100644
--- a/src/cmd/go/internal/get/get.go
+++ b/src/cmd/go/internal/get/get.go
@@ -207,7 +207,7 @@ var downloadCache = map[string]bool{}
var downloadRootCache = map[string]bool{}
// download runs the download half of the get command
-// for the package named by the argument.
+// for the package or pattern named by the argument.
func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
if mode&load.ResolveImport != 0 {
// Caller is responsible for expanding vendor paths.
@@ -376,6 +376,23 @@ func downloadPackage(p *load.Package) error {
security = web.Insecure
}
+ // p can be either a real package, or a pseudo-package whose “import path” is
+ // actually a wildcard pattern.
+ // Trim the path at the element containing the first wildcard,
+ // and hope that it applies to the wildcarded parts too.
+ // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
+ importPrefix := p.ImportPath
+ if i := strings.Index(importPrefix, "..."); i >= 0 {
+ slash := strings.LastIndexByte(importPrefix[:i], '/')
+ if slash < 0 {
+ return fmt.Errorf("cannot expand ... in %q", p.ImportPath)
+ }
+ importPrefix = importPrefix[:slash]
+ }
+ if err := CheckImportPath(importPrefix); err != nil {
+ return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
+ }
+
if p.Internal.Build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
@@ -393,7 +410,7 @@ func downloadPackage(p *load.Package) error {
}
repo = remote
if !*getF {
- if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
+ if rr, err := repoRootForImportPath(importPrefix, security); err == nil {
repo := rr.repo
if rr.vcs.resolveRepo != nil {
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
@@ -410,7 +427,7 @@ func downloadPackage(p *load.Package) error {
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.
- rr, err := repoRootForImportPath(p.ImportPath, security)
+ rr, err := repoRootForImportPath(importPrefix, security)
if err != nil {
return err
}
diff --git a/src/cmd/go/internal/get/path.go b/src/cmd/go/internal/get/path.go
new file mode 100644
index 0000000000..d443bd28a9
--- /dev/null
+++ b/src/cmd/go/internal/get/path.go
@@ -0,0 +1,192 @@
+// 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 get
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// The following functions are copied verbatim from cmd/go/internal/module/module.go,
+// with a change to additionally reject Windows short-names,
+// and one to accept arbitrary letters (golang.org/issue/29101).
+//
+// TODO(bcmills): After the call site for this function is backported,
+// consolidate this back down to a single copy.
+//
+// NOTE: DO NOT MERGE THESE UNTIL WE DECIDE ABOUT ARBITRARY LETTERS IN MODULE MODE.
+
+// CheckImportPath checks that an import path is valid.
+func CheckImportPath(path string) error {
+ if err := checkPath(path, false); err != nil {
+ return fmt.Errorf("malformed import path %q: %v", path, err)
+ }
+ return nil
+}
+
+// checkPath checks that a general path is valid.
+// It returns an error describing why but not mentioning path.
+// Because these checks apply to both module paths and import paths,
+// the caller is expected to add the "malformed ___ path %q: " prefix.
+// fileName indicates whether the final element of the path is a file name
+// (as opposed to a directory name).
+func checkPath(path string, fileName bool) error {
+ if !utf8.ValidString(path) {
+ return fmt.Errorf("invalid UTF-8")
+ }
+ if path == "" {
+ return fmt.Errorf("empty string")
+ }
+ if strings.Contains(path, "..") {
+ return fmt.Errorf("double dot")
+ }
+ if strings.Contains(path, "//") {
+ return fmt.Errorf("double slash")
+ }
+ if path[len(path)-1] == '/' {
+ return fmt.Errorf("trailing slash")
+ }
+ elemStart := 0
+ for i, r := range path {
+ if r == '/' {
+ if err := checkElem(path[elemStart:i], fileName); err != nil {
+ return err
+ }
+ elemStart = i + 1
+ }
+ }
+ if err := checkElem(path[elemStart:], fileName); err != nil {
+ return err
+ }
+ return nil
+}
+
+// checkElem checks whether an individual path element is valid.
+// fileName indicates whether the element is a file name (not a directory name).
+func checkElem(elem string, fileName bool) error {
+ if elem == "" {
+ return fmt.Errorf("empty path element")
+ }
+ if strings.Count(elem, ".") == len(elem) {
+ return fmt.Errorf("invalid path element %q", elem)
+ }
+ if elem[0] == '.' && !fileName {
+ return fmt.Errorf("leading dot in path element")
+ }
+ if elem[len(elem)-1] == '.' {
+ return fmt.Errorf("trailing dot in path element")
+ }
+
+ charOK := pathOK
+ if fileName {
+ charOK = fileNameOK
+ }
+ for _, r := range elem {
+ if !charOK(r) {
+ return fmt.Errorf("invalid char %q", r)
+ }
+ }
+
+ // Windows disallows a bunch of path elements, sadly.
+ // See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
+ short := elem
+ if i := strings.Index(short, "."); i >= 0 {
+ short = short[:i]
+ }
+ for _, bad := range badWindowsNames {
+ if strings.EqualFold(bad, short) {
+ return fmt.Errorf("disallowed path element %q", elem)
+ }
+ }
+
+ // Reject path components that look like Windows short-names.
+ // Those usually end in a tilde followed by one or more ASCII digits.
+ if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
+ suffix := short[tilde+1:]
+ suffixIsDigits := true
+ for _, r := range suffix {
+ if r < '0' || r > '9' {
+ suffixIsDigits = false
+ break
+ }
+ }
+ if suffixIsDigits {
+ return fmt.Errorf("trailing tilde and digits in path element")
+ }
+ }
+
+ return nil
+}
+
+// pathOK reports whether r can appear in an import path element.
+//
+// NOTE: This function DIVERGES from module mode pathOK by accepting Unicode letters.
+func pathOK(r rune) bool {
+ if r < utf8.RuneSelf {
+ return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
+ '0' <= r && r <= '9' ||
+ 'A' <= r && r <= 'Z' ||
+ 'a' <= r && r <= 'z'
+ }
+ return unicode.IsLetter(r)
+}
+
+// fileNameOK reports whether r can appear in a file name.
+// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
+// If we expand the set of allowed characters here, we have to
+// work harder at detecting potential case-folding and normalization collisions.
+// See note about "safe encoding" below.
+func fileNameOK(r rune) bool {
+ if r < utf8.RuneSelf {
+ // Entire set of ASCII punctuation, from which we remove characters:
+ // ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
+ // We disallow some shell special characters: " ' * < > ? ` |
+ // (Note that some of those are disallowed by the Windows file system as well.)
+ // We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
+ // We allow spaces (U+0020) in file names.
+ const allowed = "!#$%&()+,-.=@[]^_{}~ "
+ if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
+ return true
+ }
+ for i := 0; i < len(allowed); i++ {
+ if rune(allowed[i]) == r {
+ return true
+ }
+ }
+ return false
+ }
+ // It may be OK to add more ASCII punctuation here, but only carefully.
+ // For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
+ return unicode.IsLetter(r)
+}
+
+// badWindowsNames are the reserved file path elements on Windows.
+// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
+var badWindowsNames = []string{
+ "CON",
+ "PRN",
+ "AUX",
+ "NUL",
+ "COM1",
+ "COM2",
+ "COM3",
+ "COM4",
+ "COM5",
+ "COM6",
+ "COM7",
+ "COM8",
+ "COM9",
+ "LPT1",
+ "LPT2",
+ "LPT3",
+ "LPT4",
+ "LPT5",
+ "LPT6",
+ "LPT7",
+ "LPT8",
+ "LPT9",
+}
diff --git a/src/cmd/go/internal/get/vcs.go b/src/cmd/go/internal/get/vcs.go
index 0b2a04e04f..985f99d68f 100644
--- a/src/cmd/go/internal/get/vcs.go
+++ b/src/cmd/go/internal/get/vcs.go
@@ -647,14 +647,7 @@ var httpPrefixRE = regexp.MustCompile(`^https?:`)
func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) {
rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
if err == errUnknownSite {
- // If there are wildcards, look up the thing before the wildcard,
- // hoping it applies to the wildcarded parts too.
- // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
- lookup := strings.TrimSuffix(importPath, "/...")
- if i := strings.Index(lookup, "/.../"); i >= 0 {
- lookup = lookup[:i]
- }
- rr, err = repoRootForImportDynamic(lookup, security)
+ rr, err = repoRootForImportDynamic(importPath, security)
if err != nil {
err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
}
@@ -667,6 +660,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR
}
}
+ // Should have been taken care of above, but make sure.
if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
// Do not allow wildcards in the repo root.
rr = nil
@@ -970,10 +964,14 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
// expand rewrites s to replace {k} with match[k] for each key k in match.
func expand(match map[string]string, s string) string {
+ // We want to replace each match exactly once, and the result of expansion
+ // must not depend on the iteration order through the map.
+ // A strings.Replacer has exactly the properties we're looking for.
+ oldNew := make([]string, 0, 2*len(match))
for k, v := range match {
- s = strings.Replace(s, "{"+k+"}", v, -1)
+ oldNew = append(oldNew, "{"+k+"}", v)
}
- return s
+ return strings.NewReplacer(oldNew...).Replace(s)
}
// vcsPaths defines the meaning of import paths referring to
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index a50c996041..e97faf824b 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -220,7 +220,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
if len(p.SFiles) > 0 {
fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
}
- fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc
+ // GO386, GOARM, GOMIPS, etc.
+ baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le")
+ fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch)))
// TODO(rsc): Convince compiler team not to add more magic environment variables,
// or perhaps restrict the environment variables passed to subprocesses.
diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
index 1b82af9c97..7f0f7f96b0 100644
--- a/src/cmd/go/internal/work/security.go
+++ b/src/cmd/go/internal/work/security.go
@@ -167,6 +167,7 @@ var validLinkerFlags = []*regexp.Regexp{
re(`-Wl,-e[=,][a-zA-Z0-9]*`),
re(`-Wl,--enable-new-dtags`),
re(`-Wl,--end-group`),
+ re(`-Wl,--(no-)?export-dynamic`),
re(`-Wl,-framework,[^,@\-][^,]+`),
re(`-Wl,-headerpad_max_install_names`),
re(`-Wl,--no-undefined`),
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index ca81238c93..b1ee552489 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -696,9 +696,16 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
o = c.oplook(p)
/* very large branches */
- if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like
+ if (o.type_ == 7 || o.type_ == 39 || o.type_ == 40) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like, 40: TBZ and like
otxt := p.Pcond.Pc - pc
- if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 {
+ var toofar bool
+ switch o.type_ {
+ case 7, 39: // branch instruction encodes 19 bits
+ toofar = otxt <= -(1<<20)+10 || otxt >= (1<<20)-10
+ case 40: // branch instruction encodes 14 bits
+ toofar = otxt <= -(1<<15)+10 || otxt >= (1<<15)-10
+ }
+ if toofar {
q := c.newprog()
q.Link = p.Link
p.Link = q
diff --git a/src/cmd/internal/obj/arm64/asm_test.go b/src/cmd/internal/obj/arm64/asm_test.go
index 369c48f510..3e0c9c13a6 100644
--- a/src/cmd/internal/obj/arm64/asm_test.go
+++ b/src/cmd/internal/obj/arm64/asm_test.go
@@ -52,6 +52,7 @@ func TestLarge(t *testing.T) {
// gen generates a very large program, with a very far conditional branch.
func gen(buf *bytes.Buffer) {
fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
+ fmt.Fprintln(buf, "TBZ $5, R0, label")
fmt.Fprintln(buf, "CBZ R0, label")
fmt.Fprintln(buf, "BEQ label")
for i := 0; i < 1<<19; i++ {
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index abaeb15d2e..918fd82117 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -461,14 +461,14 @@ func (ctxt *Link) loadlib() {
// recording the value of GOARM.
if ctxt.Arch.Family == sys.ARM {
s := ctxt.Syms.Lookup("runtime.goarm", 0)
- s.Type = sym.SRODATA
+ s.Type = sym.SDATA
s.Size = 0
s.AddUint8(uint8(objabi.GOARM))
}
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
s := ctxt.Syms.Lookup("runtime.framepointer_enabled", 0)
- s.Type = sym.SRODATA
+ s.Type = sym.SDATA
s.Size = 0
s.AddUint8(1)
}
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index 71ffbdf0e0..86e8cbe869 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -38,32 +38,16 @@ func SystemCertPool() (*CertPool, error) {
return loadSystemRoots()
}
-// findVerifiedParents attempts to find certificates in s which have signed the
-// given certificate. If any candidates were rejected then errCert will be set
-// to one of them, arbitrarily, and err will contain the reason that it was
-// rejected.
-func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
+// findPotentialParents returns the indexes of certificates in s which might
+// have signed cert. The caller must not modify the returned slice.
+func (s *CertPool) findPotentialParents(cert *Certificate) []int {
if s == nil {
- return
+ return nil
}
- var candidates []int
-
if len(cert.AuthorityKeyId) > 0 {
- candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
- }
- if len(candidates) == 0 {
- candidates = s.byName[string(cert.RawIssuer)]
+ return s.bySubjectKeyId[string(cert.AuthorityKeyId)]
}
-
- for _, c := range candidates {
- if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
- parents = append(parents, c)
- } else {
- errCert = s.certs[c]
- }
- }
-
- return
+ return s.byName[string(cert.RawIssuer)]
}
func (s *CertPool) contains(cert *Certificate) bool {
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 1e7912555d..565b61df10 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -777,7 +777,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
if opts.Roots.contains(c) {
candidateChains = append(candidateChains, []*Certificate{c})
} else {
- if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
+ if candidateChains, err = c.buildChains(nil, []*Certificate{c}, nil, &opts); err != nil {
return nil, err
}
}
@@ -814,58 +814,74 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
return n
}
-func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
- possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
-nextRoot:
- for _, rootNum := range possibleRoots {
- root := opts.Roots.certs[rootNum]
+// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
+// that an invocation of buildChains will (tranistively) make. Most chains are
+// less than 15 certificates long, so this leaves space for multiple chains and
+// for failed checks due to different intermediates having the same Subject.
+const maxChainSignatureChecks = 100
+func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ var (
+ hintErr error
+ hintCert *Certificate
+ )
+
+ considerCandidate := func(certType int, candidate *Certificate) {
for _, cert := range currentChain {
- if cert.Equal(root) {
- continue nextRoot
+ if cert.Equal(candidate) {
+ return
}
}
- err = root.isValid(rootCertificate, currentChain, opts)
- if err != nil {
- continue
+ if sigChecks == nil {
+ sigChecks = new(int)
+ }
+ *sigChecks++
+ if *sigChecks > maxChainSignatureChecks {
+ err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
+ return
}
- chains = append(chains, appendToFreshChain(currentChain, root))
- }
- possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
-nextIntermediate:
- for _, intermediateNum := range possibleIntermediates {
- intermediate := opts.Intermediates.certs[intermediateNum]
- for _, cert := range currentChain {
- if cert.Equal(intermediate) {
- continue nextIntermediate
+ if err := c.CheckSignatureFrom(candidate); err != nil {
+ if hintErr == nil {
+ hintErr = err
+ hintCert = candidate
}
+ return
}
- err = intermediate.isValid(intermediateCertificate, currentChain, opts)
+
+ err = candidate.isValid(certType, currentChain, opts)
if err != nil {
- continue
+ return
}
- var childChains [][]*Certificate
- childChains, ok := cache[intermediateNum]
- if !ok {
- childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
- cache[intermediateNum] = childChains
+
+ switch certType {
+ case rootCertificate:
+ chains = append(chains, appendToFreshChain(currentChain, candidate))
+ case intermediateCertificate:
+ if cache == nil {
+ cache = make(map[*Certificate][][]*Certificate)
+ }
+ childChains, ok := cache[candidate]
+ if !ok {
+ childChains, err = candidate.buildChains(cache, appendToFreshChain(currentChain, candidate), sigChecks, opts)
+ cache[candidate] = childChains
+ }
+ chains = append(chains, childChains...)
}
- chains = append(chains, childChains...)
+ }
+
+ for _, rootNum := range opts.Roots.findPotentialParents(c) {
+ considerCandidate(rootCertificate, opts.Roots.certs[rootNum])
+ }
+ for _, intermediateNum := range opts.Intermediates.findPotentialParents(c) {
+ considerCandidate(intermediateCertificate, opts.Intermediates.certs[intermediateNum])
}
if len(chains) > 0 {
err = nil
}
-
if len(chains) == 0 && err == nil {
- hintErr := rootErr
- hintCert := failedRoot
- if hintErr == nil {
- hintErr = intermediateErr
- hintCert = failedIntermediate
- }
err = UnknownAuthorityError{c, hintErr, hintCert}
}
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index bd3df47907..2fc760d812 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -5,10 +5,15 @@
package x509
import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
+ "math/big"
"runtime"
"strings"
"testing"
@@ -1707,3 +1712,117 @@ UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
-----END CERTIFICATE-----`
+
+func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
+ priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
+
+ template := &Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{CommonName: cn},
+ NotBefore: time.Now().Add(-1 * time.Hour),
+ NotAfter: time.Now().Add(24 * time.Hour),
+
+ KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature | KeyUsageCertSign,
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ IsCA: isCA,
+ }
+ if issuer == nil {
+ issuer = template
+ issuerKey = priv
+ }
+
+ derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.Public(), issuerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return cert, priv, nil
+}
+
+func TestPathologicalChain(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping generation of a long chain of certificates in short mode")
+ }
+
+ // Build a chain where all intermediates share the same subject, to hit the
+ // path building worst behavior.
+ roots, intermediates := NewCertPool(), NewCertPool()
+
+ parent, parentKey, err := generateCert("Root CA", true, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ roots.AddCert(parent)
+
+ for i := 1; i < 100; i++ {
+ parent, parentKey, err = generateCert("Intermediate CA", true, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ intermediates.AddCert(parent)
+ }
+
+ leaf, _, err := generateCert("Leaf", false, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ start := time.Now()
+ _, err = leaf.Verify(VerifyOptions{
+ Roots: roots,
+ Intermediates: intermediates,
+ })
+ t.Logf("verification took %v", time.Since(start))
+
+ if err == nil || !strings.Contains(err.Error(), "signature check attempts limit") {
+ t.Errorf("expected verification to fail with a signature checks limit error; got %v", err)
+ }
+}
+
+func TestLongChain(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping generation of a long chain of certificates in short mode")
+ }
+
+ roots, intermediates := NewCertPool(), NewCertPool()
+
+ parent, parentKey, err := generateCert("Root CA", true, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ roots.AddCert(parent)
+
+ for i := 1; i < 15; i++ {
+ name := fmt.Sprintf("Intermediate CA #%d", i)
+ parent, parentKey, err = generateCert(name, true, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ intermediates.AddCert(parent)
+ }
+
+ leaf, _, err := generateCert("Leaf", false, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ start := time.Now()
+ if _, err := leaf.Verify(VerifyOptions{
+ Roots: roots,
+ Intermediates: intermediates,
+ }); err != nil {
+ t.Error(err)
+ }
+ t.Logf("verification took %v", time.Since(start))
+}
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index 8f5588ed26..719be91043 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -1070,7 +1070,7 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
select {
default:
case ret, ok := <-req:
- if ok {
+ if ok && ret.conn != nil {
db.putConn(ret.conn, ret.err, false)
}
}
diff --git a/src/internal/poll/sendfile_windows.go b/src/internal/poll/sendfile_windows.go
index 4a15b75236..17a3681064 100644
--- a/src/internal/poll/sendfile_windows.go
+++ b/src/internal/poll/sendfile_windows.go
@@ -25,8 +25,24 @@ func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
o := &fd.wop
o.qty = uint32(n)
o.handle = src
+
+ // TODO(brainman): skip calling syscall.Seek if OS allows it
+ curpos, err := syscall.Seek(o.handle, 0, 1)
+ if err != nil {
+ return 0, err
+ }
+
+ o.o.Offset = uint32(curpos)
+ o.o.OffsetHigh = uint32(curpos >> 32)
+
done, err := wsrv.ExecIO(o, func(o *operation) error {
return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
})
+ if err == nil {
+ // Some versions of Windows (Windows 10 1803) do not set
+ // file position after TransmitFile completes.
+ // So just use Seek to set file position.
+ _, err = syscall.Seek(o.handle, curpos+int64(done), 0)
+ }
return int64(done), err
}
diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go
index 2255e7c478..76c7f23992 100644
--- a/src/net/sendfile_test.go
+++ b/src/net/sendfile_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
@@ -88,3 +89,64 @@ func TestSendfile(t *testing.T) {
t.Error(err)
}
}
+
+func TestSendfileSeeked(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ const seekTo = 65 << 10
+ const sendSize = 10 << 10
+
+ errc := make(chan error, 1)
+ go func(ln Listener) {
+ // Wait for a connection.
+ conn, err := ln.Accept()
+ if err != nil {
+ errc <- err
+ close(errc)
+ return
+ }
+
+ go func() {
+ defer close(errc)
+ defer conn.Close()
+
+ f, err := os.Open(twain)
+ if err != nil {
+ errc <- err
+ return
+ }
+ defer f.Close()
+ if _, err := f.Seek(seekTo, os.SEEK_SET); err != nil {
+ errc <- err
+ return
+ }
+
+ _, err = io.CopyN(conn, f, sendSize)
+ if err != nil {
+ errc <- err
+ return
+ }
+ }()
+ }(ln)
+
+ c, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(c)
+
+ if buf.Len() != sendSize {
+ t.Errorf("Got %d bytes; want %d", buf.Len(), sendSize)
+ }
+
+ for err := range errc {
+ t.Error(err)
+ }
+}
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index e02ca16907..bb0609bf63 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -139,6 +139,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $16-8
MOVD 0(g), R4
MOVD gobuf_sp(R5), R1
MOVD gobuf_lr(R5), R31
+ MOVD 24(R1), R2 // restore R2
MOVD R31, LR
MOVD gobuf_ret(R5), R3
MOVD gobuf_ctxt(R5), R11
diff --git a/test/fixedbugs/issue27143.go b/test/fixedbugs/issue27143.go
new file mode 100644
index 0000000000..009ec9f6c2
--- /dev/null
+++ b/test/fixedbugs/issue27143.go
@@ -0,0 +1,17 @@
+// compile
+
+// 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.
+
+// Issue 27143: cmd/compile: erroneous application of walkinrange
+// optimization for const over 2**63
+
+package p
+
+var c uint64
+
+var b1 bool = 0x7fffffffffffffff < c && c < 0x8000000000000000
+var b2 bool = c < 0x8000000000000000 && 0x7fffffffffffffff < c
+var b3 bool = 0x8000000000000000 < c && c < 0x8000000000000001
+var b4 bool = c < 0x8000000000000001 && 0x8000000000000000 < c