diff --git a/SPECS/containerd2/CVE-2026-35469.patch b/SPECS/containerd2/CVE-2026-35469.patch new file mode 100644 index 00000000000..ab659cb6c93 --- /dev/null +++ b/SPECS/containerd2/CVE-2026-35469.patch @@ -0,0 +1,658 @@ +From 2d3ef6113ced4dd767d281944d176cb4bc92cc50 Mon Sep 17 00:00:00 2001 +From: jykanase +Date: Thu, 23 Apr 2026 07:02:38 +0000 +Subject: [PATCH] CVE-2026-35469 + +Upstream Patch Reference: https://github.com/moby/spdystream/compare/v0.5.0...v0.5.1.patch + +--- + go.mod | 2 +- + go.sum | 4 +- + vendor/github.com/moby/spdystream/NOTICE | 12 +++ + .../github.com/moby/spdystream/connection.go | 11 ++- + .../github.com/moby/spdystream/spdy/LICENSE | 27 +++++++ + .../github.com/moby/spdystream/spdy/PATENTS | 22 +++++ + .../moby/spdystream/spdy/dictionary.go | 16 ---- + .../moby/spdystream/spdy/options.go | 25 ++++++ + .../moby/spdystream/spdy/options_test.go | 33 ++++++++ + .../github.com/moby/spdystream/spdy/read.go | 58 ++++++++----- + .../github.com/moby/spdystream/spdy/types.go | 49 +++++++---- + .../github.com/moby/spdystream/spdy/write.go | 81 ++++++++++++------- + vendor/modules.txt | 2 +- + 13 files changed, 255 insertions(+), 87 deletions(-) + create mode 100644 vendor/github.com/moby/spdystream/spdy/LICENSE + create mode 100644 vendor/github.com/moby/spdystream/spdy/PATENTS + create mode 100644 vendor/github.com/moby/spdystream/spdy/options.go + create mode 100644 vendor/github.com/moby/spdystream/spdy/options_test.go + +diff --git a/go.mod b/go.mod +index 1e96a3d..96dccee 100644 +--- a/go.mod ++++ b/go.mod +@@ -114,7 +114,7 @@ require ( + github.com/mdlayher/socket v0.5.1 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect +- github.com/moby/spdystream v0.5.0 // indirect ++ github.com/moby/spdystream v0.5.1 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect +diff --git a/go.sum b/go.sum +index 7342f89..4806ddf 100644 +--- a/go.sum ++++ b/go.sum +@@ -224,8 +224,8 @@ github.com/mistifyio/go-zfs/v3 v3.0.1/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkO + github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= + github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= + github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +-github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +-github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= ++github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y= ++github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= + github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= + github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= + github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +diff --git a/vendor/github.com/moby/spdystream/NOTICE b/vendor/github.com/moby/spdystream/NOTICE +index b9b11c9..24e2e2a 100644 +--- a/vendor/github.com/moby/spdystream/NOTICE ++++ b/vendor/github.com/moby/spdystream/NOTICE +@@ -3,3 +3,15 @@ Copyright 2014-2021 Docker Inc. + + This product includes software developed at + Docker Inc. (https://www.docker.com/). ++ ++SPDY implementation (spdy/) ++ ++The spdy directory contains code derived from the Go project (golang.org/x/net). ++ ++Copyright 2009-2013 The Go Authors. ++Licensed under the BSD 3-Clause License. ++ ++Modifications Copyright 2014-2021 Docker Inc. ++ ++The BSD license text and Go patent grant are included in ++spdy/LICENSE and spdy/PATENTS. +diff --git a/vendor/github.com/moby/spdystream/connection.go b/vendor/github.com/moby/spdystream/connection.go +index 1394d0a..69ce477 100644 +--- a/vendor/github.com/moby/spdystream/connection.go ++++ b/vendor/github.com/moby/spdystream/connection.go +@@ -224,7 +224,13 @@ type Connection struct { + // NewConnection creates a new spdy connection from an existing + // network connection. + func NewConnection(conn net.Conn, server bool) (*Connection, error) { +- framer, framerErr := spdy.NewFramer(conn, conn) ++ return NewConnectionWithOptions(conn, server) ++} ++ ++// NewConnectionWithOptions creates a new spdy connection and applies frame ++// parsing limits via options. ++func NewConnectionWithOptions(conn net.Conn, server bool, opts ...spdy.FramerOption) (*Connection, error) { ++ framer, framerErr := spdy.NewFramerWithOptions(conn, conn, opts...) + if framerErr != nil { + return nil, framerErr + } +@@ -350,6 +356,9 @@ Loop: + } else { + debugMessage("(%p) EOF received", s) + } ++ if spdyErr, ok := err.(*spdy.Error); ok && spdyErr.Err == spdy.InvalidControlFrame { ++ _ = s.conn.Close() ++ } + break + } + var priority uint8 +diff --git a/vendor/github.com/moby/spdystream/spdy/LICENSE b/vendor/github.com/moby/spdystream/spdy/LICENSE +new file mode 100644 +index 0000000..6a66aea +--- /dev/null ++++ b/vendor/github.com/moby/spdystream/spdy/LICENSE +@@ -0,0 +1,27 @@ ++Copyright (c) 2009 The Go Authors. All rights reserved. ++ ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions are ++met: ++ ++ * Redistributions of source code must retain the above copyright ++notice, this list of conditions and the following disclaimer. ++ * Redistributions in binary form must reproduce the above ++copyright notice, this list of conditions and the following disclaimer ++in the documentation and/or other materials provided with the ++distribution. ++ * Neither the name of Google Inc. nor the names of its ++contributors may be used to endorse or promote products derived from ++this software without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +diff --git a/vendor/github.com/moby/spdystream/spdy/PATENTS b/vendor/github.com/moby/spdystream/spdy/PATENTS +new file mode 100644 +index 0000000..7330990 +--- /dev/null ++++ b/vendor/github.com/moby/spdystream/spdy/PATENTS +@@ -0,0 +1,22 @@ ++Additional IP Rights Grant (Patents) ++ ++"This implementation" means the copyrightable works distributed by ++Google as part of the Go project. ++ ++Google hereby grants to You a perpetual, worldwide, non-exclusive, ++no-charge, royalty-free, irrevocable (except as stated in this section) ++patent license to make, have made, use, offer to sell, sell, import, ++transfer and otherwise run, modify and propagate the contents of this ++implementation of Go, where such license applies only to those patent ++claims, both currently owned or controlled by Google and acquired in ++the future, licensable by Google that are necessarily infringed by this ++implementation of Go. This grant does not include claims that would be ++infringed only as a consequence of further modification of this ++implementation. If you or your agent or exclusive licensee institute or ++order or agree to the institution of patent litigation against any ++entity (including a cross-claim or counterclaim in a lawsuit) alleging ++that this implementation of Go or any code incorporated within this ++implementation of Go constitutes direct or contributory patent ++infringement, or inducement of patent infringement, then any patent ++rights granted to you under this License for this implementation of Go ++shall terminate as of the date such litigation is filed. +diff --git a/vendor/github.com/moby/spdystream/spdy/dictionary.go b/vendor/github.com/moby/spdystream/spdy/dictionary.go +index 392232f..5a5ff0e 100644 +--- a/vendor/github.com/moby/spdystream/spdy/dictionary.go ++++ b/vendor/github.com/moby/spdystream/spdy/dictionary.go +@@ -1,19 +1,3 @@ +-/* +- Copyright 2014-2021 Docker Inc. +- +- Licensed under the Apache License, Version 2.0 (the "License"); +- you may not use this file except in compliance with the License. +- You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +- Unless required by applicable law or agreed to in writing, software +- distributed under the License is distributed on an "AS IS" BASIS, +- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- See the License for the specific language governing permissions and +- limitations under the License. +-*/ +- + // Copyright 2013 The Go Authors. All rights reserved. + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. +diff --git a/vendor/github.com/moby/spdystream/spdy/options.go b/vendor/github.com/moby/spdystream/spdy/options.go +new file mode 100644 +index 0000000..ec03e0b +--- /dev/null ++++ b/vendor/github.com/moby/spdystream/spdy/options.go +@@ -0,0 +1,25 @@ ++package spdy ++ ++// FramerOption allows callers to customize frame parsing limits. ++type FramerOption func(*Framer) ++ ++// WithMaxControlFramePayloadSize sets the control-frame payload limit. ++func WithMaxControlFramePayloadSize(size uint32) FramerOption { ++ return func(f *Framer) { ++ f.maxFrameLength = size ++ } ++} ++ ++// WithMaxHeaderFieldSize sets the per-header name/value size limit. ++func WithMaxHeaderFieldSize(size uint32) FramerOption { ++ return func(f *Framer) { ++ f.maxHeaderFieldSize = size ++ } ++} ++ ++// WithMaxHeaderCount sets the maximum number of headers in a frame. ++func WithMaxHeaderCount(count uint32) FramerOption { ++ return func(f *Framer) { ++ f.maxHeaderCount = count ++ } ++} +diff --git a/vendor/github.com/moby/spdystream/spdy/options_test.go b/vendor/github.com/moby/spdystream/spdy/options_test.go +new file mode 100644 +index 0000000..b0b98f2 +--- /dev/null ++++ b/vendor/github.com/moby/spdystream/spdy/options_test.go +@@ -0,0 +1,33 @@ ++package spdy ++ ++import ( ++ "net" ++ "testing" ++) ++ ++func TestNewFramerWithOptions(t *testing.T) { ++ serverConn, clientConn := net.Pipe() ++ defer func() { ++ _ = clientConn.Close() ++ _ = serverConn.Close() ++ }() ++ ++ framer, err := NewFramerWithOptions(clientConn, clientConn, ++ WithMaxControlFramePayloadSize(1024), ++ WithMaxHeaderFieldSize(128), ++ WithMaxHeaderCount(16), ++ ) ++ if err != nil { ++ t.Fatalf("Error creating spdy connection with options: %s", err) ++ } ++ ++ if got := framer.maxFrameLength; got != 1024 { ++ t.Fatalf("Unexpected MaxControlFramePayloadSize: %d", got) ++ } ++ if got := framer.maxHeaderFieldSize; got != 128 { ++ t.Fatalf("Unexpected MaxHeaderFieldSize: %d", got) ++ } ++ if got := framer.maxHeaderCount; got != 16 { ++ t.Fatalf("Unexpected MaxHeaderCount: %d", got) ++ } ++} +diff --git a/vendor/github.com/moby/spdystream/spdy/read.go b/vendor/github.com/moby/spdystream/spdy/read.go +index 75ea045..2abb694 100644 +--- a/vendor/github.com/moby/spdystream/spdy/read.go ++++ b/vendor/github.com/moby/spdystream/spdy/read.go +@@ -1,19 +1,3 @@ +-/* +- Copyright 2014-2021 Docker Inc. +- +- Licensed under the Apache License, Version 2.0 (the "License"); +- you may not use this file except in compliance with the License. +- You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +- Unless required by applicable law or agreed to in writing, software +- distributed under the License is distributed on an "AS IS" BASIS, +- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- See the License for the specific language governing permissions and +- limitations under the License. +-*/ +- + // Copyright 2011 The Go Authors. All rights reserved. + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. +@@ -24,6 +8,7 @@ import ( + "compress/zlib" + "encoding/binary" + "io" ++ "io/ioutil" + "net/http" + "strings" + ) +@@ -59,6 +44,11 @@ func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error { + if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil { + return err + } ++ // Each setting is 8 bytes (4-byte id + 4-byte value). ++ // Payload is 4 bytes for numSettings + numSettings*8. ++ if h.length < 4 || numSettings > (h.length-4)/8 { ++ return &Error{InvalidControlFrame, 0} ++ } + frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings) + for i := uint32(0); i < numSettings; i++ { + if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil { +@@ -177,8 +167,19 @@ func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) ( + if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { + return nil, err + } ++ maxControlFramePayload := uint32(MaxDataLength) ++ if f.maxFrameLength > 0 { ++ maxControlFramePayload = f.maxFrameLength ++ } ++ + flags := ControlFlags((length & 0xff000000) >> 24) + length &= 0xffffff ++ if length > maxControlFramePayload { ++ if _, err := io.CopyN(ioutil.Discard, f.r, int64(length)); err != nil { ++ return nil, err ++ } ++ return nil, &Error{InvalidControlFrame, 0} ++ } + header := ControlFrameHeader{version, frameType, flags, length} + cframe, err := newControlFrame(frameType) + if err != nil { +@@ -190,11 +191,22 @@ func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) ( + return cframe, nil + } + +-func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) { ++func (f *Framer) parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) { + var numHeaders uint32 + if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil { + return nil, err + } ++ maxHeaders := defaultMaxHeaderCount ++ if f.maxHeaderCount > 0 { ++ maxHeaders = f.maxHeaderCount ++ } ++ if numHeaders > maxHeaders { ++ return nil, &Error{InvalidControlFrame, streamId} ++ } ++ maxFieldSize := defaultMaxHeaderFieldSize ++ if f.maxHeaderFieldSize > 0 { ++ maxFieldSize = f.maxHeaderFieldSize ++ } + var e error + h := make(http.Header, int(numHeaders)) + for i := 0; i < int(numHeaders); i++ { +@@ -202,6 +214,9 @@ func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) + if err := binary.Read(r, binary.BigEndian, &length); err != nil { + return nil, err + } ++ if length > maxFieldSize { ++ return nil, &Error{InvalidControlFrame, streamId} ++ } + nameBytes := make([]byte, length) + if _, err := io.ReadFull(r, nameBytes); err != nil { + return nil, err +@@ -217,6 +232,9 @@ func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) + if err := binary.Read(r, binary.BigEndian, &length); err != nil { + return nil, err + } ++ if length > maxFieldSize { ++ return nil, &Error{InvalidControlFrame, streamId} ++ } + value := make([]byte, length) + if _, err := io.ReadFull(r, value); err != nil { + return nil, err +@@ -256,7 +274,7 @@ func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) + } + reader = f.headerDecompressor + } +- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) ++ frame.Headers, err = f.parseHeaderValueBlock(reader, frame.StreamId) + if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { + err = &Error{WrongCompressedPayloadSize, 0} + } +@@ -288,7 +306,7 @@ func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) e + } + reader = f.headerDecompressor + } +- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) ++ frame.Headers, err = f.parseHeaderValueBlock(reader, frame.StreamId) + if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { + err = &Error{WrongCompressedPayloadSize, 0} + } +@@ -320,7 +338,7 @@ func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) err + } + reader = f.headerDecompressor + } +- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) ++ frame.Headers, err = f.parseHeaderValueBlock(reader, frame.StreamId) + if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { + err = &Error{WrongCompressedPayloadSize, 0} + } +diff --git a/vendor/github.com/moby/spdystream/spdy/types.go b/vendor/github.com/moby/spdystream/spdy/types.go +index a254a43..a552861 100644 +--- a/vendor/github.com/moby/spdystream/spdy/types.go ++++ b/vendor/github.com/moby/spdystream/spdy/types.go +@@ -1,23 +1,9 @@ +-/* +- Copyright 2014-2021 Docker Inc. +- +- Licensed under the Apache License, Version 2.0 (the "License"); +- you may not use this file except in compliance with the License. +- You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +- Unless required by applicable law or agreed to in writing, software +- distributed under the License is distributed on an "AS IS" BASIS, +- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- See the License for the specific language governing permissions and +- limitations under the License. +-*/ +- + // Copyright 2011 The Go Authors. All rights reserved. + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + ++// Modifications Copyright 2014-2021 Docker Inc. ++ + // Package spdy implements the SPDY protocol (currently SPDY/3), described in + // http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3. + package spdy +@@ -63,8 +49,20 @@ const ( + ) + + // MaxDataLength is the maximum number of bytes that can be stored in one frame. ++// ++// SPDY frame headers encode the payload length using a 24-bit field, ++// so the maximum representable size for both data and control frames ++// is 2^24-1 bytes. ++// ++// See the SPDY/3 specification, "Frame Format": ++// https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1/ + const MaxDataLength = 1<<24 - 1 + ++const ( ++ defaultMaxHeaderFieldSize uint32 = 1 << 20 ++ defaultMaxHeaderCount uint32 = 1000 ++) ++ + // headerValueSepator separates multiple header values. + const headerValueSeparator = "\x00" + +@@ -269,6 +267,10 @@ type Framer struct { + r io.Reader + headerReader io.LimitedReader + headerDecompressor io.ReadCloser ++ ++ maxFrameLength uint32 // overrides the default frame payload length limit. ++ maxHeaderFieldSize uint32 // overrides the default per-header name/value length limit. ++ maxHeaderCount uint32 // overrides the default header count limit. + } + + // NewFramer allocates a new Framer for a given SPDY connection, represented by +@@ -276,6 +278,16 @@ type Framer struct { + // from/to the Reader and Writer, so the caller should pass in an appropriately + // buffered implementation to optimize performance. + func NewFramer(w io.Writer, r io.Reader) (*Framer, error) { ++ return newFramer(w, r) ++} ++ ++// NewFramerWithOptions allocates a new Framer for a given SPDY connection and ++// applies frame parsing limits via options. ++func NewFramerWithOptions(w io.Writer, r io.Reader, opts ...FramerOption) (*Framer, error) { ++ return newFramer(w, r, opts...) ++} ++ ++func newFramer(w io.Writer, r io.Reader, opts ...FramerOption) (*Framer, error) { + compressBuf := new(bytes.Buffer) + compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary)) + if err != nil { +@@ -287,5 +299,10 @@ func NewFramer(w io.Writer, r io.Reader) (*Framer, error) { + headerCompressor: compressor, + r: r, + } ++ for _, opt := range opts { ++ if opt != nil { ++ opt(framer) ++ } ++ } + return framer, nil + } +diff --git a/vendor/github.com/moby/spdystream/spdy/write.go b/vendor/github.com/moby/spdystream/spdy/write.go +index ab6d91f..75084d3 100644 +--- a/vendor/github.com/moby/spdystream/spdy/write.go ++++ b/vendor/github.com/moby/spdystream/spdy/write.go +@@ -1,19 +1,3 @@ +-/* +- Copyright 2014-2021 Docker Inc. +- +- Licensed under the Apache License, Version 2.0 (the "License"); +- you may not use this file except in compliance with the License. +- You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +- Unless required by applicable law or agreed to in writing, software +- distributed under the License is distributed on an "AS IS" BASIS, +- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- See the License for the specific language governing permissions and +- limitations under the License. +-*/ +- + // Copyright 2011 The Go Authors. All rights reserved. + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. +@@ -23,6 +7,7 @@ package spdy + import ( + "encoding/binary" + "io" ++ "math" + "net/http" + "strings" + ) +@@ -63,13 +48,21 @@ func (frame *RstStreamFrame) write(f *Framer) (err error) { + func (frame *SettingsFrame) write(f *Framer) (err error) { + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeSettings +- frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4) ++ payloadLen := len(frame.FlagIdValues)*8 + 4 ++ if payloadLen > MaxDataLength { ++ return &Error{InvalidControlFrame, 0} ++ } ++ frame.CFHeader.length = uint32(payloadLen) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } +- if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil { ++ n := len(frame.FlagIdValues) ++ if uint64(n) > math.MaxUint32 { ++ return &Error{InvalidControlFrame, 0} ++ } ++ if err = binary.Write(f.w, binary.BigEndian, uint32(n)); err != nil { + return + } + for _, flagIdValue := range frame.FlagIdValues { +@@ -170,29 +163,41 @@ func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error { + + func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) { + n = 0 +- if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil { ++ numHeaders := len(h) ++ if numHeaders > math.MaxInt32 { ++ return n, &Error{InvalidControlFrame, 0} ++ } ++ if err = binary.Write(w, binary.BigEndian, uint32(numHeaders)); err != nil { + return + } +- n += 2 ++ n += 4 + for name, values := range h { +- if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil { ++ nameLen := len(name) ++ if nameLen > math.MaxInt32 { ++ return n, &Error{InvalidControlFrame, 0} ++ } ++ if err = binary.Write(w, binary.BigEndian, uint32(nameLen)); err != nil { + return + } +- n += 2 ++ n += 4 + name = strings.ToLower(name) + if _, err = io.WriteString(w, name); err != nil { + return + } +- n += len(name) ++ n += nameLen + v := strings.Join(values, headerValueSeparator) +- if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil { ++ vLen := len(v) ++ if vLen > math.MaxInt32 { ++ return n, &Error{InvalidControlFrame, 0} ++ } ++ if err = binary.Write(w, binary.BigEndian, uint32(vLen)); err != nil { + return + } +- n += 2 ++ n += 4 + if _, err = io.WriteString(w, v); err != nil { + return + } +- n += len(v) ++ n += vLen + } + return + } +@@ -216,7 +221,11 @@ func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) { + // Set ControlFrameHeader. + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeSynStream +- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10) ++ hLen := len(f.headerBuf.Bytes()) + 10 ++ if hLen > MaxDataLength { ++ return &Error{InvalidControlFrame, 0} ++ } ++ frame.CFHeader.length = uint32(hLen) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { +@@ -260,7 +269,11 @@ func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) { + // Set ControlFrameHeader. + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeSynReply +- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4) ++ hLen := len(f.headerBuf.Bytes()) + 4 ++ if hLen > MaxDataLength { ++ return &Error{InvalidControlFrame, 0} ++ } ++ frame.CFHeader.length = uint32(hLen) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { +@@ -295,7 +308,11 @@ func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) { + // Set ControlFrameHeader. + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeHeaders +- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4) ++ hLen := len(f.headerBuf.Bytes()) + 4 ++ if hLen > MaxDataLength { ++ return &Error{InvalidControlFrame, 0} ++ } ++ frame.CFHeader.length = uint32(hLen) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { +@@ -323,7 +340,11 @@ func (f *Framer) writeDataFrame(frame *DataFrame) (err error) { + if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { + return + } +- flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data)) ++ dLen := len(frame.Data) ++ if dLen > MaxDataLength { ++ return &Error{InvalidDataFrame, frame.StreamId} ++ } ++ flagsAndLength := uint32(frame.Flags)<<24 | uint32(dLen) + if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil { + return + } +diff --git a/vendor/modules.txt b/vendor/modules.txt +index 1f5fab5..b30f288 100644 +--- a/vendor/modules.txt ++++ b/vendor/modules.txt +@@ -372,7 +372,7 @@ github.com/mistifyio/go-zfs/v3 + # github.com/moby/locker v1.0.1 + ## explicit; go 1.13 + github.com/moby/locker +-# github.com/moby/spdystream v0.5.0 ++# github.com/moby/spdystream v0.5.1 + ## explicit; go 1.13 + github.com/moby/spdystream + github.com/moby/spdystream/spdy +-- +2.45.4 + diff --git a/SPECS/containerd2/containerd2.spec b/SPECS/containerd2/containerd2.spec index a645457fb43..c0398749ae6 100644 --- a/SPECS/containerd2/containerd2.spec +++ b/SPECS/containerd2/containerd2.spec @@ -5,7 +5,7 @@ Summary: Industry-standard container runtime Name: %{upstream_name}2 Version: 2.1.6 -Release: 1%{?dist} +Release: 2%{?dist} License: ASL 2.0 Group: Tools/Container URL: https://www.containerd.io @@ -19,6 +19,7 @@ Source2: containerd.toml Patch0: multi-snapshotters-support.patch Patch1: tardev-support.patch Patch2: fix-credential-leak-in-cri-errors.patch +Patch3: CVE-2026-35469.patch %{?systemd_requires} @@ -95,6 +96,9 @@ fi %dir /opt/containerd/lib %changelog +* Thu Apr 24 2026 Jyoti Kanase - 2.1.6-2 +- Modify CVE-2026-35469 patch for 2.1.6 + * Fri Apr 17 2026 Jyoti Kanase - 2.1.6-1 - Upgrade to 2.1.6 - Remove CVE patches fixed in upstream: CVE-2024-25621, CVE-2024-40635,