diff --git a/.gitignore b/.gitignore index c1f6b9c..41468f9 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ /go1.7.1.src.tar.gz /go1.7.3.src.tar.gz /go1.7.4.src.tar.gz +/go1.7.6.src.tar.gz /go1.8rc3.src.tar.gz /go1.8.src.tar.gz /go1.8.1.src.tar.gz @@ -45,6 +46,11 @@ /go1.9.src.tar.gz /go1.9.1.src.tar.gz /go1.9.2.src.tar.gz +/go1.9.3.src.tar.gz +/go1.9.4.src.tar.gz +/go1.9.5.src.tar.gz +/go1.9.6.src.tar.gz +/go1.9.7.src.tar.gz /go1.10beta1.src.tar.gz /go1.10beta2.src.tar.gz /go1.10rc1.src.tar.gz @@ -62,6 +68,12 @@ /go1.11.1.src.tar.gz /go1.11.2.src.tar.gz /go1.11.4.src.tar.gz +/go1.11.5.src.tar.gz +/go1.11.6.src.tar.gz +/go1.11.7.src.tar.gz +/go1.11.10.src.tar.gz +/go1.11.11.src.tar.gz +/go1.11.12.src.tar.gz /go1.12beta2.src.tar.gz /go1.12rc1.src.tar.gz /go1.12.src.tar.gz @@ -79,6 +91,11 @@ /go1.13.4.src.tar.gz /go1.13.5.src.tar.gz /go1.13.6.src.tar.gz +/go1.13.7.src.tar.gz +/go1.13.9.src.tar.gz +/go1.13.10.src.tar.gz +/go1.13.11.src.tar.gz +/go1.13.14.src.tar.gz /go1.14beta1.src.tar.gz /go1.14rc1.src.tar.gz /go1.14.src.tar.gz diff --git a/117ddcb83d7f42d6aa72241240af99ded81118e9.patch b/117ddcb83d7f42d6aa72241240af99ded81118e9.patch new file mode 100644 index 0000000..bc8eb0b --- /dev/null +++ b/117ddcb83d7f42d6aa72241240af99ded81118e9.patch @@ -0,0 +1,135 @@ +commit 117ddcb83d7f42d6aa72241240af99ded81118e9 +Author: Brad Fitzpatrick +Date: Tue Jun 30 09:22:41 2015 -0700 + + net/textproto: don't treat spaces as hyphens in header keys + + This was originally done in https://codereview.appspot.com/5690059 + (Feb 2012) to deal with bad response headers coming back from webcams, + but it presents a potential security problem with HTTP request + smuggling for request headers containing "Content Length" instead of + "Content-Length". + + Part of overall HTTP hardening for request smuggling. See RFC 7230. + + Thanks to Régis Leroy for the report. + + Change-Id: I92b17fb637c9171c5774ea1437979ae2c17ca88a + Reviewed-on: https://go-review.googlesource.com/11772 + Reviewed-by: Russ Cox + Run-TryBot: Brad Fitzpatrick + TryBot-Result: Gobot Gobot + +diff --git a/src/net/http/header.go b/src/net/http/header.go +index 153b943..d847b13 100644 +--- a/src/net/http/header.go ++++ b/src/net/http/header.go +@@ -168,6 +168,8 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error { + // letter and any letter following a hyphen to upper case; + // the rest are converted to lowercase. For example, the + // canonical key for "accept-encoding" is "Accept-Encoding". ++// If s contains a space or invalid header field bytes, it is ++// returned without modifications. + func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) } + + // hasToken reports whether token appears with v, ASCII +diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go +index e4b8f6b..91303fe 100644 +--- a/src/net/textproto/reader.go ++++ b/src/net/textproto/reader.go +@@ -547,11 +547,16 @@ func (r *Reader) upcomingHeaderNewlines() (n int) { + // the rest are converted to lowercase. For example, the + // canonical key for "accept-encoding" is "Accept-Encoding". + // MIME header keys are assumed to be ASCII only. ++// If s contains a space or invalid header field bytes, it is ++// returned without modifications. + func CanonicalMIMEHeaderKey(s string) string { + // Quick check for canonical encoding. + upper := true + for i := 0; i < len(s); i++ { + c := s[i] ++ if !validHeaderFieldByte(c) { ++ return s ++ } + if upper && 'a' <= c && c <= 'z' { + return canonicalMIMEHeaderKey([]byte(s)) + } +@@ -565,19 +570,44 @@ func CanonicalMIMEHeaderKey(s string) string { + + const toLower = 'a' - 'A' + ++// validHeaderFieldByte reports whether b is a valid byte in a header ++// field key. This is actually stricter than RFC 7230, which says: ++// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / ++// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA ++// token = 1*tchar ++// TODO: revisit in Go 1.6+ and possibly expand this. But note that many ++// servers have historically dropped '_' to prevent ambiguities when mapping ++// to CGI environment variables. ++func validHeaderFieldByte(b byte) bool { ++ return ('A' <= b && b <= 'Z') || ++ ('a' <= b && b <= 'z') || ++ ('0' <= b && b <= '9') || ++ b == '-' ++} ++ + // canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is + // allowed to mutate the provided byte slice before returning the + // string. ++// ++// For invalid inputs (if a contains spaces or non-token bytes), a ++// is unchanged and a string copy is returned. + func canonicalMIMEHeaderKey(a []byte) string { ++ // See if a looks like a header key. If not, return it unchanged. ++ for _, c := range a { ++ if validHeaderFieldByte(c) { ++ continue ++ } ++ // Don't canonicalize. ++ return string(a) ++ } ++ + upper := true + for i, c := range a { + // Canonicalize: first letter upper case + // and upper case after each dash. + // (Host, User-Agent, If-Modified-Since). + // MIME headers are ASCII only, so no Unicode issues. +- if c == ' ' { +- c = '-' +- } else if upper && 'a' <= c && c <= 'z' { ++ if upper && 'a' <= c && c <= 'z' { + c -= toLower + } else if !upper && 'A' <= c && c <= 'Z' { + c += toLower +diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go +index 6bbd993..8fce7dd 100644 +--- a/src/net/textproto/reader_test.go ++++ b/src/net/textproto/reader_test.go +@@ -24,11 +24,14 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{ + {"uSER-aGENT", "User-Agent"}, + {"user-agent", "User-Agent"}, + {"USER-AGENT", "User-Agent"}, +- {"üser-agenT", "üser-Agent"}, // non-ASCII unchanged ++ ++ // Non-ASCII or anything with spaces or non-token chars is unchanged: ++ {"üser-agenT", "üser-agenT"}, ++ {"a B", "a B"}, + + // This caused a panic due to mishandling of a space: +- {"C Ontent-Transfer-Encoding", "C-Ontent-Transfer-Encoding"}, +- {"foo bar", "Foo-Bar"}, ++ {"C Ontent-Transfer-Encoding", "C Ontent-Transfer-Encoding"}, ++ {"foo bar", "foo bar"}, + } + + func TestCanonicalMIMEHeaderKey(t *testing.T) { +@@ -194,7 +197,7 @@ func TestReadMIMEHeaderNonCompliant(t *testing.T) { + "Foo": {"bar"}, + "Content-Language": {"en"}, + "Sid": {"0"}, +- "Audio-Mode": {"None"}, ++ "Audio Mode": {"None"}, + "Privilege": {"127"}, + } + if !reflect.DeepEqual(m, want) || err != nil { diff --git a/143822585e32449860e624cace9d2e521deee62e.patch b/143822585e32449860e624cace9d2e521deee62e.patch new file mode 100644 index 0000000..b11edc6 --- /dev/null +++ b/143822585e32449860e624cace9d2e521deee62e.patch @@ -0,0 +1,112 @@ +commit 143822585e32449860e624cace9d2e521deee62e +Author: Brad Fitzpatrick +Date: Tue Jul 7 13:19:44 2015 -0600 + + net/http: revert overly-strict part of earlier smuggling defense + + The recent https://golang.org/cl/11810 is reportedly a bit too + aggressive. + + Apparently some HTTP requests in the wild do contain both a + Transfer-Encoding along with a bogus Content-Length. Instead of + returning a 400 Bad Request error, we should just ignore the + Content-Length like we did before. + + Change-Id: I0001be90d09f8293a34f04691f608342875ff5c4 + Reviewed-on: https://go-review.googlesource.com/11962 + Reviewed-by: Andrew Gerrand + Run-TryBot: Brad Fitzpatrick + TryBot-Result: Gobot Gobot + +diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go +index 1a3cf91..60e2be4 100644 +--- a/src/net/http/readrequest_test.go ++++ b/src/net/http/readrequest_test.go +@@ -178,6 +178,36 @@ var reqTests = []reqTest{ + noError, + }, + ++ // Tests chunked body and a bogus Content-Length which should be deleted. ++ { ++ "POST / HTTP/1.1\r\n" + ++ "Host: foo.com\r\n" + ++ "Transfer-Encoding: chunked\r\n" + ++ "Content-Length: 9999\r\n\r\n" + // to be removed. ++ "3\r\nfoo\r\n" + ++ "3\r\nbar\r\n" + ++ "0\r\n" + ++ "\r\n", ++ &Request{ ++ Method: "POST", ++ URL: &url.URL{ ++ Path: "/", ++ }, ++ TransferEncoding: []string{"chunked"}, ++ Proto: "HTTP/1.1", ++ ProtoMajor: 1, ++ ProtoMinor: 1, ++ Header: Header{}, ++ ContentLength: -1, ++ Host: "foo.com", ++ RequestURI: "/", ++ }, ++ ++ "foobar", ++ noTrailer, ++ noError, ++ }, ++ + // CONNECT request with domain name: + { + "CONNECT www.google.com:443 HTTP/1.1\r\n\r\n", +@@ -400,11 +430,6 @@ Content-Length: 3 + Content-Length: 4 + + abc`)}, +- {"smuggle_chunked_and_len", reqBytes(`POST / HTTP/1.1 +-Transfer-Encoding: chunked +-Content-Length: 3 +- +-abc`)}, + {"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1 + Host: foo + Content-Length: 5`)}, +diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go +index 3c868bd..fbbbf24 100644 +--- a/src/net/http/transfer.go ++++ b/src/net/http/transfer.go +@@ -430,7 +430,6 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ( + if !present { + return nil, nil + } +- isRequest := !isResponse + delete(header, "Transfer-Encoding") + + encodings := strings.Split(raw[0], ",") +@@ -458,12 +457,20 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ( + // RFC 7230 3.3.2 says "A sender MUST NOT send a + // Content-Length header field in any message that + // contains a Transfer-Encoding header field." +- if len(header["Content-Length"]) > 0 { +- if isRequest { +- return nil, errors.New("http: invalid Content-Length with Transfer-Encoding") +- } +- delete(header, "Content-Length") +- } ++ // ++ // but also: ++ // "If a message is received with both a ++ // Transfer-Encoding and a Content-Length header ++ // field, the Transfer-Encoding overrides the ++ // Content-Length. Such a message might indicate an ++ // attempt to perform request smuggling (Section 9.5) ++ // or response splitting (Section 9.4) and ought to be ++ // handled as an error. A sender MUST remove the ++ // received Content-Length field prior to forwarding ++ // such a message downstream." ++ // ++ // Reportedly, these appear in the wild. ++ delete(header, "Content-Length") + return te, nil + } + diff --git a/300d9a21583e7cf0149a778a0611e76ff7c6680f.patch b/300d9a21583e7cf0149a778a0611e76ff7c6680f.patch new file mode 100644 index 0000000..1027032 --- /dev/null +++ b/300d9a21583e7cf0149a778a0611e76ff7c6680f.patch @@ -0,0 +1,225 @@ +commit 300d9a21583e7cf0149a778a0611e76ff7c6680f +Author: Brad Fitzpatrick +Date: Tue Jun 30 14:21:15 2015 -0700 + + net/http: harden Server against request smuggling + + See RFC 7230. + + Thanks to Régis Leroy for the report. + + Change-Id: Ic1779bc2180900430d4d7a4938cac04ed73c304c + Reviewed-on: https://go-review.googlesource.com/11810 + Reviewed-by: Russ Cox + Run-TryBot: Brad Fitzpatrick + +diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go +index e930d99..1a3cf91 100644 +--- a/src/net/http/readrequest_test.go ++++ b/src/net/http/readrequest_test.go +@@ -9,6 +9,7 @@ import ( + "bytes" + "fmt" + "io" ++ "io/ioutil" + "net/url" + "reflect" + "strings" +@@ -323,6 +324,32 @@ var reqTests = []reqTest{ + noTrailer, + noError, + }, ++ ++ // HEAD with Content-Length 0. Make sure this is permitted, ++ // since I think we used to send it. ++ { ++ "HEAD / HTTP/1.1\r\nHost: issue8261.com\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", ++ &Request{ ++ Method: "HEAD", ++ URL: &url.URL{ ++ Path: "/", ++ }, ++ Header: Header{ ++ "Connection": []string{"close"}, ++ "Content-Length": []string{"0"}, ++ }, ++ Host: "issue8261.com", ++ Proto: "HTTP/1.1", ++ ProtoMajor: 1, ++ ProtoMinor: 1, ++ Close: true, ++ RequestURI: "/", ++ }, ++ ++ noBody, ++ noTrailer, ++ noError, ++ }, + } + + func TestReadRequest(t *testing.T) { +@@ -356,3 +383,39 @@ func TestReadRequest(t *testing.T) { + } + } + } ++ ++// reqBytes treats req as a request (with \n delimiters) and returns it with \r\n delimiters, ++// ending in \r\n\r\n ++func reqBytes(req string) []byte { ++ return []byte(strings.Replace(strings.TrimSpace(req), "\n", "\r\n", -1) + "\r\n\r\n") ++} ++ ++var badRequestTests = []struct { ++ name string ++ req []byte ++}{ ++ {"bad_connect_host", reqBytes("CONNECT []%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a HTTP/1.0")}, ++ {"smuggle_two_contentlen", reqBytes(`POST / HTTP/1.1 ++Content-Length: 3 ++Content-Length: 4 ++ ++abc`)}, ++ {"smuggle_chunked_and_len", reqBytes(`POST / HTTP/1.1 ++Transfer-Encoding: chunked ++Content-Length: 3 ++ ++abc`)}, ++ {"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1 ++Host: foo ++Content-Length: 5`)}, ++} ++ ++func TestReadRequest_Bad(t *testing.T) { ++ for _, tt := range badRequestTests { ++ got, err := ReadRequest(bufio.NewReader(bytes.NewReader(tt.req))) ++ if err == nil { ++ all, err := ioutil.ReadAll(got.Body) ++ t.Errorf("%s: got unexpected request = %#v\n Body = %q, %v", tt.name, got, all, err) ++ } ++ } ++} +diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go +index 5205003..3887604 100644 +--- a/src/net/http/transfer.go ++++ b/src/net/http/transfer.go +@@ -143,6 +143,9 @@ func (t *transferWriter) shouldSendContentLength() bool { + return true + } + if t.ContentLength == 0 && isIdentity(t.TransferEncoding) { ++ if t.Method == "GET" || t.Method == "HEAD" { ++ return false ++ } + return true + } + +@@ -310,6 +313,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { + } + case *Request: + t.Header = rr.Header ++ t.RequestMethod = rr.Method + t.ProtoMajor = rr.ProtoMajor + t.ProtoMinor = rr.ProtoMinor + // Transfer semantics for Requests are exactly like those for +@@ -325,7 +329,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { + } + + // Transfer encoding, content length +- t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header) ++ t.TransferEncoding, err = fixTransferEncoding(isResponse, t.RequestMethod, t.Header) + if err != nil { + return err + } +@@ -413,12 +417,12 @@ func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" } + func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" } + + // Sanitize transfer encoding +-func fixTransferEncoding(requestMethod string, header Header) ([]string, error) { ++func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ([]string, error) { + raw, present := header["Transfer-Encoding"] + if !present { + return nil, nil + } +- ++ isRequest := !isResponse + delete(header, "Transfer-Encoding") + + encodings := strings.Split(raw[0], ",") +@@ -443,10 +447,15 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error) + return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")} + } + if len(te) > 0 { +- // Chunked encoding trumps Content-Length. See RFC 2616 +- // Section 4.4. Currently len(te) > 0 implies chunked +- // encoding. +- delete(header, "Content-Length") ++ // RFC 7230 3.3.2 says "A sender MUST NOT send a ++ // Content-Length header field in any message that ++ // contains a Transfer-Encoding header field." ++ if len(header["Content-Length"]) > 0 { ++ if isRequest { ++ return nil, errors.New("http: invalid Content-Length with Transfer-Encoding") ++ } ++ delete(header, "Content-Length") ++ } + return te, nil + } + +@@ -457,9 +466,17 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error) + // function is not a method, because ultimately it should be shared by + // ReadResponse and ReadRequest. + func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) { +- ++ contentLens := header["Content-Length"] ++ isRequest := !isResponse + // Logic based on response type or status + if noBodyExpected(requestMethod) { ++ // For HTTP requests, as part of hardening against request ++ // smuggling (RFC 7230), don't allow a Content-Length header for ++ // methods which don't permit bodies. As an exception, allow ++ // exactly one Content-Length header if its value is "0". ++ if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") { ++ return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens) ++ } + return 0, nil + } + if status/100 == 1 { +@@ -470,13 +487,21 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, + return 0, nil + } + ++ if len(contentLens) > 1 { ++ // harden against HTTP request smuggling. See RFC 7230. ++ return 0, errors.New("http: message cannot contain multiple Content-Length headers") ++ } ++ + // Logic based on Transfer-Encoding + if chunked(te) { + return -1, nil + } + + // Logic based on Content-Length +- cl := strings.TrimSpace(header.get("Content-Length")) ++ var cl string ++ if len(contentLens) == 1 { ++ cl = strings.TrimSpace(contentLens[0]) ++ } + if cl != "" { + n, err := parseContentLength(cl) + if err != nil { +@@ -487,11 +512,14 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, + header.Del("Content-Length") + } + +- if !isResponse && requestMethod == "GET" { +- // RFC 2616 doesn't explicitly permit nor forbid an ++ if !isResponse { ++ // RFC 2616 neither explicitly permits nor forbids an + // entity-body on a GET request so we permit one if + // declared, but we default to 0 here (not -1 below) + // if there's no mention of a body. ++ // Likewise, all other request methods are assumed to have ++ // no body if neither Transfer-Encoding chunked nor a ++ // Content-Length are set. + return 0, nil + } + diff --git a/CVE-2017-15041.patch b/CVE-2017-15041.patch new file mode 100644 index 0000000..4c4747c --- /dev/null +++ b/CVE-2017-15041.patch @@ -0,0 +1,127 @@ +diff -up go/src/cmd/go/get.go.cve go/src/cmd/go/get.go +--- go/src/cmd/go/get.go.cve 2017-05-23 20:35:22.000000000 +0200 ++++ go/src/cmd/go/get.go 2017-10-10 10:25:24.485047705 +0200 +@@ -401,6 +401,11 @@ func downloadPackage(p *Package) error { + p.build.PkgRoot = filepath.Join(list[0], "pkg") + } + root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath)) ++ ++ if err := checkNestedVCS(vcs, root, p.build.SrcRoot); err != nil { ++ return err ++ } ++ + // If we've considered this repository already, don't do it again. + if downloadRootCache[root] { + return nil +diff -up go/src/cmd/go/go_test.go.cve go/src/cmd/go/go_test.go +--- go/src/cmd/go/go_test.go.cve 2017-05-23 20:35:22.000000000 +0200 ++++ go/src/cmd/go/go_test.go 2017-10-10 10:25:24.485047705 +0200 +@@ -1235,6 +1235,25 @@ func TestGetGitDefaultBranch(t *testing. + tg.grepStdout(`\* another-branch`, "not on correct default branch") + } + ++func TestAccidentalGitCheckout(t *testing.T) { ++ testenv.MustHaveExternalNetwork(t) ++ if _, err := exec.LookPath("git"); err != nil { ++ t.Skip("skipping because git binary not found") ++ } ++ ++ tg := testgo(t) ++ defer tg.cleanup() ++ tg.parallel() ++ tg.tempDir("src") ++ tg.setenv("GOPATH", tg.path(".")) ++ ++ tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git") ++ tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason") ++ ++ tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main") ++ tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason") ++} ++ + func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() +diff -up go/src/cmd/go/vcs.go.cve go/src/cmd/go/vcs.go +--- go/src/cmd/go/vcs.go.cve 2017-05-23 20:35:22.000000000 +0200 ++++ go/src/cmd/go/vcs.go 2017-10-10 10:30:52.151621206 +0200 +@@ -479,11 +479,29 @@ func vcsFromDir(dir, srcRoot string) (vc + return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) + } + ++ var vcsRet *vcsCmd ++ var rootRet string ++ + origDir := dir + for len(dir) > len(srcRoot) { + for _, vcs := range vcsList { + if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() { +- return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil ++ root := filepath.ToSlash(dir[len(srcRoot)+1:]) ++ // Record first VCS we find, but keep looking, ++ // to detect mistakes like one kind of VCS inside another. ++ if vcsRet == nil { ++ vcsRet = vcs ++ rootRet = root ++ continue ++ } ++ // Allow .git inside .git, which can arise due to submodules. ++ if vcsRet == vcs && vcs.cmd == "git" { ++ continue ++ } ++ // Otherwise, we have one VCS inside a different VCS. ++ return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s", ++ filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd) ++ + } + } + +@@ -496,9 +514,48 @@ func vcsFromDir(dir, srcRoot string) (vc + dir = ndir + } + ++ if vcsRet != nil { ++ return vcsRet, rootRet, nil ++ } ++ + return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir) + } + ++// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS ++// situation for dir, checking parents up until srcRoot. ++func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error { ++ if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { ++ return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) ++ } ++ ++ otherDir := dir ++ for len(otherDir) > len(srcRoot) { ++ for _, otherVCS := range vcsList { ++ if _, err := os.Stat(filepath.Join(dir, "."+otherVCS.cmd)); err == nil { ++ // Allow expected vcs in original dir. ++ if otherDir == dir && otherVCS == vcs { ++ continue ++ } ++ // Allow .git inside .git, which can arise due to submodules. ++ if otherVCS == vcs && vcs.cmd == "git" { ++ continue ++ } ++ // Otherwise, we have one VCS inside a different VCS. ++ return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd) ++ } ++ } ++ // Move to parent. ++ newDir := filepath.Dir(otherDir) ++ if len(newDir) >= len(otherDir) { ++ // Shouldn't happen, but just in case, stop. ++ break ++ } ++ otherDir = newDir ++ } ++ ++ return nil ++} ++ + // repoRoot represents a version control system, a repo, and a root of + // where to put it on disk. + type repoRoot struct { diff --git a/CVE-2017-15042.patch b/CVE-2017-15042.patch new file mode 100644 index 0000000..aca6049 --- /dev/null +++ b/CVE-2017-15042.patch @@ -0,0 +1,144 @@ +From 4be3fc33ef512532b916aa14258087e89eb47347 Mon Sep 17 00:00:00 2001 +From: Russ Cox +Date: Wed, 4 Oct 2017 13:24:49 -0400 +Subject: [PATCH] [release-branch.go1.8] net/smtp: fix PlainAuth to refuse to + send passwords to non-TLS servers + +PlainAuth originally refused to send passwords to non-TLS servers +and was documented as such. + +In 2013, issue #5184 was filed objecting to the TLS requirement, +despite the fact that it is spelled out clearly in RFC 4954. +The only possibly legitimate use case raised was using PLAIN auth +for connections to localhost, and the suggested fix was to let the +server decide: if it advertises that PLAIN auth is OK, believe it. +That approach was adopted in CL 8279043 and released in Go 1.1. + +Unfortunately, this is exactly wrong. The whole point of the TLS +requirement is to make sure not to send the password to the wrong +server or to a man-in-the-middle. Instead of implementing this rule, +CL 8279043 blindly trusts the server, so that if a man-in-the-middle +says "it's OK, you can send me your password," PlainAuth does. +And the documentation was not updated to reflect any of this. + +This CL restores the original TLS check, as required by RFC 4954 +and as promised in the documentation for PlainAuth. +It then carves out a documented exception for connections made +to localhost (defined as "localhost", "127.0.0.1", or "::1"). + +Cherry-pick of CL 68170. + +Change-Id: I1d3729bbd33aa2f11a03f4c000e6bb473164957b +Reviewed-on: https://go-review.googlesource.com/68023 +Run-TryBot: Russ Cox +Reviewed-by: Chris Broadfoot +--- + src/net/smtp/auth.go | 33 ++++++++++++++++++--------------- + src/net/smtp/smtp_test.go | 32 ++++++++++++++++++++++---------- + 2 files changed, 40 insertions(+), 25 deletions(-) + +diff --git a/src/net/smtp/auth.go b/src/net/smtp/auth.go +index 3f1339ebc56..fd1a472f930 100644 +--- a/src/net/smtp/auth.go ++++ b/src/net/smtp/auth.go +@@ -44,26 +44,29 @@ type plainAuth struct { + } + + // PlainAuth returns an Auth that implements the PLAIN authentication +-// mechanism as defined in RFC 4616. +-// The returned Auth uses the given username and password to authenticate +-// on TLS connections to host and act as identity. Usually identity will be +-// left blank to act as username. ++// mechanism as defined in RFC 4616. The returned Auth uses the given ++// username and password to authenticate to host and act as identity. ++// Usually identity should be the empty string, to act as username. ++// ++// PlainAuth will only send the credentials if the connection is using TLS ++// or is connected to localhost. Otherwise authentication will fail with an ++// error, without sending the credentials. + func PlainAuth(identity, username, password, host string) Auth { + return &plainAuth{identity, username, password, host} + } + ++func isLocalhost(name string) bool { ++ return name == "localhost" || name == "127.0.0.1" || name == "::1" ++} ++ + func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) { +- if !server.TLS { +- advertised := false +- for _, mechanism := range server.Auth { +- if mechanism == "PLAIN" { +- advertised = true +- break +- } +- } +- if !advertised { +- return "", nil, errors.New("unencrypted connection") +- } ++ // Must have TLS, or else localhost server. ++ // Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo. ++ // In particular, it doesn't matter if the server advertises PLAIN auth. ++ // That might just be the attacker saying ++ // "it's ok, you can trust me with your password." ++ if !server.TLS && !isLocalhost(server.Name) { ++ return "", nil, errors.New("unencrypted connection") + } + if server.Name != a.host { + return "", nil, errors.New("wrong host name") +diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go +index c48fae6d5ac..15eaca524be 100644 +--- a/src/net/smtp/smtp_test.go ++++ b/src/net/smtp/smtp_test.go +@@ -60,29 +60,41 @@ testLoop: + } + + func TestAuthPlain(t *testing.T) { +- auth := PlainAuth("foo", "bar", "baz", "servername") + + tests := []struct { +- server *ServerInfo +- err string ++ authName string ++ server *ServerInfo ++ err string + }{ + { +- server: &ServerInfo{Name: "servername", TLS: true}, ++ authName: "servername", ++ server: &ServerInfo{Name: "servername", TLS: true}, + }, + { +- // Okay; explicitly advertised by server. +- server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, ++ // OK to use PlainAuth on localhost without TLS ++ authName: "localhost", ++ server: &ServerInfo{Name: "localhost", TLS: false}, + }, + { +- server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, +- err: "unencrypted connection", ++ // NOT OK on non-localhost, even if server says PLAIN is OK. ++ // (We don't know that the server is the real server.) ++ authName: "servername", ++ server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, ++ err: "unencrypted connection", + }, + { +- server: &ServerInfo{Name: "attacker", TLS: true}, +- err: "wrong host name", ++ authName: "servername", ++ server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, ++ err: "unencrypted connection", ++ }, ++ { ++ authName: "servername", ++ server: &ServerInfo{Name: "attacker", TLS: true}, ++ err: "wrong host name", + }, + } + for i, tt := range tests { ++ auth := PlainAuth("foo", "bar", "baz", tt.authName) + _, _, err := auth.Start(tt.server) + got := "" + if err != nil { diff --git a/el6-atomics.patch b/el6-atomics.patch new file mode 100644 index 0000000..cc3895d --- /dev/null +++ b/el6-atomics.patch @@ -0,0 +1,52 @@ +diff -up go/misc/cgo/test/testx.go.rev ./go/misc/cgo/test/testx.go +--- go/misc/cgo/test/testx.go.rev 2020-08-26 19:36:41.493810467 +0200 ++++ go/misc/cgo/test/testx.go 2020-08-26 19:36:48.498808001 +0200 +@@ -83,18 +83,33 @@ extern void f7665(void); + + void issue7978cb(void); + ++#if defined(__APPLE__) && defined(__arm__) ++// on Darwin/ARM, libSystem doesn't provide implementation of the __sync_fetch_and_add ++// primitive, and although gcc supports it, it doesn't inline its definition. ++// Clang could inline its definition, so we require clang on Darwin/ARM. ++#if defined(__clang__) ++#define HAS_SYNC_FETCH_AND_ADD 1 ++#else ++#define HAS_SYNC_FETCH_AND_ADD 0 ++#endif ++#else ++#define HAS_SYNC_FETCH_AND_ADD 1 ++#endif ++ + // use ugly atomic variable sync since that doesn't require calling back into + // Go code or OS dependencies + static void issue7978c(uint32_t *sync) { +- while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 0) ++#if HAS_SYNC_FETCH_AND_ADD ++ while(__sync_fetch_and_add(sync, 0) != 0) + ; +- __atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST); +- while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 2) ++ __sync_fetch_and_add(sync, 1); ++ while(__sync_fetch_and_add(sync, 0) != 2) + ; + issue7978cb(); +- __atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST); +- while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 6) ++ __sync_fetch_and_add(sync, 1); ++ while(__sync_fetch_and_add(sync, 0) != 6) + ; ++#endif + } + + // issue 8331 part 2 - part 1 in test.go +@@ -502,6 +517,9 @@ func test7978(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("gccgo can not do stack traces of C code") + } ++ if C.HAS_SYNC_FETCH_AND_ADD == 0 { ++ t.Skip("clang required for __sync_fetch_and_add support on darwin/arm") ++ } + debug.SetTraceback("2") + issue7978sync = 0 + go issue7978go() diff --git a/go1.5beta1-disable-TestGdbPython.patch b/go1.5beta1-disable-TestGdbPython.patch new file mode 100644 index 0000000..89d7d68 --- /dev/null +++ b/go1.5beta1-disable-TestGdbPython.patch @@ -0,0 +1,12 @@ +diff -up go/src/runtime/runtime-gdb_test.go.gdb go/src/runtime/runtime-gdb_test.go +--- go/src/runtime/runtime-gdb_test.go.gdb 2016-04-28 10:31:13.005689813 +0200 ++++ go/src/runtime/runtime-gdb_test.go 2016-04-28 10:32:12.202935125 +0200 +@@ -72,7 +72,7 @@ func main() { + } + ` + +-func TestGdbPython(t *testing.T) { ++func testGdbPython(t *testing.T) { + checkGdbEnvironment(t) + checkGdbVersion(t) + checkGdbPython(t) diff --git a/golang-1.5.1-a3156aaa12.patch b/golang-1.5.1-a3156aaa12.patch new file mode 100644 index 0000000..afff18d --- /dev/null +++ b/golang-1.5.1-a3156aaa12.patch @@ -0,0 +1,309 @@ +commit a3156aaa121446c4136927f8c2139fefe05ba82c +Author: Brad Fitzpatrick +Date: Tue Sep 29 14:26:48 2015 -0700 + + net/http/httptest: change Server to use http.Server.ConnState for accounting + + With this CL, httptest.Server now uses connection-level accounting of + outstanding requests instead of ServeHTTP-level accounting. This is + more robust and results in a non-racy shutdown. + + This is much easier now that net/http.Server has the ConnState hook. + + Fixes #12789 + Fixes #12781 + + Change-Id: I098cf334a6494316acb66cd07df90766df41764b + Reviewed-on: https://go-review.googlesource.com/15151 + Reviewed-by: Andrew Gerrand + Run-TryBot: Brad Fitzpatrick + TryBot-Result: Gobot Gobot + +diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go +index 96eb0ef..e4f680f 100644 +--- a/src/net/http/httptest/server.go ++++ b/src/net/http/httptest/server.go +@@ -7,13 +7,17 @@ + package httptest + + import ( ++ "bytes" + "crypto/tls" + "flag" + "fmt" ++ "log" + "net" + "net/http" + "os" ++ "runtime" + "sync" ++ "time" + ) + + // A Server is an HTTP server listening on a system-chosen port on the +@@ -34,24 +38,10 @@ type Server struct { + // wg counts the number of outstanding HTTP requests on this server. + // Close blocks until all requests are finished. + wg sync.WaitGroup +-} +- +-// historyListener keeps track of all connections that it's ever +-// accepted. +-type historyListener struct { +- net.Listener +- sync.Mutex // protects history +- history []net.Conn +-} + +-func (hs *historyListener) Accept() (c net.Conn, err error) { +- c, err = hs.Listener.Accept() +- if err == nil { +- hs.Lock() +- hs.history = append(hs.history, c) +- hs.Unlock() +- } +- return ++ mu sync.Mutex // guards closed and conns ++ closed bool ++ conns map[net.Conn]http.ConnState // except terminal states + } + + func newLocalListener() net.Listener { +@@ -103,10 +93,9 @@ func (s *Server) Start() { + if s.URL != "" { + panic("Server already started") + } +- s.Listener = &historyListener{Listener: s.Listener} + s.URL = "http://" + s.Listener.Addr().String() +- s.wrapHandler() +- go s.Config.Serve(s.Listener) ++ s.wrap() ++ s.goServe() + if *serve != "" { + fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL) + select {} +@@ -134,23 +123,10 @@ func (s *Server) StartTLS() { + if len(s.TLS.Certificates) == 0 { + s.TLS.Certificates = []tls.Certificate{cert} + } +- tlsListener := tls.NewListener(s.Listener, s.TLS) +- +- s.Listener = &historyListener{Listener: tlsListener} ++ s.Listener = tls.NewListener(s.Listener, s.TLS) + s.URL = "https://" + s.Listener.Addr().String() +- s.wrapHandler() +- go s.Config.Serve(s.Listener) +-} +- +-func (s *Server) wrapHandler() { +- h := s.Config.Handler +- if h == nil { +- h = http.DefaultServeMux +- } +- s.Config.Handler = &waitGroupHandler{ +- s: s, +- h: h, +- } ++ s.wrap() ++ s.goServe() + } + + // NewTLSServer starts and returns a new Server using TLS. +@@ -161,43 +137,139 @@ func NewTLSServer(handler http.Handler) *Server { + return ts + } + ++type closeIdleTransport interface { ++ CloseIdleConnections() ++} ++ + // Close shuts down the server and blocks until all outstanding + // requests on this server have completed. + func (s *Server) Close() { +- s.Listener.Close() +- s.wg.Wait() +- s.CloseClientConnections() +- if t, ok := http.DefaultTransport.(*http.Transport); ok { ++ s.mu.Lock() ++ if !s.closed { ++ s.closed = true ++ s.Listener.Close() ++ s.Config.SetKeepAlivesEnabled(false) ++ for c, st := range s.conns { ++ if st == http.StateIdle { ++ s.closeConn(c) ++ } ++ } ++ // If this server doesn't shut down in 5 seconds, tell the user why. ++ t := time.AfterFunc(5*time.Second, s.logCloseHangDebugInfo) ++ defer t.Stop() ++ } ++ s.mu.Unlock() ++ ++ // Not part of httptest.Server's correctness, but assume most ++ // users of httptest.Server will be using the standard ++ // transport, so help them out and close any idle connections for them. ++ if t, ok := http.DefaultTransport.(closeIdleTransport); ok { + t.CloseIdleConnections() + } ++ ++ s.wg.Wait() + } + +-// CloseClientConnections closes any currently open HTTP connections +-// to the test Server. ++func (s *Server) logCloseHangDebugInfo() { ++ s.mu.Lock() ++ defer s.mu.Unlock() ++ var buf bytes.Buffer ++ buf.WriteString("httptest.Server blocked in Close after 5 seconds, waiting for connections:\n") ++ for c, st := range s.conns { ++ fmt.Fprintf(&buf, " %T %p %v in state %v\n", c, c, c.RemoteAddr(), st) ++ } ++ log.Print(buf.String()) ++} ++ ++// CloseClientConnections closes any open HTTP connections to the test Server. + func (s *Server) CloseClientConnections() { +- hl, ok := s.Listener.(*historyListener) +- if !ok { +- return ++ s.mu.Lock() ++ defer s.mu.Unlock() ++ for c := range s.conns { ++ s.closeConn(c) + } +- hl.Lock() +- for _, conn := range hl.history { +- conn.Close() ++} ++ ++func (s *Server) goServe() { ++ s.wg.Add(1) ++ go func() { ++ defer s.wg.Done() ++ s.Config.Serve(s.Listener) ++ }() ++} ++ ++// wrap installs the connection state-tracking hook to know which ++// connections are idle. ++func (s *Server) wrap() { ++ oldHook := s.Config.ConnState ++ s.Config.ConnState = func(c net.Conn, cs http.ConnState) { ++ s.mu.Lock() ++ defer s.mu.Unlock() ++ switch cs { ++ case http.StateNew: ++ s.wg.Add(1) ++ if _, exists := s.conns[c]; exists { ++ panic("invalid state transition") ++ } ++ if s.conns == nil { ++ s.conns = make(map[net.Conn]http.ConnState) ++ } ++ s.conns[c] = cs ++ if s.closed { ++ // Probably just a socket-late-binding dial from ++ // the default transport that lost the race (and ++ // thus this connection is now idle and will ++ // never be used). ++ s.closeConn(c) ++ } ++ case http.StateActive: ++ if oldState, ok := s.conns[c]; ok { ++ if oldState != http.StateNew && oldState != http.StateIdle { ++ panic("invalid state transition") ++ } ++ s.conns[c] = cs ++ } ++ case http.StateIdle: ++ if oldState, ok := s.conns[c]; ok { ++ if oldState != http.StateActive { ++ panic("invalid state transition") ++ } ++ s.conns[c] = cs ++ } ++ if s.closed { ++ s.closeConn(c) ++ } ++ case http.StateHijacked, http.StateClosed: ++ s.forgetConn(c) ++ } ++ if oldHook != nil { ++ oldHook(c, cs) ++ } + } +- hl.Unlock() + } + +-// waitGroupHandler wraps a handler, incrementing and decrementing a +-// sync.WaitGroup on each request, to enable Server.Close to block +-// until outstanding requests are finished. +-type waitGroupHandler struct { +- s *Server +- h http.Handler // non-nil ++// closeConn closes c. Except on plan9, which is special. See comment below. ++// s.mu must be held. ++func (s *Server) closeConn(c net.Conn) { ++ if runtime.GOOS == "plan9" { ++ // Go's Plan 9 net package isn't great at unblocking reads when ++ // their underlying TCP connections are closed. Don't trust ++ // that that the ConnState state machine will get to ++ // StateClosed. Instead, just go there directly. Plan 9 may leak ++ // resources if the syscall doesn't end up returning. Oh well. ++ s.forgetConn(c) ++ } ++ go c.Close() + } + +-func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { +- h.s.wg.Add(1) +- defer h.s.wg.Done() // a defer, in case ServeHTTP below panics +- h.h.ServeHTTP(w, r) ++// forgetConn removes c from the set of tracked conns and decrements it from the ++// waitgroup, unless it was previously removed. ++// s.mu must be held. ++func (s *Server) forgetConn(c net.Conn) { ++ if _, ok := s.conns[c]; ok { ++ delete(s.conns, c) ++ s.wg.Done() ++ } + } + + // localhostCert is a PEM-encoded TLS cert with SAN IPs +diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go +index 500a9f0..90901ce 100644 +--- a/src/net/http/httptest/server_test.go ++++ b/src/net/http/httptest/server_test.go +@@ -27,3 +27,30 @@ func TestServer(t *testing.T) { + t.Errorf("got %q, want hello", string(got)) + } + } ++ ++// Issue 12781 ++func TestGetAfterClose(t *testing.T) { ++ ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ++ w.Write([]byte("hello")) ++ })) ++ ++ res, err := http.Get(ts.URL) ++ if err != nil { ++ t.Fatal(err) ++ } ++ got, err := ioutil.ReadAll(res.Body) ++ if err != nil { ++ t.Fatal(err) ++ } ++ if string(got) != "hello" { ++ t.Fatalf("got %q, want hello", string(got)) ++ } ++ ++ ts.Close() ++ ++ res, err = http.Get(ts.URL) ++ if err == nil { ++ body, _ := ioutil.ReadAll(res.Body) ++ t.Fatalf("Unexected response after close: %v, %v, %s", res.Status, res.Header, body) ++ } ++} diff --git a/golang-prelink.conf b/golang-prelink.conf new file mode 100644 index 0000000..471e8e6 --- /dev/null +++ b/golang-prelink.conf @@ -0,0 +1,3 @@ +# there are ELF files in src which are testdata and shouldn't be modified +-b /usr/lib/golang/src +-b /usr/lib64/golang/src diff --git a/golang.spec b/golang.spec index e70d2d9..047d0c9 100644 --- a/golang.spec +++ b/golang.spec @@ -1,12 +1,4 @@ %bcond_with bootstrap -# temporalily ignore test failures -# due to https://github.com/golang/go/issues/39466 -%ifarch aarch64 -%bcond_without ignore_tests -%else -%bcond_with ignore_tests -%endif - # build ids are not currently generated: # https://code.google.com/p/go/issues/detail?id=5238 # @@ -33,9 +25,6 @@ %global golibdir %{_libdir}/golang -# This macro may not always be defined, ensure it is -%{!?gopath: %global gopath %{_datadir}/gocode} - # Golang build options. # Build golang using external/internal(close to cgo disabled) linking. @@ -60,11 +49,7 @@ %endif # Controls what ever we fail on failed tests -%if %{with ignore_tests} -%global fail_on_tests 0 -%else %global fail_on_tests 1 -%endif # Build golang shared objects for stdlib %ifarch %{ix86} x86_64 ppc64le %{arm} aarch64 @@ -82,6 +67,9 @@ # Fedora GOROOT %global goroot /usr/lib/%{name} +%global gopath %{_datadir}/gocode +%global go_arches %{ix86} x86_64 %{arm} aarch64 ppc64le +%global golibdir %{_libdir}/golang %ifarch x86_64 %global gohostarch amd64 @@ -131,9 +119,10 @@ BuildRequires: hostname BuildRequires: net-tools %endif # for tests -BuildRequires: pcre-devel, glibc-static, perl-interpreter, procps-ng +BuildRequires: pcre-devel, glibc-static, perl Provides: go = %{version}-%{release} +Provides: go-srpm-macros # Bundled/Vendored provides generated by # go list -f {{.ImportPath}} ./src/vendor/... | sed "s:_$PWD/src/vendor/::g;s:_:.:;s:.*:Provides\: bundled(golang(&)):" && go list -f {{.ImportPath}} ./src/cmd/vendor/... | sed "s:_$PWD/src/cmd/vendor/::g;s:_:.:;s:.*:Provides\: bundled(golang(&)):" @@ -237,6 +226,9 @@ Requires: go-srpm-macros Patch1: 0001-Don-t-use-the-bundled-tzdata-at-runtime-except-for-t.patch Patch2: 0002-syscall-expose-IfInfomsg.X__ifi_pad-on-s390x.patch Patch3: 0003-cmd-go-disable-Google-s-proxy-and-sumdb.patch +# Revert https://github.com/golang/go/commit/b4924870f4b8302aba051a506bb499fad99b464e +# as RHEL 6 is using gcc 4.4 +Patch4: el6-atomics.patch # Having documentation separate was broken Obsoletes: %{name}-docs < 1.1-4 @@ -249,9 +241,11 @@ Obsoletes: %{name}-vim < 1.4 Obsoletes: emacs-%{name} < 1.4 # These are the only RHEL/Fedora architectures that we compile this package for -ExclusiveArch: %{golang_arches} +ExclusiveArch: %{go_arches} Source100: golang-gdbinit +Source101: golang-prelink.conf +Source102: macros.golang %description %{summary}. @@ -327,11 +321,7 @@ Requires(preun): %{_sbindir}/update-alternatives # This is an odd issue, still looking for a better fix. Requires: glibc Requires: gcc -%if 0%{?rhel} && 0%{?rhel} < 8 -Requires: git, subversion, mercurial -%else -Recommends: git, subversion, mercurial -%endif +Requires: git, subversion, mercurial %description bin %{summary} @@ -514,6 +504,21 @@ ln -sf /etc/alternatives/gofmt $RPM_BUILD_ROOT%{_bindir}/gofmt mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/gdbinit.d cp -av %{SOURCE100} $RPM_BUILD_ROOT%{_sysconfdir}/gdbinit.d/golang.gdb +# prelink blacklist +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/prelink.conf.d +cp -av %{SOURCE101} $RPM_BUILD_ROOT%{_sysconfdir}/prelink.conf.d/golang.conf + +# rpm macros +mkdir -p %{buildroot} +%if 0%{?rhel} > 6 || 0%{?fedora} > 0 +mkdir -p $RPM_BUILD_ROOT%{_rpmconfigdir}/macros.d +cp -av %{SOURCE102} $RPM_BUILD_ROOT%{_rpmconfigdir}/macros.d/macros.golang +%else +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/rpm +cp -av %{SOURCE102} $RPM_BUILD_ROOT%{_sysconfdir}/rpm/macros.golang +%endif + + %check export GOROOT=$(pwd -P) export PATH="$GOROOT"/bin:"$PATH" @@ -528,12 +533,6 @@ export GO_LDFLAGS="-linkmode internal" %if !%{cgo_enabled} || !%{external_linker} export CGO_ENABLED=0 %endif -# workaround for https://github.com/golang/go/issues/39466 until it gests fixed -# Commented until the patch is ready, this work around suggested in the link avobe -# doesn't work properly -#ifarch aarch64 -#export CGO_CFLAGS="-mno-outline-atomics" -#endif # make sure to not timeout export GO_TEST_TIMEOUT_SCALE=2 @@ -563,6 +562,7 @@ fi # VERSION has to be present in the GOROOT, for `go install std` to work %doc %{goroot}/VERSION %dir %{goroot}/doc +%doc %{goroot}/doc/* # go files %dir %{goroot} @@ -585,7 +585,17 @@ fi # gdbinit (for gdb debugging) %{_sysconfdir}/gdbinit.d -%files src -f go-src.list +# prelink blacklist +%{_sysconfdir}/prelink.conf.d + +%if 0%{?rhel} > 6 || 0%{?fedora} > 0 +%{_rpmconfigdir}/macros.d/macros.golang +%else +%{_sysconfdir}/rpm/macros.golang +%endif + + +%files -f go-src.list src %files docs -f go-docs.list @@ -608,256 +618,85 @@ fi %endif %changelog -* Fri Nov 13 2020 Jakub Čajka - 1.15.5-1 +* Mon Nov 16 2020 Jakub Čajka - 1.15.5-1 - Rebase to go1.15.5 - Security fix for CVE-2020-28362, CVE-2020-28367 and CVE-2020-28366 -- Resolves: BZ#1897342, BZ#1897636, BZ#1897644, BZ#1897647 - -* Fri Nov 06 2020 Jakub Čajka - 1.15.4-1 -- Rebase to go1.15.4 -- Resolves: BZ#1895189 - -* Thu Oct 15 2020 Jakub Čajka - 1.15.3-1 -- Rebase to go1.15.3 -- Resolves: BZ#1888443 +- Resolves: BZ#1897637, BZ#1897645 and BZ#1897648 * Thu Sep 10 2020 Jakub Čajka - 1.15.2-1 - Rebase to go1.15.2 -- Resolves: BZ#1877565 - -* Thu Sep 03 2020 Jakub Čajka - 1.15.1-1 -- Rebase to go1.15.1 - Security fix for CVE-2020-24553 -- Resolves: BZ#1874858, BZ#1866892 +- Resolves: BZ#1874859 -* Wed Aug 12 2020 Jakub Čajka - 1.15-1 -- Rebase to go1.15 proper -- Resolves: BZ#1859241, BZ#1866892 +* Tue Aug 25 2020 Jakub Čajka - 1.15-1 +- Rebase to go1.15 +- Security fix for CVE-2020-16845 and CVE-2020-14040 +- Resolves BZ#1867100 and BZ#1853654 -* Mon Aug 10 2020 Jakub Čajka - 1.15-0.rc2.0 -- Rebase to go1.15rc1 -- Security fix for CVE-2020-16845 -- Resolves: BZ#1867101 -- Related: BZ#1859241 +* Mon Jul 20 2020 Jakub Čajka - 1.13.14-1 +- Rebase to go1.13.14 +- Fix for CVE-2020-15586 +- Resolves: BZ#1856956 -* Mon Jul 27 2020 Fedora Release Engineering - 1.15-0.rc1.0.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild +* Mon May 18 2020 Álex Sáez - 1.13.11-1 +- Rebase to go1.13.11 -* Mon Jul 27 2020 Jakub Čajka - 1.15-0.rc1.0 -- Rebase to go1.15rc1 -- Related: BZ#1859241 - -* Mon Jul 20 2020 Jakub Čajka - 1.15-0.beta1.0 -- Rebase to go1.15beta1 - -* Mon Jul 20 2020 Jakub Čajka - 1.14.6-1 -- Rebase to go1.14.6 -- Security fix for CVE-2020-14040 and CVE-2020-15586 -- Resolves: BZ#1842708, BZ#1856957, BZ#1853653 - -* Tue Jun 30 2020 Alejandro Sáez - 1.14.4-1 -- Rebase to go1.14.4 -- Add patch that fixes: https://golang.org/issue/39991 -- Related: BZ#1842708 - -* Mon May 18 2020 Álex Sáez - 1.14.3-1 -- Rebase to go1.14.3 -- Resolves: BZ#1836015 - -* Mon Apr 20 2020 Jakub Čajka - 1.14.2-1 -- Rebase to go1.14.2 -- Resolves: BZ#1815282 - -* Wed Feb 26 2020 Jakub Čajka - 1.14-1 -- Rebase to go1.14 proper -- Resolves: BZ#1792475 - -* Thu Feb 06 2020 Jakub Čajka - 1.14-0.rc1.0 -- Rebase to go1.14.rc1 -- Related: BZ#1792475 - -* Tue Jan 28 2020 Fedora Release Engineering - 1.14-0.beta1.0.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild - -* Mon Jan 20 2020 Jakub Čajka - 1.14-0.beta1.0 -- Rebase to go1.14beta1 -- Resolves: BZ#1792475 - -* Mon Jan 13 2020 Jakub Čajka - 1.13.6-1 +* Mon Feb 03 2020 Jakub Čajka - 1.13.6-1 - Rebase to go1.13.6 -* Thu Dec 05 2019 Jakub Čajka - 1.13.5-1 -- Rebase to go1.13.5 - -* Tue Nov 26 2019 Neal Gompa - 1.13.4-2 -- Small fixes to the spec and tighten up the file list - -* Fri Nov 01 2019 Jakub Čajka - 1.13.4-1 +* Wed Nov 13 2019 Jakub Čajka - 1.13.4-1 - Rebase to go1.13.4 -- Resolves BZ#1767673 -* Sat Oct 19 2019 Jakub Čajka - 1.13.3-1 +* Wed Oct 30 2019 Jakub Čajka - 1.13.3-1 - Rebase to go1.13.3 - Fix for CVE-2019-17596 -- Resolves: BZ#1755639, BZ#1763312 +- Resolves: BZ#1763311 -* Fri Sep 27 2019 Jakub Čajka - 1.13.1-1 +* Sat Oct 5 2019 Jakub Čajka - 1.13.1-1 - Rebase to go1.13.1 - Fix for CVE-2019-16276 -- Resolves: BZ#1755970 +- Resolves: BZ#1755971 -* Thu Sep 05 2019 Jakub Čajka - 1.13-2 -- Back to go1.13 tls1.3 behavior - -* Wed Sep 04 2019 Jakub Čajka - 1.13-1 +* Tue Sep 10 2019 Jakub Čajka - 1.13-1 - Rebase to go1.13 +- Fix for CVE-2019-9512, CVE-2019-9514, CVE-2019-14809 +- Resolves: BZ#1741815, BZ#1741826, BZ#1743130 -* Fri Aug 30 2019 Jakub Čajka - 1.13-0.rc2.1 -- Rebase to go1.13rc2 -- Do not enable tls1.3 by default -- Related: BZ#1737471 +* Thu Aug 08 2019 Jakub Čajka - 1.11.12-1 +- Rebase to 1.11.12 -* Wed Aug 28 2019 Jakub Čajka - 1.13-0.rc1.2 -- Actually fix CVE-2019-9514 and CVE-2019-9512 -- Related: BZ#1741816, BZ#1741827 - -* Mon Aug 26 2019 Jakub Čajka - 1.13-0.rc1.1 -- Rebase to 1.13rc1 -- Fix for CVE-2019-14809, CVE-2019-9514 and CVE-2019-9512 -- Resolves: BZ#1741816, BZ#1741827 and BZ#1743131 - -* Thu Aug 01 2019 Jakub Čajka - 1.13-0.beta1.2.2 -- Fix ICE affecting aarch64 -- Resolves: BZ#1735290 - -* Thu Jul 25 2019 Fedora Release Engineering - 1.13-0.beta1.2.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild - -* Wed Jul 24 2019 Jakub Čajka - 1.13-0.beta1.2 -- De-configure sumdb and go proxy - -* Wed Jul 24 2019 Jakub Čajka - 1.13-0.beta1.1 -- Rebase to 1.13beta1 -- Related: BZ#1732118 - -* Tue Jul 09 2019 Jakub Čajka - 1.12.7-1 -- Rebase to 1.12.7 -- Resolves: BZ#1728056 - -* Wed Jun 12 2019 Jakub Čajka - 1.12.6-1 -- Rebase to 1.12.6 -- Resolves: BZ#1719483 - -* Tue May 07 2019 Jakub Čajka - 1.12.5-1 -- Rebase to 1.12.5 -- Resolves: BZ#1707187 - -* Mon Apr 08 2019 Jakub Čajka - 1.12.2-1 -- Rebase to 1.12.2 -- Resolves: BZ#1688996 - -* Mon Apr 01 2019 Jakub Čajka - 1.12.1-2 -- Fix up change log, respective CVE has been fixed in go1.12rc1 - -* Fri Mar 15 2019 Jakub Čajka - 1.12.1-1 -- Rebase to 1.12.1 -- Fix requirement for %%preun (instead of %%postun) scriptlet thanks to Tim Landscheidt -- Use weak deps for SCM deps - -* Wed Feb 27 2019 Jakub Čajka - 1.12-1 -- Rebase to go1.12 proper -- Resolves: BZ#1680040 - -* Mon Feb 18 2019 Jakub Čajka - 1.12-0.rc1.1 -- Rebase to go1.12rc1 - -* Thu Jan 31 2019 Fedora Release Engineering - 1.12-0.beta2.2.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild - -* Sun Jan 27 2019 Jakub Čajka - 1.12-0.beta2.2 +* Mon Feb 04 2019 Jakub Čajka - 1.11.5-1 +- Rebase to go1.11.5 - Fix for CVE-2019-6486 -- Resolves: BZ#1668973 - -* Fri Jan 11 2019 Jakub Čajka - 1.12-0.beta2.1 -- Rebase to go1.12beta2 +- Resolves: BZ#1668975 * Wed Jan 02 2019 Jakub Čajka - 1.11.4-1 - Rebase to go1.11.4 - Fix for CVE-2018-16875, CVE-2018-16874 and CVE-2018-16873 -- Resolves: BZ#1659290, BZ#1659289, BZ#1659288 +- Resolves: BZ#1664332 -* Mon Nov 05 2018 Jakub Čajka - 1.11.2-1 +* Fri Nov 30 2018 Jakub Čajka - 1.11.2-3 +- add ppc64le proper + +* Mon Nov 26 2018 Jakub Čajka - 1.11.2-2 +- fix up macros file for aarch64 + +* Fri Nov 23 2018 Jakub Čajka - 1.11.2-1 - Rebase to go1.11.2 -* Thu Oct 04 2018 Jakub Čajka - 1.11.1-1 +* Sun Oct 07 2018 Jakub Čajka - 1.11.1-1 - Rebase to go1.11.1 -* Mon Aug 27 2018 Jakub Čajka - 1.11-1 -- Rebase to go1.11 release +* Mon Jun 11 2018 Jakub Čajka - 1.9.7-1 +- Rebase to 1.9.7 -* Thu Aug 23 2018 Jakub Čajka - 1.11-0.rc2.1 -- Rebase to go1.11rc2 -- Reduce size of bin package +* Thu May 10 2018 Jakub Čajka - 1.9.6-1 +- Rebase to 1.9.6 -* Tue Aug 14 2018 Jakub Čajka - 1.11-0.rc1.1 -- Rebase to go1.11rc1 - -* Mon Aug 06 2018 Jakub Čajka - 1.11-0.beta3.1 -- Rebase to go1.11beta3 - -* Fri Jul 27 2018 Jakub Čajka - 1.11-0.beta2.2 -- Turn on back DWARF compression by default -- Use less memory on 32bit targets during build -- Resolves: BZ#1607270 -- Related: BZ#1602096 - -* Fri Jul 20 2018 Jakub Čajka - 1.11-0.beta2.1 -- Rebase to 1.11beta2 - -* Wed Jul 18 2018 Jakub Čajka - 1.11-0.beta1.2 -- Turn off DWARF compression by default as it is not supported by rpm/debuginfo -- Related: BZ#1602096 - -* Fri Jul 13 2018 Fedora Release Engineering - 1.11-0.beta1.1.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild - -* Wed Jul 04 2018 Jakub Čajka - 1.11-0.beta1.1 -* Rebase to 1.11beta1 - -* Fri Jun 08 2018 Jakub Čajka - 1.10.3-1 -- Rebase to 1.10.3 - -* Wed May 02 2018 Jakub Čajka - 1.10.2-1 -- Rebase to 1.10.2 - -* Wed Apr 04 2018 Jakub Čajka - 1.10.1-1 -- Rebase to 1.10.1 -- Resolves: BZ#1562270 - -* Sat Mar 03 2018 Jakub Čajka - 1.10-2 -- Fix CVE-2018-7187 -- Resolves: BZ#1546386, BZ#1546388 - -* Wed Feb 21 2018 Jakub Čajka - 1.10-1 -- Rebase to 1.10 - -* Thu Feb 08 2018 Jakub Čajka - 1.10-0.rc2.1 -- Rebase to 1.10rc2 -- Fix CVE-2018-6574 -- Resolves: BZ#1543561, BZ#1543562 - -* Wed Feb 07 2018 Fedora Release Engineering - 1.10-0.rc1.1.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild - -* Fri Jan 26 2018 Jakub Čajka - 1.10-0.rc1.1 -- Rebase to 1.10rc1 - -* Fri Jan 12 2018 Jakub Čajka - 1.10-0.beta2.1 -- Rebase to 1.10beta2 - -* Mon Jan 08 2018 Jakub Čajka - 1.10-0.beta1.1 -- Rebase to 1.10beta1 -- Drop verbose patch as most of it is now implemented by bootstrap tool and is easily toggled by passing -v flag to make.bash +* Tue Mar 20 2018 Jakub Čajka - 1.9.4-1 +- Rebase to 1.9.4 +- Fix CVE-2018-6574 and CVE-2018-7187 +- Resolves: BZ#1543561, BZ#1543563, BZ#1546386, BZ#1546387 * Thu Oct 26 2017 Jakub Čajka - 1.9.2-1 - Rebase to 1.9.2 diff --git a/macros.golang b/macros.golang new file mode 100644 index 0000000..de6c610 --- /dev/null +++ b/macros.golang @@ -0,0 +1,8 @@ +# Where to set GOPATH for builds. Like: +# export GOPATH=$(pwd)/_build:%{gopath} +%gopath %{_datadir}/gocode + +# for use like: +# ExclusiveArch: %{go_arches} +%go_arches %{ix86} x86_64 %{arm} aarch64 ppc64le + diff --git a/ppc64x-overflow-1.patch b/ppc64x-overflow-1.patch new file mode 100644 index 0000000..35e3e3d --- /dev/null +++ b/ppc64x-overflow-1.patch @@ -0,0 +1,457 @@ +From d6beea7f9ea1aa2ae5abca7fccb252767820aa13 Mon Sep 17 00:00:00 2001 +From: Lynn Boger +Date: Tue, 26 Jul 2016 08:51:10 -0500 +Subject: [PATCH] cmd/link: split large elf text sections for ppc64x + +Some applications built with Go on ppc64x with +external linking can fail to link with relocation +truncation errors, due to the way that the golang +compiler generates a single go.o file containing +a single large text section to send to the GNU +linker. If the size of the single text section is +greater than 2^26, this can lead to link errors +due to 24 bit offset field in the bl (call) +instruction. + +This fix solves the problem by splitting into +multiple text sections when this limit is reached. +When this is done then the GNU linker can fix the +long calls and insert jump tables where needed. +--- + src/cmd/link/internal/ld/data.go | 52 +++++++++++++++++++++++++++++-- + src/cmd/link/internal/ld/elf.go | 60 ++++++++++++++++++++++++++++++++--- + src/cmd/link/internal/ld/lib.go | 20 ++++++++++++ + src/cmd/link/internal/ld/symtab.go | 64 ++++++++++++++++++++++++++++++++++++++ + src/cmd/link/internal/ppc64/asm.go | 12 ++++--- + src/runtime/symtab.go | 34 +++++++++++++++----- + src/runtime/type.go | 16 +++++++++- + 7 files changed, 237 insertions(+), 21 deletions(-) + +diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go +index 57a0dad..58ce18c 100644 +--- a/src/cmd/link/internal/ld/data.go ++++ b/src/cmd/link/internal/ld/data.go +@@ -527,7 +527,15 @@ func relocsym(s *LSym) { + o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr) + + case obj.R_ADDROFF: +- o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add ++ ++ // The method offset tables using this relocation expect the offset to be relative ++ // to the start of the first text section, even if there are multiple. ++ ++ if Linkmode == LinkExternal && r.Sym.Sect.Name == ".text" && r.Sym.Sect.Vaddr != Segtext.Vaddr { ++ o = Symaddr(r.Sym) - int64(Segtext.Vaddr) + r.Add ++ } else { ++ o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add ++ } + + // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. + case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL: +@@ -1926,6 +1934,7 @@ func textaddress() { + } + va := uint64(INITTEXT) + sect.Vaddr = va ++ n := 1 + for _, sym := range Ctxt.Textp { + sym.Sect = sect + if sym.Type&obj.SSUB != 0 { +@@ -1948,9 +1957,30 @@ func textaddress() { + } else { + va += uint64(sym.Size) + } ++ // On ppc64x a text section should not be larger than 2^26 bytes due to the size of ++ // call target offset field in the bl instruction. Splitting into text ++ // sections smaller than this limit allows the GNU linker to modify the long calls ++ // appropriately. The limit allows for the space for linker tables. ++ ++ // Only break at outermost syms. ++ ++ if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > uint64(0x1c00000) { ++ ++ // Set the length for the previous text section ++ sect.Length = va - sect.Vaddr ++ ++ // Create new section, set the starting Vaddr ++ sect = addsection(&Segtext, ".text", 05) ++ sect.Vaddr = va ++ ++ // Create a symbol for the start and end of the secondary text section ++ Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect ++ n++ ++ } + } + + sect.Length = va - sect.Vaddr ++ Linklookup(Ctxt, "runtime.etext", 0).Sect = sect + } + + // assign addresses +@@ -2057,11 +2087,27 @@ func address() { + Segdwarf.Filelen = va - Segdwarf.Vaddr + + text := Segtext.Sect ++ lasttext := text + var rodata *Section + if Segrodata.Sect != nil { + rodata = Segrodata.Sect + } else { +- rodata = text.Next ++ // Could be multiple .text sections ++ n := 1 ++ for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { ++ if sect.Name != ".text" { ++ break ++ } ++ lasttext = sect ++ symname := fmt.Sprintf("runtime.text.%d", n) ++ xdefine(symname, obj.STEXT, int64(sect.Vaddr)) ++ n++ ++ } ++ ++ rodata = lasttext.Next ++ if rodata != nil && rodata.Name != ".rodata" { ++ Diag("Unexpected section order in text segment") ++ } + } + var relrodata *Section + typelink := rodata.Next +@@ -2108,7 +2154,7 @@ func address() { + } + + xdefine("runtime.text", obj.STEXT, int64(text.Vaddr)) +- xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length)) ++ xdefine("runtime.etext", obj.STEXT, int64(lasttext.Vaddr+lasttext.Length)) + if HEADTYPE == obj.Hwindows { + xdefine(".text", obj.STEXT, int64(text.Vaddr)) + } +diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go +index 39d3609..ecb00c2 100644 +--- a/src/cmd/link/internal/ld/elf.go ++++ b/src/cmd/link/internal/ld/elf.go +@@ -1623,6 +1623,25 @@ func elfshname(name string) *ElfShdr { + return nil + } + ++// Create an ElfShdr for the section with name. ++// A new one is created even if one already exists with ++// the same name. ++func elfshnamedup(name string) *ElfShdr { ++ var off int ++ var sh *ElfShdr ++ ++ for i := 0; i < nelfstr; i++ { ++ if name == elfstr[i].s { ++ off = elfstr[i].off ++ sh = newElfShdr(int64(off)) ++ return sh ++ } ++ } ++ Diag("cannot find elf name %s", name) ++ errorexit() ++ return nil ++} ++ + func elfshalloc(sect *Section) *ElfShdr { + sh := elfshname(sect.Name) + sect.Elfsect = sh +@@ -1630,7 +1649,17 @@ func elfshalloc(sect *Section) *ElfShdr { + } + + func elfshbits(sect *Section) *ElfShdr { +- sh := elfshalloc(sect) ++ var sh *ElfShdr ++ ++ if sect.Name == ".text" { ++ if sect.Elfsect == nil { ++ sect.Elfsect = elfshnamedup(sect.Name) ++ } ++ sh = sect.Elfsect ++ } else { ++ sh = elfshalloc(sect) ++ } ++ + // If this section has already been set up as a note, we assume type_ and + // flags are already correct, but the other fields still need filling in. + if sh.type_ == SHT_NOTE { +@@ -1706,6 +1735,15 @@ func elfshreloc(sect *Section) *ElfShdr { + } + + sh := elfshname(elfRelType + sect.Name) ++ ++ // There could be multiple text sections but each needs ++ // its own .rela.text. ++ if sect.Name == ".text" { ++ if sh.info != 0 && sh.info != uint32(sect.Elfsect.shnum) { ++ sh = elfshnamedup(elfRelType + sect.Name) ++ } ++ } ++ + sh.type_ = uint32(typ) + sh.entsize = uint64(SysArch.RegSize) * 2 + if typ == SHT_RELA { +@@ -1776,9 +1814,12 @@ func Elfemitreloc() { + Cput(0) + } + +- elfrelocsect(Segtext.Sect, Ctxt.Textp) +- for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { +- elfrelocsect(sect, datap) ++ for sect := Segtext.Sect; sect != nil; sect = sect.Next { ++ if sect.Name == ".text" { ++ elfrelocsect(sect, Ctxt.Textp) ++ } else { ++ elfrelocsect(sect, datap) ++ } + } + for sect := Segrodata.Sect; sect != nil; sect = sect.Next { + elfrelocsect(sect, datap) +@@ -2109,7 +2150,16 @@ func Asmbelfsetup() { + elfshname("") + + for sect := Segtext.Sect; sect != nil; sect = sect.Next { +- elfshalloc(sect) ++ ++ // There could be multiple .text sections. Instead check the Elfsect ++ // field to determine if already has an ElfShdr and if not, create one. ++ if sect.Name == ".text" { ++ if sect.Elfsect == nil { ++ sect.Elfsect = elfshnamedup(sect.Name) ++ } ++ } else { ++ elfshalloc(sect) ++ } + } + for sect := Segrodata.Sect; sect != nil; sect = sect.Next { + elfshalloc(sect) +diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go +index 14f4fa9..709e7ca 100644 +--- a/src/cmd/link/internal/ld/lib.go ++++ b/src/cmd/link/internal/ld/lib.go +@@ -1956,6 +1956,26 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { + if s.Type == obj.STEXT { + put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil) + } ++ n := 0 ++ ++ // Generate base addresses for all text sections if there are multiple ++ for sect := Segtext.Sect; sect != nil; sect = sect.Next { ++ if n == 0 { ++ n++ ++ continue ++ } ++ if sect.Name != ".text" { ++ break ++ } ++ s = Linkrlookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0) ++ if s == nil { ++ break ++ } ++ if s.Type == obj.STEXT { ++ put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil) ++ } ++ n++ ++ } + s = Linklookup(Ctxt, "runtime.etext", 0) + if s.Type == obj.STEXT { + put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil) +diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go +index 06d7792..80eb33d 100644 +--- a/src/cmd/link/internal/ld/symtab.go ++++ b/src/cmd/link/internal/ld/symtab.go +@@ -315,6 +315,62 @@ func (libs byPkg) Swap(a, b int) { + libs[a], libs[b] = libs[b], libs[a] + } + ++// Create a table with information on the text sections. ++ ++func textsectionmap() uint32 { ++ ++ t := Linklookup(Ctxt, "runtime.textsectionmap", 0) ++ t.Type = obj.SRODATA ++ t.Attr |= AttrReachable ++ nsections := int64(0) ++ ++ for sect := Segtext.Sect; sect != nil; sect = sect.Next { ++ if sect.Name == ".text" { ++ nsections++ ++ } else { ++ break ++ } ++ } ++ Symgrow(Ctxt, t, nsections*3*8) ++ ++ off := int64(0) ++ n := 0 ++ ++ // The vaddr for each text section is the difference between the section's ++ // Vaddr and the Vaddr for the first text section as determined at compile ++ // time. ++ ++ // The symbol name for the start address of the first text section is ++ // runtime.text. Additional text sections are named runtime.text.n where n is the ++ // order of creation starting with 1. These symbols provide the section's ++ // start address after relocation by the linker. ++ ++ textbase := Segtext.Sect.Vaddr ++ for sect := Segtext.Sect; sect != nil; sect = sect.Next { ++ if sect.Name != ".text" { ++ break ++ } ++ off = setuintxx(Ctxt, t, off, sect.Vaddr-textbase, int64(SysArch.IntSize)) ++ off = setuintxx(Ctxt, t, off, sect.Length, int64(SysArch.IntSize)) ++ if n == 0 { ++ s := Linkrlookup(Ctxt, "runtime.text", 0) ++ if s == nil { ++ Diag("Unable to find symbol runtime.text\n") ++ } ++ off = setaddr(Ctxt, t, off, s) ++ ++ } else { ++ s := Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0) ++ if s == nil { ++ Diag("Unable to find symbol runtime.text.%d\n", n) ++ } ++ off = setaddr(Ctxt, t, off, s) ++ } ++ n++ ++ } ++ return uint32(n) ++} ++ + func symtab() { + dosymtype() + +@@ -489,6 +545,8 @@ func symtab() { + adduint(Ctxt, abihashgostr, uint64(hashsym.Size)) + } + ++ nsections := textsectionmap() ++ + // Information about the layout of the executable image for the + // runtime to use. Any changes here must be matched by changes to + // the definition of moduledata in runtime/symtab.go. +@@ -527,6 +585,12 @@ func symtab() { + Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0)) + Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.types", 0)) + Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypes", 0)) ++ ++ // text section information ++ Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.textsectionmap", 0)) ++ adduint(Ctxt, moduledata, uint64(nsections)) ++ adduint(Ctxt, moduledata, uint64(nsections)) ++ + // The typelinks slice + Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0)) + adduint(Ctxt, moduledata, uint64(ntypelinks)) +diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go +index bd2e23f..ab59fa8 100644 +--- a/src/cmd/link/internal/ppc64/asm.go ++++ b/src/cmd/link/internal/ppc64/asm.go +@@ -813,12 +813,14 @@ func asmb() { + ld.Asmbelfsetup() + } + +- sect := ld.Segtext.Sect +- ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) +- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length)) +- for sect = sect.Next; sect != nil; sect = sect.Next { ++ for sect := ld.Segtext.Sect; sect != nil; sect = sect.Next { + ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) +- ld.Datblk(int64(sect.Vaddr), int64(sect.Length)) ++ // Might have multiple text sections ++ if sect.Name == ".text" { ++ ld.Codeblk(int64(sect.Vaddr), int64(sect.Length)) ++ } else { ++ ld.Datblk(int64(sect.Vaddr), int64(sect.Length)) ++ } + } + + if ld.Segrodata.Filelen > 0 { +diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go +index 4f6fae2..23e80ce 100644 +--- a/src/runtime/symtab.go ++++ b/src/runtime/symtab.go +@@ -195,8 +195,9 @@ type moduledata struct { + end, gcdata, gcbss uintptr + types, etypes uintptr + +- typelinks []int32 // offsets from types +- itablinks []*itab ++ textsectmap []textsect ++ typelinks []int32 // offsets from types ++ itablinks []*itab + + modulename string + modulehashes []modulehash +@@ -226,6 +227,14 @@ type functab struct { + funcoff uintptr + } + ++// Mapping information for secondary text sections ++ ++type textsect struct { ++ vaddr uint64 // prelinked section vaddr ++ length uint64 // section length ++ baseaddr uintptr // relocated section address ++} ++ + const minfunc = 16 // minimum function size + const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table + +@@ -368,12 +377,23 @@ func findfunc(pc uintptr) *_func { + ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) + idx := ffb.idx + uint32(ffb.subbuckets[i]) + if pc < datap.ftab[idx].entry { +- throw("findfunc: bad findfunctab entry") +- } + +- // linear search to find func with pc >= entry. +- for datap.ftab[idx+1].entry <= pc { +- idx++ ++ // If there are multiple text sections then the buckets for the secondary ++ // text sections will be off because the addresses in those text sections ++ // were relocated to higher addresses. Search back to find it. ++ ++ for datap.ftab[idx].entry > pc && idx > 0 { ++ idx-- ++ } ++ if idx == 0 { ++ throw("findfunc: bad findfunctab entry idx") ++ } ++ } else { ++ ++ // linear search to find func with pc >= entry. ++ for datap.ftab[idx+1].entry <= pc { ++ idx++ ++ } + } + return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])) + } +diff --git a/src/runtime/type.go b/src/runtime/type.go +index 5ef11a4..f641adc 100644 +--- a/src/runtime/type.go ++++ b/src/runtime/type.go +@@ -257,7 +257,21 @@ func (t *_type) textOff(off textOff) unsafe.Pointer { + } + return res + } +- res := md.text + uintptr(off) ++ res := uintptr(0) ++ ++ // Find the text section range that contains the offset to determine the section's base ++ // address. In cases where there are multiple text sections, the base address might be ++ // relocated by the linker. ++ ++ for i := 0; i < len(md.textsectmap); i++ { ++ sectaddr := md.textsectmap[i].vaddr ++ sectlen := md.textsectmap[i].length ++ if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen { ++ res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr) ++ break ++ } ++ } ++ + if res > md.etext { + println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext)) + throw("runtime: text offset out of range") diff --git a/ppc64x-overflow-2.patch b/ppc64x-overflow-2.patch new file mode 100644 index 0000000..35dfc0e --- /dev/null +++ b/ppc64x-overflow-2.patch @@ -0,0 +1,150 @@ +From a5b97a846d70cd8db7f33c24f2b9159f935ce318 Mon Sep 17 00:00:00 2001 +From: Lynn Boger +Date: Tue, 13 Sep 2016 15:13:08 -0500 +Subject: [PATCH] cmd/compile: large text sections on ppc64le + +Additional fixes as submitted upstream. +--- + src/cmd/link/internal/ld/data.go | 24 ++++++++++++------------ + src/cmd/link/internal/ld/lib.go | 2 +- + src/cmd/link/internal/ld/symtab.go | 2 +- + src/runtime/type.go | 28 ++++++++++++++++++---------- + 4 files changed, 32 insertions(+), 24 deletions(-) + +diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go +index 58ce18c..d8e43ff 100644 +--- a/src/cmd/link/internal/ld/data.go ++++ b/src/cmd/link/internal/ld/data.go +@@ -531,7 +531,7 @@ func relocsym(s *LSym) { + // The method offset tables using this relocation expect the offset to be relative + // to the start of the first text section, even if there are multiple. + +- if Linkmode == LinkExternal && r.Sym.Sect.Name == ".text" && r.Sym.Sect.Vaddr != Segtext.Vaddr { ++ if r.Sym.Sect.Name == ".text" { + o = Symaddr(r.Sym) - int64(Segtext.Vaddr) + r.Add + } else { + o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add +@@ -1928,7 +1928,6 @@ func textaddress() { + + sect.Align = int32(Funcalign) + Linklookup(Ctxt, "runtime.text", 0).Sect = sect +- Linklookup(Ctxt, "runtime.etext", 0).Sect = sect + if HEADTYPE == obj.Hwindows { + Linklookup(Ctxt, ".text", 0).Sect = sect + } +@@ -1964,7 +1963,7 @@ func textaddress() { + + // Only break at outermost syms. + +- if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > uint64(0x1c00000) { ++ if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > 0x1c00000 { + + // Set the length for the previous text section + sect.Length = va - sect.Vaddr +@@ -1973,7 +1972,7 @@ func textaddress() { + sect = addsection(&Segtext, ".text", 05) + sect.Vaddr = va + +- // Create a symbol for the start and end of the secondary text section ++ // Create a symbol for the start of the secondary text section + Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect + n++ + } +@@ -2093,15 +2092,8 @@ func address() { + rodata = Segrodata.Sect + } else { + // Could be multiple .text sections +- n := 1 +- for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { +- if sect.Name != ".text" { +- break +- } ++ for sect := Segtext.Sect.Next; sect != nil && sect.Name == ".text"; sect = sect.Next { + lasttext = sect +- symname := fmt.Sprintf("runtime.text.%d", n) +- xdefine(symname, obj.STEXT, int64(sect.Vaddr)) +- n++ + } + + rodata = lasttext.Next +@@ -2155,6 +2147,14 @@ func address() { + + xdefine("runtime.text", obj.STEXT, int64(text.Vaddr)) + xdefine("runtime.etext", obj.STEXT, int64(lasttext.Vaddr+lasttext.Length)) ++ ++ n := 1 ++ for sect := Segtext.Sect.Next; sect != nil && sect.Name == ".text"; sect = sect.Next { ++ symname := fmt.Sprintf("runtime.text.%d", n) ++ xdefine(symname, obj.STEXT, int64(sect.Vaddr)) ++ n++ ++ } ++ + if HEADTYPE == obj.Hwindows { + xdefine(".text", obj.STEXT, int64(text.Vaddr)) + } +diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go +index 709e7ca..c37ef92 100644 +--- a/src/cmd/link/internal/ld/lib.go ++++ b/src/cmd/link/internal/ld/lib.go +@@ -1958,7 +1958,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { + } + n := 0 + +- // Generate base addresses for all text sections if there are multiple ++ // Generate base addresses for all text sections if there are multiple. + for sect := Segtext.Sect; sect != nil; sect = sect.Next { + if n == 0 { + n++ +diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go +index 80eb33d..ec26f88 100644 +--- a/src/cmd/link/internal/ld/symtab.go ++++ b/src/cmd/link/internal/ld/symtab.go +@@ -331,7 +331,7 @@ func textsectionmap() uint32 { + break + } + } +- Symgrow(Ctxt, t, nsections*3*8) ++ Symgrow(Ctxt, t, nsections*(2*int64(SysArch.IntSize)+int64(SysArch.PtrSize))) + + off := int64(0) + n := 0 +diff --git a/src/runtime/type.go b/src/runtime/type.go +index f641adc..d4df5a9 100644 +--- a/src/runtime/type.go ++++ b/src/runtime/type.go +@@ -259,17 +259,25 @@ func (t *_type) textOff(off textOff) unsafe.Pointer { + } + res := uintptr(0) + +- // Find the text section range that contains the offset to determine the section's base +- // address. In cases where there are multiple text sections, the base address might be +- // relocated by the linker. +- +- for i := 0; i < len(md.textsectmap); i++ { +- sectaddr := md.textsectmap[i].vaddr +- sectlen := md.textsectmap[i].length +- if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen { +- res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr) +- break ++ // The text, or instruction stream is generated as one large buffer. The off (offset) for a method is ++ // its offset within this buffer. If the total text size gets too large, there can be issues on platforms like ppc64 if ++ // the target of calls are too far for the call instruction. To resolve the large text issue, the text is split ++ // into multiple text sections to allow the linker to generate long calls when necessary. When this happens, the vaddr ++ // for each text section is set to its offset within the text. Each method's offset is compared against the section ++ // vaddrs and sizes to determine the containing section. Then the section relative offset is added to the section's ++ // relocated baseaddr to compute the method addess. ++ ++ if len(md.textsectmap) > 1 { ++ for i := 0; i < len(md.textsectmap); i++ { ++ sectaddr := md.textsectmap[i].vaddr ++ sectlen := md.textsectmap[i].length ++ if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen { ++ res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr) ++ break ++ } + } ++ } else { ++ res = md.text + uintptr(off) + } + + if res > md.etext { diff --git a/tzdata-fix.patch b/tzdata-fix.patch new file mode 100644 index 0000000..8fb9f40 --- /dev/null +++ b/tzdata-fix.patch @@ -0,0 +1,97 @@ +From 8890527476e25747f063377d637b106db0008329 Mon Sep 17 00:00:00 2001 +From: Alberto Donizetti +Date: Thu, 9 Mar 2017 13:20:54 +0100 +Subject: [PATCH] [release-branch.go1.8] time: make the ParseInLocation test + more robust + +The tzdata 2017a update (2017-02-28) changed the abbreviation of the +Asia/Baghdad time zone (used in TestParseInLocation) from 'AST' to the +numeric '+03'. + +Update the test so that it skips the checks if we're using a recent +tzdata release. + +Fixes #19457 + +Change-Id: I45d705a5520743a611bdd194dc8f8d618679980c +Reviewed-on: https://go-review.googlesource.com/37964 +Reviewed-by: Ian Lance Taylor +Run-TryBot: Ian Lance Taylor +TryBot-Result: Gobot Gobot +(cherry picked from commit 91563ced5897faf729a34be7081568efcfedda31) +Reviewed-on: https://go-review.googlesource.com/37991 +Run-TryBot: Brad Fitzpatrick +--- + src/time/format_test.go | 41 +++++++++++++++++++++++++++++++---------- + 1 file changed, 31 insertions(+), 10 deletions(-) + +diff --git a/src/time/format_test.go b/src/time/format_test.go +index 219c2ca..d0013bc 100644 +--- a/src/time/format_test.go ++++ b/src/time/format_test.go +@@ -245,27 +245,45 @@ func TestParseDayOutOfRange(t *testing.T) { + } + } + ++// TestParseInLocation checks that the Parse and ParseInLocation ++// functions do not get confused by the fact that AST (Arabia Standard ++// Time) and AST (Atlantic Standard Time) are different time zones, ++// even though they have the same abbreviation. ++// ++// ICANN has been slowly phasing out invented abbreviation in favor of ++// numeric time zones (for example, the Asia/Baghdad time zone ++// abbreviation got changed from AST to +03 in the 2017a tzdata ++// release); but we still want to make sure that the time package does ++// not get confused on systems with slightly older tzdata packages. + func TestParseInLocation(t *testing.T) { +- // Check that Parse (and ParseInLocation) understand that +- // Feb 01 AST (Arabia Standard Time) and Feb 01 AST (Atlantic Standard Time) +- // are in different time zones even though both are called AST + + baghdad, err := LoadLocation("Asia/Baghdad") + if err != nil { + t.Fatal(err) + } + +- t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad) ++ var t1, t2 Time ++ ++ t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad) + if err != nil { + t.Fatal(err) + } +- t2 := Date(2013, February, 1, 00, 00, 00, 0, baghdad) +- if t1 != t2 { +- t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2) +- } ++ + _, offset := t1.Zone() +- if offset != 3*60*60 { +- t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60) ++ ++ // A zero offset means that ParseInLocation did not recognize the ++ // 'AST' abbreviation as matching the current location (Baghdad, ++ // where we'd expect a +03 hrs offset); likely because we're using ++ // a recent tzdata release (2017a or newer). ++ // If it happens, skip the Baghdad test. ++ if offset != 0 { ++ t2 = Date(2013, February, 1, 00, 00, 00, 0, baghdad) ++ if t1 != t2 { ++ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2) ++ } ++ if offset != 3*60*60 { ++ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60) ++ } + } + + blancSablon, err := LoadLocation("America/Blanc-Sablon") +@@ -273,6 +291,9 @@ func TestParseInLocation(t *testing.T) { + t.Fatal(err) + } + ++ // In this case 'AST' means 'Atlantic Standard Time', and we ++ // expect the abbreviation to correctly match the american ++ // location. + t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon) + if err != nil { + t.Fatal(err)