All of lore.kernel.org
 help / color / mirror / Atom feed
* [meta-virtualization][wrynose][PATCH 1/5] docker-moby: Fix CVE-2026-34040
@ 2026-11-05  6:00 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
  2026-11-05  6:00 ` [meta-virtualization][wrynose][PATCH 2/5] docker-moby: Fix CVE-2026-33997 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco) @ 2026-11-05  6:00 UTC (permalink / raw)
  To: meta-virtualization

From: Deepak Rathore <deeratho@cisco.com>

This patch applies the upstream Docker 29.x backports for
CVE-2026-34040. It rejects authorization requests whose body exceeds the
inspection limit, then increases the supported inspection limit to 4 MiB.
The request-body limit fix commits are referenced in [1] and [2], and the
public CVE advisory is referenced in [3].

[1] https://github.com/moby/moby/commit/7a402982117c20280152adbd16f020835f541665
[2] https://github.com/moby/moby/commit/f302d066877d3717869655ebd12fab47d49ca611
[3] https://github.com/moby/moby/security/advisories/GHSA-x744-4wpc-v9h2

Signed-off-by: Deepak Rathore <deeratho@cisco.com>
---
 recipes-containers/docker/docker-moby_git.bb  |   2 +
 .../docker/files/CVE-2026-34040_p1.patch      | 209 ++++++++++++++++++
 .../docker/files/CVE-2026-34040_p2.patch      |  36 +++
 3 files changed, 247 insertions(+)
 create mode 100644 recipes-containers/docker/files/CVE-2026-34040_p1.patch
 create mode 100644 recipes-containers/docker/files/CVE-2026-34040_p2.patch

diff --git a/recipes-containers/docker/docker-moby_git.bb b/recipes-containers/docker/docker-moby_git.bb
index a512219a..7561215c 100644
--- a/recipes-containers/docker/docker-moby_git.bb
+++ b/recipes-containers/docker/docker-moby_git.bb
@@ -57,6 +57,8 @@ SRC_URI = "\
         file://CVE-2026-41568.patch;patchdir=src/import \
         file://CVE-2026-42306_p1.patch;patchdir=src/import \
         file://CVE-2026-42306_p2.patch;patchdir=src/import \
+        file://CVE-2026-34040_p1.patch;patchdir=src/import \
+        file://CVE-2026-34040_p2.patch;patchdir=src/import \
 	"
 
 DOCKER_COMMIT = "${SRCREV_moby}"
diff --git a/recipes-containers/docker/files/CVE-2026-34040_p1.patch b/recipes-containers/docker/files/CVE-2026-34040_p1.patch
new file mode 100644
index 00000000..63f50944
--- /dev/null
+++ b/recipes-containers/docker/files/CVE-2026-34040_p1.patch
@@ -0,0 +1,209 @@
+From 048989b4dca317967755c484ca94157c5a68d0a0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= <pawel.gronowski@docker.com>
+Date: Mon, 16 Feb 2026 14:15:24 +0100
+Subject: [PATCH] pkg/authz: Reject requests exceeding body size limit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Previously, the authorization system would silently skip body inspection when
+request bodies exceeded the maximum size limit (1MiB).
+
+The authorization plugins would receive an empty body for inspection
+while the actual large payload would still be processed by the Docker
+daemon, allowing malicious requests to circumvent plugin-based security
+controls.
+
+CVE: CVE-2026-34040
+Upstream-Status: Backport [https://github.com/moby/moby/commit/7a402982117c20280152adbd16f020835f541665]
+
+Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
+(cherry picked from commit 7a767b27fd1238c89a5cc926c39e27d3bcf58e35)
+Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
+(cherry picked from commit 7a402982117c20280152adbd16f020835f541665)
+Signed-off-by: Deepak Rathore <deeratho@cisco.com>
+---
+ pkg/authorization/authz.go           | 56 +++++++-----------
+ pkg/authorization/authz_unix_test.go | 87 +++++++++++++++++++---------
+ 2 files changed, 80 insertions(+), 63 deletions(-)
+
+diff --git a/pkg/authorization/authz.go b/pkg/authorization/authz.go
+index 7f85fa4c4a..a5b94d6bb7 100644
+--- a/pkg/authorization/authz.go
++++ b/pkg/authorization/authz.go
+@@ -55,28 +55,31 @@ type Ctx struct {
+ 	authReq *Request
+ }
+ 
+-func isChunked(r *http.Request) bool {
+-	// RFC 7230 specifies that content length is to be ignored if Transfer-Encoding is chunked
+-	if strings.EqualFold(r.Header.Get("Transfer-Encoding"), "chunked") {
+-		return true
+-	}
+-	for _, v := range r.TransferEncoding {
+-		if strings.EqualFold(v, "chunked") {
+-			return true
+-		}
+-	}
+-	return false
+-}
+-
+ // AuthZRequest authorized the request to the docker daemon using authZ plugins
+ func (ctx *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error {
+ 	var body []byte
+-	if sendBody(ctx.requestURI, r.Header) && (r.ContentLength > 0 || isChunked(r)) && r.ContentLength < maxBodySize {
+-		var err error
+-		body, r.Body, err = drainBody(r.Body)
+-		if err != nil {
++	if sendBody(ctx.requestURI, r.Header) {
++		// Wrap the original request body in a buffered reader so we can inspect
++		// the prefix without consuming bytes from the downstream reader.
++		// `Peek(maxBodySize + 1)` is used as a size check:
++		//   - err == nil means at least maxBodySize+1 bytes are buffered/available,
++		//     so the payload exceeds the plugin limit and is rejected.
++		//   - otherwise, `peeked` contains the complete body bytes currently available
++		//     (for short bodies this is the full payload), and reads from r.Body still
++		//     stream the original body unchanged.
++		bufBody := bufio.NewReaderSize(r.Body, maxBodySize+1)
++		r.Body = ioutils.NewReadCloserWrapper(bufBody, r.Body.Close)
++
++		peeked, err := bufBody.Peek(maxBodySize + 1)
++		if err == nil {
++			// Successfully peeked maxBodySize+1 bytes, so body is too large
++			// TODO: Allows plugin to opt in
++			return fmt.Errorf("request body too large for authorization plugin: size exceeds %d bytes", maxBodySize)
++		} else if err != io.EOF {
+ 			return err
+ 		}
++
++		body = peeked
+ 	}
+ 
+ 	var h bytes.Buffer
+@@ -142,25 +145,6 @@ func (ctx *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error {
+ 	return nil
+ }
+ 
+-// drainBody dump the body (if its length is less than 1MB) without modifying the request state
+-func drainBody(body io.ReadCloser) ([]byte, io.ReadCloser, error) {
+-	bufReader := bufio.NewReaderSize(body, maxBodySize)
+-	newBody := ioutils.NewReadCloserWrapper(bufReader, func() error { return body.Close() })
+-
+-	data, err := bufReader.Peek(maxBodySize)
+-	// Body size exceeds max body size
+-	if err == nil {
+-		log.G(context.TODO()).Warnf("Request body is larger than: '%d' skipping body", maxBodySize)
+-		return nil, newBody, nil
+-	}
+-	// Body size is less than maximum size
+-	if err == io.EOF {
+-		return data, newBody, nil
+-	}
+-	// Unknown error
+-	return nil, newBody, err
+-}
+-
+ func isAuthEndpoint(urlPath string) (bool, error) {
+ 	// eg www.test.com/v1.24/auth/optional?optional1=something&optional2=something (version optional)
+ 	matched, err := regexp.MatchString(`^[^\/]*\/(v\d[\d\.]*\/)?auth.*`, urlPath)
+diff --git a/pkg/authorization/authz_unix_test.go b/pkg/authorization/authz_unix_test.go
+index 5f4902dad4..9107b4c08a 100644
+--- a/pkg/authorization/authz_unix_test.go
++++ b/pkg/authorization/authz_unix_test.go
+@@ -140,36 +140,69 @@ func TestResponseModifier(t *testing.T) {
+ 	}
+ }
+ 
+-func TestDrainBody(t *testing.T) {
+-	tests := []struct {
+-		length             int // length is the message length send to drainBody
+-		expectedBodyLength int // expectedBodyLength is the expected body length after drainBody is called
+-	}{
+-		{10, 10},                           // Small message size
+-		{maxBodySize - 1, maxBodySize - 1}, // Max message size
+-		{maxBodySize * 2, 0},               // Large message size (skip copying body)
++type recordingPlugin struct {
++	recordedRequest Request
++}
++
++func (p *recordingPlugin) Name() string { return "recording-plugin" }
++
++func (p *recordingPlugin) AuthZRequest(authReq *Request) (*Response, error) {
++	p.recordedRequest = *authReq
++	p.recordedRequest.RequestBody = bytes.Clone(authReq.RequestBody)
++	return &Response{Allow: true}, nil
++}
++
++func (p *recordingPlugin) AuthZResponse(_ *Request) (*Response, error) {
++	return &Response{Allow: true}, nil
++}
++
++func TestAuthZRequestBodyWithinLimit(t *testing.T) {
++	payload := strings.Repeat("a", maxBodySize)
++	plugin := &recordingPlugin{}
++	ctx := NewCtx([]Plugin{plugin}, "user", "tls", http.MethodPost, "/containers/create")
+ 
++	req := httptest.NewRequest(http.MethodPost, "http://example.com/containers/create", strings.NewReader(payload))
++	req.Header.Set("Content-Type", "application/json")
++
++	if err := ctx.AuthZRequest(httptest.NewRecorder(), req); err != nil {
++		t.Fatalf("AuthZRequest failed: %v", err)
+ 	}
+ 
+-	for _, test := range tests {
+-		msg := strings.Repeat("a", test.length)
+-		body, closer, err := drainBody(io.NopCloser(bytes.NewReader([]byte(msg))))
+-		if err != nil {
+-			t.Fatal(err)
+-		}
+-		if len(body) != test.expectedBodyLength {
+-			t.Fatalf("Body must be copied, actual length: '%d'", len(body))
+-		}
+-		if closer == nil {
+-			t.Fatal("Closer must not be nil")
+-		}
+-		modified, err := io.ReadAll(closer)
+-		if err != nil {
+-			t.Fatalf("Error must not be nil: '%v'", err)
+-		}
+-		if len(modified) != len(msg) {
+-			t.Fatalf("Result should not be truncated. Original length: '%d', new length: '%d'", len(msg), len(modified))
+-		}
++	if string(plugin.recordedRequest.RequestBody) != payload {
++		t.Fatalf("expected full request body to be sent to plugin, got length %d, expected %d", len(plugin.recordedRequest.RequestBody), len(payload))
++	}
++
++	remaining, err := io.ReadAll(req.Body)
++	if err != nil {
++		t.Fatalf("failed to read request body after authz: %v", err)
++	}
++	if string(remaining) != payload {
++		t.Fatalf("request body should be preserved for downstream readers")
++	}
++}
++
++func TestAuthZRequestBodyOverLimit(t *testing.T) {
++	payload := strings.Repeat("a", maxBodySize+1)
++	plugin := &recordingPlugin{}
++	ctx := NewCtx([]Plugin{plugin}, "user", "tls", http.MethodPost, "/containers/create")
++
++	req := httptest.NewRequest(http.MethodPost, "http://example.com/containers/create", strings.NewReader(payload))
++	req.Header.Set("Content-Type", "application/json")
++
++	err := ctx.AuthZRequest(httptest.NewRecorder(), req)
++	if err == nil {
++		t.Fatal("expected AuthZRequest to reject body over max size")
++	}
++	if !strings.Contains(err.Error(), "request body too large for authorization plugin") {
++		t.Fatalf("unexpected error: %v", err)
++	}
++
++	remaining, readErr := io.ReadAll(req.Body)
++	if readErr != nil {
++		t.Fatalf("failed to read request body after authz error: %v", readErr)
++	}
++	if string(remaining) != payload {
++		t.Fatalf("request body should still be preserved after over-limit check")
+ 	}
+ }
+ 
diff --git a/recipes-containers/docker/files/CVE-2026-34040_p2.patch b/recipes-containers/docker/files/CVE-2026-34040_p2.patch
new file mode 100644
index 00000000..4ccdf597
--- /dev/null
+++ b/recipes-containers/docker/files/CVE-2026-34040_p2.patch
@@ -0,0 +1,36 @@
+From c31b7dfc88d0a7d2107e72a4675ab52df193973a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= <pawel.gronowski@docker.com>
+Date: Mon, 16 Feb 2026 14:16:06 +0100
+Subject: [PATCH] pkg/authz: Increase body limit to 4 MiB
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some endpoint could potentially use a body request than 1 MiB without
+malicious intent.
+
+CVE: CVE-2026-34040
+Upstream-Status: Backport [https://github.com/moby/moby/commit/f302d066877d3717869655ebd12fab47d49ca611]
+
+Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
+(cherry picked from commit ec76e941838797fc762185c556c152f0a032d387)
+Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
+(cherry picked from commit f302d066877d3717869655ebd12fab47d49ca611)
+Signed-off-by: Deepak Rathore <deeratho@cisco.com>
+---
+ pkg/authorization/authz.go | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/pkg/authorization/authz.go b/pkg/authorization/authz.go
+index a5b94d6bb7..b635e01733 100644
+--- a/pkg/authorization/authz.go
++++ b/pkg/authorization/authz.go
+@@ -16,7 +16,7 @@ import (
+ 	"github.com/moby/moby/v2/pkg/ioutils"
+ )
+ 
+-const maxBodySize = 1048576 // 1MB
++const maxBodySize = 4 * 1024 * 1024 // 4MiB
+ 
+ // NewCtx creates new authZ context, it is used to store authorization information related to a specific docker
+ // REST http session
-- 
2.35.6


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-11-05 17:00 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05  6:00 [meta-virtualization][wrynose][PATCH 1/5] docker-moby: Fix CVE-2026-34040 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-11-05  6:00 ` [meta-virtualization][wrynose][PATCH 2/5] docker-moby: Fix CVE-2026-33997 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-11-05 17:00   ` Bruce Ashfield
2026-11-05  6:00 ` [meta-virtualization][wrynose][PATCH 3/5] docker-moby: Fix CVE-2026-17106 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-11-05 16:50   ` Bruce Ashfield
2026-11-05  6:00 ` [meta-virtualization][wrynose][PATCH 4/5] docker-moby: Fix CVE-2026-92543 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-11-05 17:00   ` Bruce Ashfield
2026-11-05  6:00 ` [meta-virtualization][wrynose][PATCH 5/5] docker-moby: Fix CVE-2026-92542 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-11-05 17:00   ` Bruce Ashfield
2026-11-05 17:00 ` [meta-virtualization][wrynose][PATCH 1/5] docker-moby: Fix CVE-2026-34040 Bruce Ashfield

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.