diff --git a/SPECS/azurelinux-image-tools/CVE-2026-39882.patch b/SPECS/azurelinux-image-tools/CVE-2026-39882.patch new file mode 100644 index 00000000000..1f2d5df87a7 --- /dev/null +++ b/SPECS/azurelinux-image-tools/CVE-2026-39882.patch @@ -0,0 +1,169 @@ +From d3070852ca48669c5dbd6b4559c3a9cab8c9eb99 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Mon, 20 Apr 2026 13:51:02 +0000 +Subject: [PATCH] Limit OTLP HTTP response body to 4 MiB and treat excess as + non-retryable; add tests exposure var; apply to logs, metrics, traces HTTP + exporters + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/open-telemetry/opentelemetry-go/commit/5e363de517dba6db62736b2f5cdef0e0929b4cd0.patch +--- + .../otlptrace/otlptracehttp/export_test.go | 8 ++++++++ + .../otlp/otlplog/otlploghttp/client.go | 20 +++++++++++++++++-- + .../otlp/otlpmetric/otlpmetrichttp/client.go | 20 +++++++++++++++++-- + .../otlp/otlptrace/otlptracehttp/client.go | 20 +++++++++++++++++-- + 4 files changed, 62 insertions(+), 6 deletions(-) + create mode 100644 exporters/otlp/otlptrace/otlptracehttp/export_test.go + +diff --git a/exporters/otlp/otlptrace/otlptracehttp/export_test.go b/exporters/otlp/otlptrace/otlptracehttp/export_test.go +new file mode 100644 +index 0000000..bbc3376 +--- /dev/null ++++ b/exporters/otlp/otlptrace/otlptracehttp/export_test.go +@@ -0,0 +1,8 @@ ++// Copyright The OpenTelemetry Authors ++// SPDX-License-Identifier: Apache-2.0 ++ ++package otlptracehttp ++ ++// MaxResponseBodySize exposes the package-level maxResponseBodySize variable ++// to allow tests to override it. ++var MaxResponseBodySize = &maxResponseBodySize +diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/client.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/client.go +index 59be105..8000956 100644 +--- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/client.go ++++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/client.go +@@ -121,6 +121,14 @@ var ourTransport = &http.Transport{ + ExpectContinueTimeout: 1 * time.Second, + } + ++// maxResponseBodySize is the maximum number of bytes to read from a response ++// body. It is set to 4 MiB per the OTLP specification recommendation to ++// mitigate excessive memory usage caused by a misconfigured or malicious ++// server. If exceeded, the response is treated as a not-retryable error. ++// This is a variable to allow tests to override it. ++var maxResponseBodySize int64 = 4 * 1024 * 1024 ++ ++ + func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs) error { + // The Exporter synchronizes access to client methods. This is not called + // after the Exporter is shutdown. Only thing to do here is send data. +@@ -164,7 +172,11 @@ func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs) + + // Read the partial success message, if any. + var respData bytes.Buffer +- if _, err := io.Copy(&respData, resp.Body); err != nil { ++ if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { ++ var maxBytesErr *http.MaxBytesError ++ if errors.As(err, &maxBytesErr) { ++ return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) ++ } + return err + } + if respData.Len() == 0 { +@@ -195,7 +207,11 @@ func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs) + // message to be returned. It will help in + // debugging the actual issue. + var respData bytes.Buffer +- if _, err := io.Copy(&respData, resp.Body); err != nil { ++ if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { ++ var maxBytesErr *http.MaxBytesError ++ if errors.As(err, &maxBytesErr) { ++ return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) ++ } + return err + } + respStr := strings.TrimSpace(respData.String()) +diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go +index 26af47e..21a0368 100644 +--- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go ++++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go +@@ -53,6 +53,14 @@ var ourTransport = &http.Transport{ + ExpectContinueTimeout: 1 * time.Second, + } + ++// maxResponseBodySize is the maximum number of bytes to read from a response ++// body. It is set to 4 MiB per the OTLP specification recommendation to ++// mitigate excessive memory usage caused by a misconfigured or malicious ++// server. If exceeded, the response is treated as a not-retryable error. ++// This is a variable to allow tests to override it. ++var maxResponseBodySize int64 = 4 * 1024 * 1024 ++ ++ + // newClient creates a new HTTP metric client. + func newClient(cfg oconf.Config) (*client, error) { + httpClient := cfg.Metrics.HTTPClient +@@ -168,7 +176,11 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou + + // Read the partial success message, if any. + var respData bytes.Buffer +- if _, err := io.Copy(&respData, resp.Body); err != nil { ++ if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { ++ var maxBytesErr *http.MaxBytesError ++ if errors.As(err, &maxBytesErr) { ++ return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) ++ } + return err + } + if respData.Len() == 0 { +@@ -199,7 +211,11 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou + // message to be returned. It will help in + // debugging the actual issue. + var respData bytes.Buffer +- if _, err := io.Copy(&respData, resp.Body); err != nil { ++ if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { ++ var maxBytesErr *http.MaxBytesError ++ if errors.As(err, &maxBytesErr) { ++ return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) ++ } + return err + } + respStr := strings.TrimSpace(respData.String()) +diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go +index c7b1a55..6bb898f 100644 +--- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go ++++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go +@@ -31,6 +31,14 @@ import ( + + const contentTypeProto = "application/x-protobuf" + ++// maxResponseBodySize is the maximum number of bytes to read from a response ++// body. It is set to 4 MiB per the OTLP specification recommendation to ++// mitigate excessive memory usage caused by a misconfigured or malicious ++// server. If exceeded, the response is treated as a not-retryable error. ++// This is a variable to allow tests to override it. ++var maxResponseBodySize int64 = 4 * 1024 * 1024 ++ ++ + var gzPool = sync.Pool{ + New: func() any { + w := gzip.NewWriter(io.Discard) +@@ -174,7 +182,11 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc + // Success, do not retry. + // Read the partial success message, if any. + var respData bytes.Buffer +- if _, err := io.Copy(&respData, resp.Body); err != nil { ++ if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { ++ var maxBytesErr *http.MaxBytesError ++ if errors.As(err, &maxBytesErr) { ++ return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) ++ } + return err + } + if respData.Len() == 0 { +@@ -205,7 +217,11 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc + // message to be returned. It will help in + // debugging the actual issue. + var respData bytes.Buffer +- if _, err := io.Copy(&respData, resp.Body); err != nil { ++ if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { ++ var maxBytesErr *http.MaxBytesError ++ if errors.As(err, &maxBytesErr) { ++ return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) ++ } + return err + } + respStr := strings.TrimSpace(respData.String()) +-- +2.45.4 + diff --git a/SPECS/azurelinux-image-tools/azurelinux-image-tools.spec b/SPECS/azurelinux-image-tools/azurelinux-image-tools.spec index 3cad0890004..66a59f1f9fd 100644 --- a/SPECS/azurelinux-image-tools/azurelinux-image-tools.spec +++ b/SPECS/azurelinux-image-tools/azurelinux-image-tools.spec @@ -3,7 +3,7 @@ Summary: Azure Linux Image Tools Name: azurelinux-image-tools Version: 1.2.0 -Release: 2%{?dist} +Release: 3%{?dist} License: MIT URL: https://github.com/microsoft/azure-linux-image-tools/ Group: Applications/System @@ -16,6 +16,7 @@ Source0: https://github.com/microsoft/azure-linux-image-tools/archive/ref # Source1: %{name}-%{version}-vendor.tar.gz Patch0: CVE-2026-27141.patch +Patch1: CVE-2026-39882.patch BuildRequires: golang < 1.25 BuildRequires: systemd-udev Requires: %{name}-imagecustomizer = %{version}-%{release} @@ -112,6 +113,9 @@ go test -C toolkit/tools ./... %{_bindir}/osmodifier %changelog +* Mon Apr 20 2026 Azure Linux Security Servicing Account - 1.2.0-3 +- Patch for CVE-2026-39882 + * Thu Mar 05 2026 Azure Linux Security Servicing Account - 1.2.0-2 - Patch for CVE-2026-27141