diff -Nru golang-1.3.3/debian/changelog golang-1.3.3/debian/changelog --- golang-1.3.3/debian/changelog 2014-12-12 13:11:08.000000000 -0800 +++ golang-1.3.3/debian/changelog 2015-09-14 17:06:00.000000000 -0700 @@ -1,3 +1,12 @@ +golang (2:1.3.3-1+deb8u1) stable; urgency=high + + * Apply backported CVE fixes (Closes: #795106). + - CVE-2015-5739: Invalid headers are parsed as valid headers + - CVE-2015-5740: RFC 7230 3.3.3 4 violation + - CVE-2015-5741: other discoveries of security-relevant RFC 7230 violations + + -- Tianon Gravi Mon, 14 Sep 2015 15:37:36 -0700 + golang (2:1.3.3-1) unstable; urgency=medium * New upstream version (https://code.google.com/p/go/source/list?name=go1.3.3) diff -Nru golang-1.3.3/debian/patches/cve-2015-5739-5740-5741.patch golang-1.3.3/debian/patches/cve-2015-5739-5740-5741.patch --- golang-1.3.3/debian/patches/cve-2015-5739-5740-5741.patch 1969-12-31 16:00:00.000000000 -0800 +++ golang-1.3.3/debian/patches/cve-2015-5739-5740-5741.patch 2015-09-14 17:06:53.000000000 -0700 @@ -0,0 +1,391 @@ +Description: Fixes for CVE-2015-5739, CVE-2015-5740, and CVE-2015-5741 +Author: Tianon Gravi +Applied-Upstream: 1.5+ + +Index: golang/src/pkg/net/http/header.go +=================================================================== +--- golang.orig/src/pkg/net/http/header.go ++++ golang/src/pkg/net/http/header.go +@@ -168,6 +168,8 @@ func (h Header) WriteSubset(w io.Writer, + // 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 +Index: golang/src/pkg/net/textproto/reader.go +=================================================================== +--- golang.orig/src/pkg/net/textproto/reader.go ++++ golang/src/pkg/net/textproto/reader.go +@@ -540,11 +540,16 @@ func (r *Reader) upcomingHeaderNewlines( + // 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)) + } +@@ -558,19 +563,44 @@ func CanonicalMIMEHeaderKey(s string) st + + 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 +Index: golang/src/pkg/net/textproto/reader_test.go +=================================================================== +--- golang.orig/src/pkg/net/textproto/reader_test.go ++++ golang/src/pkg/net/textproto/reader_test.go +@@ -24,11 +24,14 @@ var canonicalHeaderKeyTests = []canonica + {"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) { +@@ -185,7 +188,7 @@ func TestReadMIMEHeaderNonCompliant(t *t + "Foo": {"bar"}, + "Content-Language": {"en"}, + "Sid": {"0"}, +- "Audio-Mode": {"None"}, ++ "Audio Mode": {"None"}, + "Privilege": {"127"}, + } + if !reflect.DeepEqual(m, want) || err != nil { +Index: golang/src/pkg/net/http/readrequest_test.go +=================================================================== +--- golang.orig/src/pkg/net/http/readrequest_test.go ++++ golang/src/pkg/net/http/readrequest_test.go +@@ -9,6 +9,7 @@ import ( + "bytes" + "fmt" + "io" ++ "io/ioutil" + "net/url" + "reflect" + "testing" +@@ -176,6 +177,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", +@@ -295,6 +326,59 @@ var reqTests = []reqTest{ + noTrailer, + noError, + }, ++ ++ // Connection: close. golang.org/issue/8261 ++ { ++ "GET / HTTP/1.1\r\nHost: issue8261.com\r\nConnection: close\r\n\r\n", ++ &Request{ ++ Method: "GET", ++ URL: &url.URL{ ++ Path: "/", ++ }, ++ Header: Header{ ++ // This wasn't removed from Go 1.0 to ++ // Go 1.3, so locking it in that we ++ // keep this: ++ "Connection": []string{"close"}, ++ }, ++ Host: "issue8261.com", ++ Proto: "HTTP/1.1", ++ ProtoMajor: 1, ++ ProtoMinor: 1, ++ Close: true, ++ RequestURI: "/", ++ }, ++ ++ noBody, ++ 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) { +@@ -329,3 +413,34 @@ 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_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) ++ } ++ } ++} +Index: golang/src/pkg/net/http/transfer.go +=================================================================== +--- golang.orig/src/pkg/net/http/transfer.go ++++ golang/src/pkg/net/http/transfer.go +@@ -138,6 +138,9 @@ func (t *transferWriter) shouldSendConte + return true + } + if t.ContentLength == 0 && isIdentity(t.TransferEncoding) { ++ if t.Method == "GET" || t.Method == "HEAD" { ++ return false ++ } + return true + } + +@@ -305,6 +308,7 @@ func readTransfer(msg interface{}, r *bu + } + 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 +@@ -320,7 +324,7 @@ func readTransfer(msg interface{}, r *bu + } + + // 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 + } +@@ -408,12 +412,11 @@ func chunked(te []string) bool { return + 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 + } +- + delete(header, "Transfer-Encoding") + + encodings := strings.Split(raw[0], ",") +@@ -438,9 +441,22 @@ func fixTransferEncoding(requestMethod s + 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. ++ // 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." ++ // ++ // 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 + } +@@ -452,9 +468,17 @@ func fixTransferEncoding(requestMethod s + // 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 { +@@ -465,13 +489,21 @@ func fixLength(isResponse bool, status i + 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 { +@@ -482,11 +514,14 @@ func fixLength(isResponse bool, status i + header.Del("Content-Length") + } + +- if !isResponse && requestMethod == "GET" { +- // RFC 2616 doesn't explicitly permit nor forbid an ++ if !isResponse { ++ // RFC 2616 neither explicitly permits nor forbids an + // entity-body on a GET request so we permit one if + // declared, but we default to 0 here (not -1 below) + // if there's no mention of a body. ++ // Likewise, all other request methods are assumed to have ++ // no body if neither Transfer-Encoding chunked nor a ++ // Content-Length are set. + return 0, nil + } + diff -Nru golang-1.3.3/debian/patches/series golang-1.3.3/debian/patches/series --- golang-1.3.3/debian/patches/series 2014-12-12 12:44:54.000000000 -0800 +++ golang-1.3.3/debian/patches/series 2015-09-14 15:28:21.000000000 -0700 @@ -2,3 +2,4 @@ 0002-archive-tar-reuse-temporary-buffer-in-writeHeader.patch 0003-archive-tar-reuse-temporary-buffer-in-readHeader.patch 0004-archive-tar-fix-writing-of-pax-headers.patch +cve-2015-5739-5740-5741.patch