diff options
Diffstat (limited to 'meta/recipes-devtools/go/go-1.12/CVE-2020-15586.patch')
-rw-r--r-- | meta/recipes-devtools/go/go-1.12/CVE-2020-15586.patch | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.12/CVE-2020-15586.patch b/meta/recipes-devtools/go/go-1.12/CVE-2020-15586.patch new file mode 100644 index 0000000000..ebdc5aec6d --- /dev/null +++ b/meta/recipes-devtools/go/go-1.12/CVE-2020-15586.patch | |||
@@ -0,0 +1,131 @@ | |||
1 | From fa98f46741f818913a8c11b877520a548715131f Mon Sep 17 00:00:00 2001 | ||
2 | From: Russ Cox <rsc@golang.org> | ||
3 | Date: Mon, 13 Jul 2020 13:27:22 -0400 | ||
4 | Subject: [PATCH] net/http: synchronize "100 Continue" write and Handler writes | ||
5 | |||
6 | The expectContinueReader writes to the connection on the first | ||
7 | Request.Body read. Since a Handler might be doing a read in parallel or | ||
8 | before a write, expectContinueReader needs to synchronize with the | ||
9 | ResponseWriter, and abort if a response already went out. | ||
10 | |||
11 | The tests will land in a separate CL. | ||
12 | |||
13 | Fixes #34902 | ||
14 | Fixes CVE-2020-15586 | ||
15 | |||
16 | Change-Id: Icdd8dd539f45e8863762bd378194bb4741e875fc | ||
17 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/793350 | ||
18 | Reviewed-by: Filippo Valsorda <valsorda@google.com> | ||
19 | Reviewed-on: https://go-review.googlesource.com/c/go/+/242598 | ||
20 | Run-TryBot: Katie Hockman <katie@golang.org> | ||
21 | Reviewed-by: Filippo Valsorda <filippo@golang.org> | ||
22 | TryBot-Result: Gobot Gobot <gobot@golang.org> | ||
23 | |||
24 | Upstream-Status: Backport | ||
25 | CVE: CVE-2020-15586 | ||
26 | Signed-off-by: Li Zhou <li.zhou@windriver.com> | ||
27 | --- | ||
28 | src/net/http/server.go | 43 +++++++++++++++++++++++++++++++++++------- | ||
29 | 1 file changed, 36 insertions(+), 7 deletions(-) | ||
30 | |||
31 | diff --git a/src/net/http/server.go b/src/net/http/server.go | ||
32 | index a995a50658..d41b5f6f48 100644 | ||
33 | --- a/src/net/http/server.go | ||
34 | +++ b/src/net/http/server.go | ||
35 | @@ -425,6 +425,16 @@ type response struct { | ||
36 | wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive" | ||
37 | wantsClose bool // HTTP request has Connection "close" | ||
38 | |||
39 | + // canWriteContinue is a boolean value accessed as an atomic int32 | ||
40 | + // that says whether or not a 100 Continue header can be written | ||
41 | + // to the connection. | ||
42 | + // writeContinueMu must be held while writing the header. | ||
43 | + // These two fields together synchronize the body reader | ||
44 | + // (the expectContinueReader, which wants to write 100 Continue) | ||
45 | + // against the main writer. | ||
46 | + canWriteContinue atomicBool | ||
47 | + writeContinueMu sync.Mutex | ||
48 | + | ||
49 | w *bufio.Writer // buffers output in chunks to chunkWriter | ||
50 | cw chunkWriter | ||
51 | |||
52 | @@ -515,6 +525,7 @@ type atomicBool int32 | ||
53 | |||
54 | func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } | ||
55 | func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } | ||
56 | +func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } | ||
57 | |||
58 | // declareTrailer is called for each Trailer header when the | ||
59 | // response header is written. It notes that a header will need to be | ||
60 | @@ -878,21 +889,27 @@ type expectContinueReader struct { | ||
61 | resp *response | ||
62 | readCloser io.ReadCloser | ||
63 | closed bool | ||
64 | - sawEOF bool | ||
65 | + sawEOF atomicBool | ||
66 | } | ||
67 | |||
68 | func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { | ||
69 | if ecr.closed { | ||
70 | return 0, ErrBodyReadAfterClose | ||
71 | } | ||
72 | - if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked() { | ||
73 | - ecr.resp.wroteContinue = true | ||
74 | - ecr.resp.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n") | ||
75 | - ecr.resp.conn.bufw.Flush() | ||
76 | + w := ecr.resp | ||
77 | + if !w.wroteContinue && w.canWriteContinue.isSet() && !w.conn.hijacked() { | ||
78 | + w.wroteContinue = true | ||
79 | + w.writeContinueMu.Lock() | ||
80 | + if w.canWriteContinue.isSet() { | ||
81 | + w.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n") | ||
82 | + w.conn.bufw.Flush() | ||
83 | + w.canWriteContinue.setFalse() | ||
84 | + } | ||
85 | + w.writeContinueMu.Unlock() | ||
86 | } | ||
87 | n, err = ecr.readCloser.Read(p) | ||
88 | if err == io.EOF { | ||
89 | - ecr.sawEOF = true | ||
90 | + ecr.sawEOF.setTrue() | ||
91 | } | ||
92 | return | ||
93 | } | ||
94 | @@ -1311,7 +1328,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { | ||
95 | // because we don't know if the next bytes on the wire will be | ||
96 | // the body-following-the-timer or the subsequent request. | ||
97 | // See Issue 11549. | ||
98 | - if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF { | ||
99 | + if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF.isSet() { | ||
100 | w.closeAfterReply = true | ||
101 | } | ||
102 | |||
103 | @@ -1561,6 +1578,17 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er | ||
104 | } | ||
105 | return 0, ErrHijacked | ||
106 | } | ||
107 | + | ||
108 | + if w.canWriteContinue.isSet() { | ||
109 | + // Body reader wants to write 100 Continue but hasn't yet. | ||
110 | + // Tell it not to. The store must be done while holding the lock | ||
111 | + // because the lock makes sure that there is not an active write | ||
112 | + // this very moment. | ||
113 | + w.writeContinueMu.Lock() | ||
114 | + w.canWriteContinue.setFalse() | ||
115 | + w.writeContinueMu.Unlock() | ||
116 | + } | ||
117 | + | ||
118 | if !w.wroteHeader { | ||
119 | w.WriteHeader(StatusOK) | ||
120 | } | ||
121 | @@ -1872,6 +1900,7 @@ func (c *conn) serve(ctx context.Context) { | ||
122 | if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 { | ||
123 | // Wrap the Body reader with one that replies on the connection | ||
124 | req.Body = &expectContinueReader{readCloser: req.Body, resp: w} | ||
125 | + w.canWriteContinue.setTrue() | ||
126 | } | ||
127 | } else if req.Header.get("Expect") != "" { | ||
128 | w.sendExpectationFailed() | ||
129 | -- | ||
130 | 2.17.1 | ||
131 | |||