From: Damien Neil Date: Tue, 30 Sep 2025 22:11:16 +0000 (-0700) Subject: [release-branch.go1.25] net/textproto: avoid quadratic complexity in Reader.ReadResponse X-Git-Tag: go1.25.2~7 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=5d7a787aa2b486f77537eeaed9c38c940a7182b8;p=gostls13.git [release-branch.go1.25] net/textproto: avoid quadratic complexity in Reader.ReadResponse Reader.ReadResponse constructed a response string from repeated string concatenation, permitting a malicious sender to cause excessive memory allocation and CPU consumption by sending a response consisting of many short lines. Use a strings.Builder to construct the string instead. Thanks to Jakub Ciolek for reporting this issue. Fixes CVE-2025-61724 For #75716 Fixes #75718 Change-Id: I1a98ce85a21b830cb25799f9ac9333a67400d736 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2940 Reviewed-by: Roland Shoemaker Reviewed-by: Nicholas Husin Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2960 Reviewed-by: Damien Neil Reviewed-on: https://go-review.googlesource.com/c/go/+/709846 Reviewed-by: Carlos Amedee TryBot-Bypass: Michael Pratt Auto-Submit: Michael Pratt --- diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index d375340121..94e3e0b53d 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -284,8 +284,10 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err err // // An expectCode <= 0 disables the check of the status code. func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) { - code, continued, message, err := r.readCodeLine(expectCode) + code, continued, first, err := r.readCodeLine(expectCode) multi := continued + var messageBuilder strings.Builder + messageBuilder.WriteString(first) for continued { line, err := r.ReadLine() if err != nil { @@ -296,12 +298,15 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err err var moreMessage string code2, continued, moreMessage, err = parseCodeLine(line, 0) if err != nil || code2 != code { - message += "\n" + strings.TrimRight(line, "\r\n") + messageBuilder.WriteByte('\n') + messageBuilder.WriteString(strings.TrimRight(line, "\r\n")) continued = true continue } - message += "\n" + moreMessage + messageBuilder.WriteByte('\n') + messageBuilder.WriteString(moreMessage) } + message = messageBuilder.String() if err != nil && multi && message != "" { // replace one line error message with all lines (full message) err = &Error{code, message}