Compare commits
164 Commits
Author | SHA1 | Date |
---|---|---|
Jakub Čajka | b61393bfb6 | |
Jakub Čajka | e508311512 | |
Jakub Čajka | b688c00ba0 | |
Jakub Čajka | c4aa731b10 | |
Jakub Čajka | 480d70a19c | |
Jakub Čajka | c909a8f70d | |
Jakub Čajka | 3af15562d1 | |
Jakub Čajka | c3b72c1a47 | |
Jakub Čajka | 3b89fed2fe | |
Jakub Čajka | 9ad1b634ea | |
Jakub Čajka | 0301e6483a | |
Jakub Čajka | 7d97257830 | |
Jakub Čajka | f7816c011a | |
Jakub Čajka | d0a2453060 | |
Jakub Čajka | b9f45a789f | |
Jakub Čajka | fc3cecf952 | |
Jakub Čajka | 46137b6f4c | |
Jakub Čajka | ebf90baf57 | |
Jakub Čajka | a35b3718c0 | |
Mohan Boddu | c6f5d788eb | |
Jakub Čajka | be0aa0461a | |
Jakub Čajka | 34238f3930 | |
Jakub Čajka | 8547fbcae7 | |
Jakub Čajka | 623973606f | |
Jakub Čajka | 371df34265 | |
Jakub Čajka | a6109823f2 | |
Jakub Čajka | 7371bb1d93 | |
Jakub Čajka | 6e78911a79 | |
Jakub Čajka | 5abf0c8166 | |
Jakub Čajka | 9ca117e19c | |
Jakub Čajka | 40390077fd | |
Jakub Čajka | 55f301f006 | |
Jakub Čajka | dc8fe7c9ce | |
Jakub Čajka | 5c3bfeff0a | |
Jakub Čajka | e3d5bfee3f | |
Jakub Čajka | 45a3692f23 | |
Jakub Čajka | 414707a1eb | |
Jakub Čajka | fd042bef95 | |
Vincent Batts | 27c6fb3111 | |
Vincent Batts | 682f928b4c | |
Vincent Batts | 0d7b61e3f5 | |
Vincent Batts | 821a201d20 | |
Vincent Batts | ab2af38a0f | |
Vincent Batts | 93edd60791 | |
Vincent Batts | aa501a2cd8 | |
Vincent Batts | 6eee324d17 | |
Vincent Batts | 8350bb0fe4 | |
Vincent Batts | 65328ffa21 | |
Vincent Batts | 2986c3304e | |
Vincent Batts | 9de436f47e | |
Vincent Batts | 07f7084dbc | |
Vincent Batts | 8e03a6571d | |
Vincent Batts | 627516c002 | |
Vincent Batts | 8b9f2ff413 | |
Vincent Batts | 9d7e13198d | |
Vincent Batts | 6cc32fc12f | |
Vincent Batts | 3c45dc2a3a | |
Vincent Batts | 47ce6d73cf | |
Vincent Batts | 84033d417e | |
Vincent Batts | 33152ba710 | |
Vincent Batts | 31e8a62d23 | |
Vincent Batts | 3b49f3293c | |
Vincent Batts | 110e264e04 | |
Vincent Batts | 9380b0eceb | |
Vincent Batts | abfb918aeb | |
Vincent Batts | d216431587 | |
Vincent Batts | 1c5a967947 | |
Vincent Batts | ea1d7adb97 | |
Vincent Batts | 39bf515e07 | |
Vincent Batts | 230c272aac | |
Vincent Batts | ab7a3d0b63 | |
Vincent Batts | 60a575aca1 | |
Vincent Batts | 6ceac592dd | |
Vincent Batts | 90e73267ad | |
Vincent Batts | d65d3f8a40 | |
Vincent Batts | 60bb592493 | |
Vincent Batts | 688fe6aa08 | |
Vincent Batts | 27d627a74b | |
Vincent Batts | c89cd17117 | |
Vincent Batts | 6da1cd966e | |
Vincent Batts | 97dd9b460e | |
Vincent Batts | c6c5ac57e3 | |
Vincent Batts | 9abed9ed84 | |
Vincent Batts | 8712265c7e | |
Vincent Batts | 73415829c2 | |
Vincent Batts | e3554eaea8 | |
Vincent Batts | 420732b09d | |
Vincent Batts | 7c6268c5d6 | |
Vincent Batts | 96d7496e05 | |
Vincent Batts | 12d61d4672 | |
Vincent Batts | d1b8e89d5a | |
Vincent Batts | 412a4623e4 | |
Vincent Batts | 3ab77e50be | |
Vincent Batts | 85310545d9 | |
Vincent Batts | 204c3459b6 | |
Vincent Batts | fa35b27c26 | |
Vincent Batts | f6645a7f86 | |
Vincent Batts | 477679dbcb | |
Vincent Batts | df3e55e110 | |
Vincent Batts | a5ed0429aa | |
Vincent Batts | eb35b4275b | |
Vincent Batts | d0e5db2e11 | |
Vincent Batts | 847040875c | |
Vincent Batts | b155214884 | |
Vincent Batts | 668c87d6d8 | |
Vincent Batts | a518e20201 | |
Vincent Batts | 1a89979632 | |
Vincent Batts | cf91978557 | |
Vincent Batts | 89650786aa | |
Vincent Batts | 15411c9d44 | |
Vincent Batts | 4ea74e374a | |
Vincent Batts | 81323f3ca5 | |
Vincent Batts | 3dab810ad8 | |
Vincent Batts | 178b1469c1 | |
Vincent Batts | 6e03bb440c | |
Vincent Batts | 70cefcfce2 | |
Vincent Batts | a0dbb55483 | |
Vincent Batts | 9cc2b544fe | |
Vincent Batts | 9b901fa781 | |
Adam Miller | 8b15f6569a | |
Adam Miller | 8537b89aa8 | |
Adam Miller | 46df8a9ba5 | |
Adam Miller | 3342a8bbe5 | |
Adam Miller | 3fb2038602 | |
Adam Miller | c773818a7b | |
Adam Miller | 2e5eb6e3d1 | |
Adam Miller | 8a8b586b8d | |
Adam Miller | bb2aeae6ad | |
Adam Miller | 9e4e25cf53 | |
Adam Miller | 957169509d | |
Adam Miller | 5253fbfde8 | |
Adam Miller | b9ac06acb3 | |
Adam Miller | 52bd3bfa8d | |
Adam Miller | ba9665b0fe | |
Adam Miller | ea4af86ffb | |
Vincent Batts | 4604bf724d | |
Vincent Batts | 583f94dcc1 | |
Vincent Batts | 8197a39098 | |
Vincent Batts | a9a1e214b2 | |
Vincent Batts | ea5e86ce3d | |
Vincent Batts | 64f997fc97 | |
Vincent Batts | a70daa81a8 | |
Vincent Batts | 9a07007520 | |
Vincent Batts | 2f21c1b8e2 | |
Vincent Batts | 0aff087ed3 | |
Vincent Batts | 5a0728e5a2 | |
Vincent Batts | d4e31c03ca | |
Vincent Batts | 3d2e2d5e92 | |
Vincent Batts | 766dafab1b | |
Vincent Batts | 80f4cc9e22 | |
Vincent Batts | 6dfa9a88bc | |
Vincent Batts | adb88d9b5d | |
Vincent Batts | 866e8dcc93 | |
Vincent Batts | 8856b2e166 | |
Adam Miller | f12359b27e | |
Adam Miller | e6ff51995e | |
Adam Miller | a601655be1 | |
Adam Miller | e3f1c1568c | |
Adam Miller | 666ac20aad | |
Adam Miller | 76d86a9d1a | |
Adam Miller | 993b94291e | |
Adam Miller | 75bcad53e9 | |
Adam Miller | 79fe1edc90 | |
Adam Miller | e275250300 |
|
@ -37,6 +37,7 @@
|
||||||
/go1.7.1.src.tar.gz
|
/go1.7.1.src.tar.gz
|
||||||
/go1.7.3.src.tar.gz
|
/go1.7.3.src.tar.gz
|
||||||
/go1.7.4.src.tar.gz
|
/go1.7.4.src.tar.gz
|
||||||
|
/go1.7.6.src.tar.gz
|
||||||
/go1.8rc3.src.tar.gz
|
/go1.8rc3.src.tar.gz
|
||||||
/go1.8.src.tar.gz
|
/go1.8.src.tar.gz
|
||||||
/go1.8.1.src.tar.gz
|
/go1.8.1.src.tar.gz
|
||||||
|
@ -45,6 +46,11 @@
|
||||||
/go1.9.src.tar.gz
|
/go1.9.src.tar.gz
|
||||||
/go1.9.1.src.tar.gz
|
/go1.9.1.src.tar.gz
|
||||||
/go1.9.2.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.10beta1.src.tar.gz
|
||||||
/go1.10beta2.src.tar.gz
|
/go1.10beta2.src.tar.gz
|
||||||
/go1.10rc1.src.tar.gz
|
/go1.10rc1.src.tar.gz
|
||||||
|
@ -62,6 +68,12 @@
|
||||||
/go1.11.1.src.tar.gz
|
/go1.11.1.src.tar.gz
|
||||||
/go1.11.2.src.tar.gz
|
/go1.11.2.src.tar.gz
|
||||||
/go1.11.4.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.12beta2.src.tar.gz
|
||||||
/go1.12rc1.src.tar.gz
|
/go1.12rc1.src.tar.gz
|
||||||
/go1.12.src.tar.gz
|
/go1.12.src.tar.gz
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
commit 117ddcb83d7f42d6aa72241240af99ded81118e9
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
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 <rsc@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
|
||||||
|
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 {
|
|
@ -0,0 +1,112 @@
|
||||||
|
commit 143822585e32449860e624cace9d2e521deee62e
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
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 <adg@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
commit 300d9a21583e7cf0149a778a0611e76ff7c6680f
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
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 <rsc@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
|
@ -0,0 +1,144 @@
|
||||||
|
From 4be3fc33ef512532b916aa14258087e89eb47347 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Russ Cox <rsc@golang.org>
|
||||||
|
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 <rsc@golang.org>
|
||||||
|
Reviewed-by: Chris Broadfoot <cbro@golang.org>
|
||||||
|
---
|
||||||
|
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 {
|
|
@ -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)
|
|
@ -0,0 +1,309 @@
|
||||||
|
commit a3156aaa121446c4136927f8c2139fefe05ba82c
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
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 <adg@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
|
||||||
|
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)
|
||||||
|
+ }
|
||||||
|
+}
|
|
@ -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
|
232
golang.spec
232
golang.spec
|
@ -1,11 +1,5 @@
|
||||||
%bcond_with bootstrap
|
%bcond_with bootstrap
|
||||||
# temporalily ignore test failures
|
|
||||||
%ifarch %{ix86} aarch64 %{arm}
|
|
||||||
%bcond_without ignore_tests
|
|
||||||
%else
|
|
||||||
%bcond_with ignore_tests
|
%bcond_with ignore_tests
|
||||||
%endif
|
|
||||||
|
|
||||||
# build ids are not currently generated:
|
# build ids are not currently generated:
|
||||||
# https://code.google.com/p/go/issues/detail?id=5238
|
# https://code.google.com/p/go/issues/detail?id=5238
|
||||||
#
|
#
|
||||||
|
@ -32,9 +26,6 @@
|
||||||
|
|
||||||
%global golibdir %{_libdir}/golang
|
%global golibdir %{_libdir}/golang
|
||||||
|
|
||||||
# This macro may not always be defined, ensure it is
|
|
||||||
%{!?gopath: %global gopath %{_datadir}/gocode}
|
|
||||||
|
|
||||||
# Golang build options.
|
# Golang build options.
|
||||||
|
|
||||||
# Build golang using external/internal(close to cgo disabled) linking.
|
# Build golang using external/internal(close to cgo disabled) linking.
|
||||||
|
@ -59,7 +50,7 @@
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
# Controls what ever we fail on failed tests
|
# Controls what ever we fail on failed tests
|
||||||
%if %{with ignore_tests}
|
%ifarch x86_64
|
||||||
%global fail_on_tests 0
|
%global fail_on_tests 0
|
||||||
%else
|
%else
|
||||||
%global fail_on_tests 1
|
%global fail_on_tests 1
|
||||||
|
@ -81,6 +72,9 @@
|
||||||
|
|
||||||
# Fedora GOROOT
|
# Fedora GOROOT
|
||||||
%global goroot /usr/lib/%{name}
|
%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
|
%ifarch x86_64
|
||||||
%global gohostarch amd64
|
%global gohostarch amd64
|
||||||
|
@ -130,9 +124,10 @@ BuildRequires: hostname
|
||||||
BuildRequires: net-tools
|
BuildRequires: net-tools
|
||||||
%endif
|
%endif
|
||||||
# for tests
|
# for tests
|
||||||
BuildRequires: pcre-devel, glibc-static, perl-interpreter, procps-ng
|
BuildRequires: pcre-devel, glibc-static, perl
|
||||||
|
|
||||||
Provides: go = %{version}-%{release}
|
Provides: go = %{version}-%{release}
|
||||||
|
Provides: go-srpm-macros
|
||||||
|
|
||||||
# Bundled/Vendored provides generated by
|
# 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(&)):"
|
# 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(&)):"
|
||||||
|
@ -232,9 +227,11 @@ Obsoletes: %{name}-vim < 1.4
|
||||||
Obsoletes: emacs-%{name} < 1.4
|
Obsoletes: emacs-%{name} < 1.4
|
||||||
|
|
||||||
# These are the only RHEL/Fedora architectures that we compile this package for
|
# These are the only RHEL/Fedora architectures that we compile this package for
|
||||||
ExclusiveArch: %{golang_arches}
|
ExclusiveArch: %{go_arches}
|
||||||
|
|
||||||
Source100: golang-gdbinit
|
Source100: golang-gdbinit
|
||||||
|
Source101: golang-prelink.conf
|
||||||
|
Source102: macros.golang
|
||||||
|
|
||||||
%description
|
%description
|
||||||
%{summary}.
|
%{summary}.
|
||||||
|
@ -310,7 +307,7 @@ Requires(preun): %{_sbindir}/update-alternatives
|
||||||
# This is an odd issue, still looking for a better fix.
|
# This is an odd issue, still looking for a better fix.
|
||||||
Requires: glibc
|
Requires: glibc
|
||||||
Requires: gcc
|
Requires: gcc
|
||||||
Recommends: git, subversion, mercurial
|
Requires: git, subversion, mercurial
|
||||||
%description bin
|
%description bin
|
||||||
%{summary}
|
%{summary}
|
||||||
|
|
||||||
|
@ -493,6 +490,21 @@ ln -sf /etc/alternatives/gofmt $RPM_BUILD_ROOT%{_bindir}/gofmt
|
||||||
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/gdbinit.d
|
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/gdbinit.d
|
||||||
cp -av %{SOURCE100} $RPM_BUILD_ROOT%{_sysconfdir}/gdbinit.d/golang.gdb
|
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
|
%check
|
||||||
export GOROOT=$(pwd -P)
|
export GOROOT=$(pwd -P)
|
||||||
export PATH="$GOROOT"/bin:"$PATH"
|
export PATH="$GOROOT"/bin:"$PATH"
|
||||||
|
@ -536,6 +548,7 @@ fi
|
||||||
# VERSION has to be present in the GOROOT, for `go install std` to work
|
# VERSION has to be present in the GOROOT, for `go install std` to work
|
||||||
%doc %{goroot}/VERSION
|
%doc %{goroot}/VERSION
|
||||||
%dir %{goroot}/doc
|
%dir %{goroot}/doc
|
||||||
|
%doc %{goroot}/doc/*
|
||||||
|
|
||||||
# go files
|
# go files
|
||||||
%dir %{goroot}
|
%dir %{goroot}
|
||||||
|
@ -558,7 +571,17 @@ fi
|
||||||
# gdbinit (for gdb debugging)
|
# gdbinit (for gdb debugging)
|
||||||
%{_sysconfdir}/gdbinit.d
|
%{_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
|
%files docs -f go-docs.list
|
||||||
|
|
||||||
|
@ -581,181 +604,62 @@ fi
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Mon Jan 13 2020 Jakub Čajka <jcajka@redhat.com> - 1.13.6-1
|
* Mon Feb 03 2020 Jakub Čajka <jcajka@redhat.com> - 1.13.6-1
|
||||||
- Rebase to go1.13.6
|
- Rebase to go1.13.6
|
||||||
|
|
||||||
* Thu Dec 05 2019 Jakub Čajka <jcajka@redhat.com> - 1.13.5-1
|
* Wed Nov 13 2019 Jakub Čajka <jcajka@redhat.com> - 1.13.4-1
|
||||||
- Rebase to go1.13.5
|
|
||||||
|
|
||||||
* Tue Nov 26 2019 Neal Gompa <ngompa@datto.com> - 1.13.4-2
|
|
||||||
- Small fixes to the spec and tighten up the file list
|
|
||||||
|
|
||||||
* Fri Nov 01 2019 Jakub Čajka <jcajka@redhat.com> - 1.13.4-1
|
|
||||||
- Rebase to go1.13.4
|
- Rebase to go1.13.4
|
||||||
- Resolves BZ#1767673
|
|
||||||
|
|
||||||
* Sat Oct 19 2019 Jakub Čajka <jcajka@redhat.com> - 1.13.3-1
|
* Wed Oct 30 2019 Jakub Čajka <jcajka@redhat.com> - 1.13.3-1
|
||||||
- Rebase to go1.13.3
|
- Rebase to go1.13.3
|
||||||
- Fix for CVE-2019-17596
|
- Fix for CVE-2019-17596
|
||||||
- Resolves: BZ#1755639, BZ#1763312
|
- Resolves: BZ#1763311
|
||||||
|
|
||||||
* Fri Sep 27 2019 Jakub Čajka <jcajka@redhat.com> - 1.13.1-1
|
* Sat Oct 5 2019 Jakub Čajka <jcajka@redhat.com> - 1.13.1-1
|
||||||
- Rebase to go1.13.1
|
- Rebase to go1.13.1
|
||||||
- Fix for CVE-2019-16276
|
- Fix for CVE-2019-16276
|
||||||
- Resolves: BZ#1755970
|
- Resolves: BZ#1755971
|
||||||
|
|
||||||
* Thu Sep 05 2019 Jakub Čajka <jcajka@redhat.com> - 1.13-2
|
* Tue Sep 10 2019 Jakub Čajka <jcajka@redhat.com> - 1.13-1
|
||||||
- Back to go1.13 tls1.3 behavior
|
|
||||||
|
|
||||||
* Wed Sep 04 2019 Jakub Čajka <jcajka@redhat.com> - 1.13-1
|
|
||||||
- Rebase to go1.13
|
- 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 <jcajka@redhat.com> - 1.13-0.rc2.1
|
* Thu Aug 08 2019 Jakub Čajka <jcajka@redhat.com> - 1.11.12-1
|
||||||
- Rebase to go1.13rc2
|
- Rebase to 1.11.12
|
||||||
- Do not enable tls1.3 by default
|
|
||||||
- Related: BZ#1737471
|
|
||||||
|
|
||||||
* Wed Aug 28 2019 Jakub Čajka <jcajka@redhat.com> - 1.13-0.rc1.2
|
* Mon Feb 04 2019 Jakub Čajka <jcajka@redhat.com> - 1.11.5-1
|
||||||
- Actually fix CVE-2019-9514 and CVE-2019-9512
|
- Rebase to go1.11.5
|
||||||
- Related: BZ#1741816, BZ#1741827
|
|
||||||
|
|
||||||
* Mon Aug 26 2019 Jakub Čajka <jcajka@redhat.com> - 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 <jcajka@redhat.com> - 1.13-0.beta1.2.2
|
|
||||||
- Fix ICE affecting aarch64
|
|
||||||
- Resolves: BZ#1735290
|
|
||||||
|
|
||||||
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.13-0.beta1.2.1
|
|
||||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
|
|
||||||
|
|
||||||
* Wed Jul 24 2019 Jakub Čajka <jcajka@redhat.com> - 1.13-0.beta1.2
|
|
||||||
- De-configure sumdb and go proxy
|
|
||||||
|
|
||||||
* Wed Jul 24 2019 Jakub Čajka <jcajka@redhat.com> - 1.13-0.beta1.1
|
|
||||||
- Rebase to 1.13beta1
|
|
||||||
- Related: BZ#1732118
|
|
||||||
|
|
||||||
* Tue Jul 09 2019 Jakub Čajka <jcajka@redhat.com> - 1.12.7-1
|
|
||||||
- Rebase to 1.12.7
|
|
||||||
- Resolves: BZ#1728056
|
|
||||||
|
|
||||||
* Wed Jun 12 2019 Jakub Čajka <jcajka@redhat.com> - 1.12.6-1
|
|
||||||
- Rebase to 1.12.6
|
|
||||||
- Resolves: BZ#1719483
|
|
||||||
|
|
||||||
* Tue May 07 2019 Jakub Čajka <jcajka@redhat.com> - 1.12.5-1
|
|
||||||
- Rebase to 1.12.5
|
|
||||||
- Resolves: BZ#1707187
|
|
||||||
|
|
||||||
* Mon Apr 08 2019 Jakub Čajka <jcajka@redhat.com> - 1.12.2-1
|
|
||||||
- Rebase to 1.12.2
|
|
||||||
- Resolves: BZ#1688996
|
|
||||||
|
|
||||||
* Mon Apr 01 2019 Jakub Čajka <jcajka@redhat.com> - 1.12.1-2
|
|
||||||
- Fix up change log, respective CVE has been fixed in go1.12rc1
|
|
||||||
|
|
||||||
* Fri Mar 15 2019 Jakub Čajka <jcajka@redhat.com> - 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 <jcajka@redhat.com> - 1.12-1
|
|
||||||
- Rebase to go1.12 proper
|
|
||||||
- Resolves: BZ#1680040
|
|
||||||
|
|
||||||
* Mon Feb 18 2019 Jakub Čajka <jcajka@redhat.com> - 1.12-0.rc1.1
|
|
||||||
- Rebase to go1.12rc1
|
|
||||||
|
|
||||||
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.12-0.beta2.2.1
|
|
||||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
|
||||||
|
|
||||||
* Sun Jan 27 2019 Jakub Čajka <jcajka@redhat.com> - 1.12-0.beta2.2
|
|
||||||
- Fix for CVE-2019-6486
|
- Fix for CVE-2019-6486
|
||||||
- Resolves: BZ#1668973
|
- Resolves: BZ#1668975
|
||||||
|
|
||||||
* Fri Jan 11 2019 Jakub Čajka <jcajka@redhat.com> - 1.12-0.beta2.1
|
|
||||||
- Rebase to go1.12beta2
|
|
||||||
|
|
||||||
* Wed Jan 02 2019 Jakub Čajka <jcajka@redhat.com> - 1.11.4-1
|
* Wed Jan 02 2019 Jakub Čajka <jcajka@redhat.com> - 1.11.4-1
|
||||||
- Rebase to go1.11.4
|
- Rebase to go1.11.4
|
||||||
- Fix for CVE-2018-16875, CVE-2018-16874 and CVE-2018-16873
|
- 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 <jcajka@redhat.com> - 1.11.2-1
|
* Fri Nov 30 2018 Jakub Čajka <jcajka@redhat.com> - 1.11.2-3
|
||||||
|
- add ppc64le proper
|
||||||
|
|
||||||
|
* Mon Nov 26 2018 Jakub Čajka <jcajka@redhat.com> - 1.11.2-2
|
||||||
|
- fix up macros file for aarch64
|
||||||
|
|
||||||
|
* Fri Nov 23 2018 Jakub Čajka <jcajka@redhat.com> - 1.11.2-1
|
||||||
- Rebase to go1.11.2
|
- Rebase to go1.11.2
|
||||||
|
|
||||||
* Thu Oct 04 2018 Jakub Čajka <jcajka@redhat.com> - 1.11.1-1
|
* Sun Oct 07 2018 Jakub Čajka <jcajka@redhat.com> - 1.11.1-1
|
||||||
- Rebase to go1.11.1
|
- Rebase to go1.11.1
|
||||||
|
|
||||||
* Mon Aug 27 2018 Jakub Čajka <jcajka@redhat.com> - 1.11-1
|
* Mon Jun 11 2018 Jakub Čajka <jcajka@redhat.com> - 1.9.7-1
|
||||||
- Rebase to go1.11 release
|
- Rebase to 1.9.7
|
||||||
|
|
||||||
* Thu Aug 23 2018 Jakub Čajka <jcajka@redhat.com> - 1.11-0.rc2.1
|
* Thu May 10 2018 Jakub Čajka <jcajka@redhat.com> - 1.9.6-1
|
||||||
- Rebase to go1.11rc2
|
- Rebase to 1.9.6
|
||||||
- Reduce size of bin package
|
|
||||||
|
|
||||||
* Tue Aug 14 2018 Jakub Čajka <jcajka@redhat.com> - 1.11-0.rc1.1
|
* Tue Mar 20 2018 Jakub Čajka <jcajka@redhat.com> - 1.9.4-1
|
||||||
- Rebase to go1.11rc1
|
- Rebase to 1.9.4
|
||||||
|
- Fix CVE-2018-6574 and CVE-2018-7187
|
||||||
* Mon Aug 06 2018 Jakub Čajka <jcajka@redhat.com> - 1.11-0.beta3.1
|
- Resolves: BZ#1543561, BZ#1543563, BZ#1546386, BZ#1546387
|
||||||
- Rebase to go1.11beta3
|
|
||||||
|
|
||||||
* Fri Jul 27 2018 Jakub Čajka <jcajka@redhat.com> - 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 <jcajka@redhat.com> - 1.11-0.beta2.1
|
|
||||||
- Rebase to 1.11beta2
|
|
||||||
|
|
||||||
* Wed Jul 18 2018 Jakub Čajka <jcajka@redhat.com> - 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 <releng@fedoraproject.org> - 1.11-0.beta1.1.1
|
|
||||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
|
||||||
|
|
||||||
* Wed Jul 04 2018 Jakub Čajka <jcajka@redhat.com> - 1.11-0.beta1.1
|
|
||||||
* Rebase to 1.11beta1
|
|
||||||
|
|
||||||
* Fri Jun 08 2018 Jakub Čajka <jcajka@redhat.com> - 1.10.3-1
|
|
||||||
- Rebase to 1.10.3
|
|
||||||
|
|
||||||
* Wed May 02 2018 Jakub Čajka <jcajka@redhat.com> - 1.10.2-1
|
|
||||||
- Rebase to 1.10.2
|
|
||||||
|
|
||||||
* Wed Apr 04 2018 Jakub Čajka <jcajka@redhat.com> - 1.10.1-1
|
|
||||||
- Rebase to 1.10.1
|
|
||||||
- Resolves: BZ#1562270
|
|
||||||
|
|
||||||
* Sat Mar 03 2018 Jakub Čajka <jcajka@redhat.com> - 1.10-2
|
|
||||||
- Fix CVE-2018-7187
|
|
||||||
- Resolves: BZ#1546386, BZ#1546388
|
|
||||||
|
|
||||||
* Wed Feb 21 2018 Jakub Čajka <jcajka@redhat.com> - 1.10-1
|
|
||||||
- Rebase to 1.10
|
|
||||||
|
|
||||||
* Thu Feb 08 2018 Jakub Čajka <jcajka@redhat.com> - 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 <releng@fedoraproject.org> - 1.10-0.rc1.1.1
|
|
||||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
|
||||||
|
|
||||||
* Fri Jan 26 2018 Jakub Čajka <jcajka@redhat.com> - 1.10-0.rc1.1
|
|
||||||
- Rebase to 1.10rc1
|
|
||||||
|
|
||||||
* Fri Jan 12 2018 Jakub Čajka <jcajka@redhat.com> - 1.10-0.beta2.1
|
|
||||||
- Rebase to 1.10beta2
|
|
||||||
|
|
||||||
* Mon Jan 08 2018 Jakub Čajka <jcajka@redhat.com> - 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
|
|
||||||
|
|
||||||
* Thu Oct 26 2017 Jakub Čajka <jcajka@redhat.com> - 1.9.2-1
|
* Thu Oct 26 2017 Jakub Čajka <jcajka@redhat.com> - 1.9.2-1
|
||||||
- Rebase to 1.9.2
|
- Rebase to 1.9.2
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,457 @@
|
||||||
|
From d6beea7f9ea1aa2ae5abca7fccb252767820aa13 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||||
|
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")
|
|
@ -0,0 +1,150 @@
|
||||||
|
From a5b97a846d70cd8db7f33c24f2b9159f935ce318 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||||
|
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 {
|
|
@ -0,0 +1,97 @@
|
||||||
|
From 8890527476e25747f063377d637b106db0008329 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alberto Donizetti <alb.donizetti@gmail.com>
|
||||||
|
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 <iant@golang.org>
|
||||||
|
Run-TryBot: Ian Lance Taylor <iant@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
(cherry picked from commit 91563ced5897faf729a34be7081568efcfedda31)
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/37991
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
---
|
||||||
|
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)
|
Loading…
Reference in New Issue