]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.25] net/textproto: avoid quadratic complexity in Reader.ReadResponse
authorDamien Neil <dneil@google.com>
Tue, 30 Sep 2025 22:11:16 +0000 (15:11 -0700)
committerGopher Robot <gobot@golang.org>
Tue, 7 Oct 2025 18:02:09 +0000 (11:02 -0700)
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 <bracewell@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2960
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709846
Reviewed-by: Carlos Amedee <carlos@golang.org>
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>

src/net/textproto/reader.go

index d375340121fa0b7d72e63330741d7eef76f3be5c..94e3e0b53d115ea85e241eaad0d8acb83e0ea8b0 100644 (file)
@@ -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}