| @@ -312,12 +312,25 @@ func (s *Source) decodeWithPreference(ctx context.Context, stream io.Reader, met | |||||
| } | } | ||||
| } | } | ||||
| // maxCaptureBytes caps the amount of stream data buffered while the native | |||||
| // decoder is deciding whether it can handle the format. Without a cap, a | |||||
| // decoder that reads extensively before returning ErrUnsupported could grow | |||||
| // this buffer unboundedly on a corrupt or adversarial stream. | |||||
| const maxCaptureBytes = 1 << 20 // 1 MiB | |||||
| // errCaptureLimitExceeded is returned by capturingReader when the buffer cap | |||||
| // is hit. The caller should treat it like ErrUnsupported and fall back. | |||||
| var errCaptureLimitExceeded = errors.New("capture buffer limit exceeded") | |||||
| type capturingReader struct { | type capturingReader struct { | ||||
| r io.Reader | r io.Reader | ||||
| buf bytes.Buffer | buf bytes.Buffer | ||||
| } | } | ||||
| func (r *capturingReader) Read(p []byte) (int, error) { | func (r *capturingReader) Read(p []byte) (int, error) { | ||||
| if r.buf.Len() >= maxCaptureBytes { | |||||
| return 0, errCaptureLimitExceeded | |||||
| } | |||||
| n, err := r.r.Read(p) | n, err := r.r.Read(p) | ||||
| if n > 0 { | if n > 0 { | ||||
| _, _ = r.buf.Write(p[:n]) | _, _ = r.buf.Write(p[:n]) | ||||