From 24617595e8eb9bd14e932c5948da925d5b67e5b9 Mon Sep 17 00:00:00 2001 From: Azure Linux Security Servicing Account Date: Wed, 22 Apr 2026 20:53:45 +0000 Subject: [PATCH 1/2] Patch azurelinux-image-tools for CVE-2026-39882, CVE-2026-29181 --- .../CVE-2026-29181.patch | 450 ++++++++++++++++++ .../CVE-2026-39882.patch | 154 ++++++ .../azurelinux-image-tools.spec | 7 +- 3 files changed, 610 insertions(+), 1 deletion(-) create mode 100644 SPECS/azurelinux-image-tools/CVE-2026-29181.patch create mode 100644 SPECS/azurelinux-image-tools/CVE-2026-39882.patch diff --git a/SPECS/azurelinux-image-tools/CVE-2026-29181.patch b/SPECS/azurelinux-image-tools/CVE-2026-29181.patch new file mode 100644 index 00000000000..34ef10dd10c --- /dev/null +++ b/SPECS/azurelinux-image-tools/CVE-2026-29181.patch @@ -0,0 +1,450 @@ +From 1a4eac167dc32ec6868d250617153c476a1307f8 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Wed, 22 Apr 2026 20:46:08 +0000 +Subject: [PATCH] Comply with W3C Baggage limits: update maxMembers to 64, + remove per-member byte limit; add truncation for count/size, introduce + internal errorhandler, and propagate errors during extraction. + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/open-telemetry/opentelemetry-go/commit/aa1894e09e3fe66860c7885cb40f98901b35277f.patch +--- + .../otel/baggage/baggage.go | 102 +++++++++++++----- + .../internal/errorhandler/errorhandler.go | 96 +++++++++++++++++ + .../otel/internal/global/handler.go | 32 +----- + .../otel/internal/global/state.go | 27 +---- + .../otel/propagation/baggage.go | 23 +++- + 5 files changed, 201 insertions(+), 79 deletions(-) + create mode 100644 vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go + +diff --git a/vendor/go.opentelemetry.io/otel/baggage/baggage.go b/vendor/go.opentelemetry.io/otel/baggage/baggage.go +index f83a448..e6e731e 100644 +--- a/vendor/go.opentelemetry.io/otel/baggage/baggage.go ++++ b/vendor/go.opentelemetry.io/otel/baggage/baggage.go +@@ -14,8 +14,7 @@ import ( + ) + + const ( +- maxMembers = 180 +- maxBytesPerMembers = 4096 ++ maxMembers = 64 + maxBytesPerBaggageString = 8192 + + listDelimiter = "," +@@ -29,7 +28,6 @@ var ( + errInvalidProperty = errors.New("invalid baggage list-member property") + errInvalidMember = errors.New("invalid baggage list-member") + errMemberNumber = errors.New("too many list-members in baggage-string") +- errMemberBytes = errors.New("list-member too large") + errBaggageBytes = errors.New("baggage-string too large") + ) + +@@ -309,10 +307,6 @@ func newInvalidMember() Member { + // an error if the input is invalid according to the W3C Baggage + // specification. + func parseMember(member string) (Member, error) { +- if n := len(member); n > maxBytesPerMembers { +- return newInvalidMember(), fmt.Errorf("%w: %d", errMemberBytes, n) +- } +- + var props properties + keyValue, properties, found := strings.Cut(member, propertyDelimiter) + if found { +@@ -430,6 +424,10 @@ type Baggage struct { //nolint:golint + // New returns a new valid Baggage. It returns an error if it results in a + // Baggage exceeding limits set in that specification. + // ++// If the resulting Baggage exceeds the maximum allowed members or bytes, ++// members are dropped until the limits are satisfied and an error is returned ++// along with the partial result. ++// + // It expects all the provided members to have already been validated. + func New(members ...Member) (Baggage, error) { + if len(members) == 0 { +@@ -441,7 +439,6 @@ func New(members ...Member) (Baggage, error) { + if !m.hasData { + return Baggage{}, errInvalidMember + } +- + // OpenTelemetry resolves duplicates by last-one-wins. + b[m.key] = baggage.Item{ + Value: m.value, +@@ -449,17 +446,42 @@ func New(members ...Member) (Baggage, error) { + } + } + +- // Check member numbers after deduplication. ++ var truncateErr error ++ ++ // Check member count after deduplication. + if len(b) > maxMembers { +- return Baggage{}, errMemberNumber ++ truncateErr = errors.Join(truncateErr, errMemberNumber) ++ for k := range b { ++ if len(b) <= maxMembers { ++ break ++ } ++ delete(b, k) ++ } + } + +- bag := Baggage{b} +- if n := len(bag.String()); n > maxBytesPerBaggageString { +- return Baggage{}, fmt.Errorf("%w: %d", errBaggageBytes, n) ++ // Check byte size and drop members if necessary. ++ totalBytes := 0 ++ first := true ++ for k := range b { ++ m := Member{ ++ key: k, ++ value: b[k].Value, ++ properties: fromInternalProperties(b[k].Properties), ++ } ++ memberSize := len(m.String()) ++ if !first { ++ memberSize++ // comma separator ++ } ++ if totalBytes+memberSize > maxBytesPerBaggageString { ++ truncateErr = errors.Join(truncateErr, fmt.Errorf("%w: %d", errBaggageBytes, totalBytes+memberSize)) ++ delete(b, k) ++ continue ++ } ++ totalBytes += memberSize ++ first = false + } + +- return bag, nil ++ return Baggage{b}, truncateErr + } + + // Parse attempts to decode a baggage-string from the passed string. It +@@ -475,31 +497,59 @@ func Parse(bStr string) (Baggage, error) { + return Baggage{}, nil + } + +- if n := len(bStr); n > maxBytesPerBaggageString { +- return Baggage{}, fmt.Errorf("%w: %d", errBaggageBytes, n) +- } +- + b := make(baggage.List) ++ sizes := make(map[string]int) // Track per-key byte sizes ++ var totalBytes int ++ var truncateErr error + for _, memberStr := range strings.Split(bStr, listDelimiter) { ++ // Check member count limit. ++ if len(b) >= maxMembers { ++ truncateErr = errors.Join(truncateErr, errMemberNumber) ++ break ++ } ++ + m, err := parseMember(memberStr) + if err != nil { +- return Baggage{}, err ++ truncateErr = errors.Join(truncateErr, err) ++ continue // skip invalid member, keep processing ++ } ++ ++ // Check byte size limit. ++ // Account for comma separator between members. ++ memberBytes := len(m.String()) ++ _, existingKey := b[m.key] ++ if !existingKey && len(b) > 0 { ++ memberBytes++ // comma separator only for new keys ++ } ++ ++ // Calculate new totalBytes if we add/overwrite this key ++ var newTotalBytes int ++ if oldSize, exists := sizes[m.key]; exists { ++ // Overwriting existing key: subtract old size, add new size ++ newTotalBytes = totalBytes - oldSize + memberBytes ++ } else { ++ // New key ++ newTotalBytes = totalBytes + memberBytes ++ } ++ ++ if newTotalBytes > maxBytesPerBaggageString { ++ truncateErr = errors.Join(truncateErr, errBaggageBytes) ++ break + } ++ + // OpenTelemetry resolves duplicates by last-one-wins. + b[m.key] = baggage.Item{ + Value: m.value, + Properties: m.properties.asInternal(), + } ++ sizes[m.key] = memberBytes ++ totalBytes = newTotalBytes + } + +- // OpenTelemetry does not allow for duplicate list-members, but the W3C +- // specification does. Now that we have deduplicated, ensure the baggage +- // does not exceed list-member limits. +- if len(b) > maxMembers { +- return Baggage{}, errMemberNumber ++ if len(b) == 0 { ++ return Baggage{}, truncateErr + } +- +- return Baggage{b}, nil ++ return Baggage{b}, truncateErr + } + + // Member returns the baggage list-member identified by key. +diff --git a/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go b/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go +new file mode 100644 +index 0000000..3f0ab31 +--- /dev/null ++++ b/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go +@@ -0,0 +1,96 @@ ++// Copyright The OpenTelemetry Authors ++// SPDX-License-Identifier: Apache-2.0 ++ ++// Package errorhandler provides the global error handler for OpenTelemetry. ++// ++// This package has no OTel dependencies, allowing it to be imported by any ++// package in the module without creating import cycles. ++package errorhandler // import "go.opentelemetry.io/otel/internal/errorhandler" ++ ++import ( ++ "errors" ++ "log" ++ "sync" ++ "sync/atomic" ++) ++ ++// ErrorHandler handles irremediable events. ++type ErrorHandler interface { ++ // Handle handles any error deemed irremediable by an OpenTelemetry ++ // component. ++ Handle(error) ++} ++ ++type ErrDelegator struct { ++ delegate atomic.Pointer[ErrorHandler] ++} ++ ++// Compile-time check that delegator implements ErrorHandler. ++var _ ErrorHandler = (*ErrDelegator)(nil) ++ ++func (d *ErrDelegator) Handle(err error) { ++ if eh := d.delegate.Load(); eh != nil { ++ (*eh).Handle(err) ++ return ++ } ++ log.Print(err) ++} ++ ++// setDelegate sets the ErrorHandler delegate. ++func (d *ErrDelegator) setDelegate(eh ErrorHandler) { ++ d.delegate.Store(&eh) ++} ++ ++type errorHandlerHolder struct { ++ eh ErrorHandler ++} ++ ++var ( ++ globalErrorHandler = defaultErrorHandler() ++ delegateErrorHandlerOnce sync.Once ++) ++ ++// GetErrorHandler returns the global ErrorHandler instance. ++// ++// The default ErrorHandler instance returned will log all errors to STDERR ++// until an override ErrorHandler is set with SetErrorHandler. All ++// ErrorHandler returned prior to this will automatically forward errors to ++// the set instance instead of logging. ++// ++// Subsequent calls to SetErrorHandler after the first will not forward errors ++// to the new ErrorHandler for prior returned instances. ++func GetErrorHandler() ErrorHandler { ++ return globalErrorHandler.Load().(errorHandlerHolder).eh ++} ++ ++// SetErrorHandler sets the global ErrorHandler to h. ++// ++// The first time this is called all ErrorHandler previously returned from ++// GetErrorHandler will send errors to h instead of the default logging ++// ErrorHandler. Subsequent calls will set the global ErrorHandler, but not ++// delegate errors to h. ++func SetErrorHandler(h ErrorHandler) { ++ current := GetErrorHandler() ++ ++ if _, cOk := current.(*ErrDelegator); cOk { ++ if _, ehOk := h.(*ErrDelegator); ehOk && current == h { ++ // Do not assign to the delegate of the default ErrDelegator to be ++ // itself. ++ log.Print(errors.New("no ErrorHandler delegate configured"), " ErrorHandler remains its current value.") ++ return ++ } ++ } ++ ++ delegateErrorHandlerOnce.Do(func() { ++ if def, ok := current.(*ErrDelegator); ok { ++ def.setDelegate(h) ++ } ++ }) ++ globalErrorHandler.Store(errorHandlerHolder{eh: h}) ++} ++ ++func defaultErrorHandler() *atomic.Value { ++ v := &atomic.Value{} ++ v.Store(errorHandlerHolder{eh: &ErrDelegator{}}) ++ return v ++} +diff --git a/vendor/go.opentelemetry.io/otel/internal/global/handler.go b/vendor/go.opentelemetry.io/otel/internal/global/handler.go +index 2e47b29..c4b0e2a 100644 +--- a/vendor/go.opentelemetry.io/otel/internal/global/handler.go ++++ b/vendor/go.opentelemetry.io/otel/internal/global/handler.go +@@ -5,33 +5,11 @@ + package global // import "go.opentelemetry.io/otel/internal/global" + + import ( +- "log" +- "sync/atomic" ++ "go.opentelemetry.io/otel/internal/errorhandler" + ) + +-// ErrorHandler handles irremediable events. +-type ErrorHandler interface { +- // Handle handles any error deemed irremediable by an OpenTelemetry +- // component. +- Handle(error) +-} ++// ErrorHandler is an alias for errorhandler.ErrorHandler, kept for backward ++// compatibility with existing callers of internal/global. ++type ErrorHandler = errorhandler.ErrorHandler + +-type ErrDelegator struct { +- delegate atomic.Pointer[ErrorHandler] +-} +- +-// Compile-time check that delegator implements ErrorHandler. +-var _ ErrorHandler = (*ErrDelegator)(nil) +- +-func (d *ErrDelegator) Handle(err error) { +- if eh := d.delegate.Load(); eh != nil { +- (*eh).Handle(err) +- return +- } +- log.Print(err) +-} +- +-// setDelegate sets the ErrorHandler delegate. +-func (d *ErrDelegator) setDelegate(eh ErrorHandler) { +- d.delegate.Store(&eh) +-} ++type ErrDelegator = errorhandler.ErrDelegator +diff --git a/vendor/go.opentelemetry.io/otel/internal/global/state.go b/vendor/go.opentelemetry.io/otel/internal/global/state.go +index 204ea14..9768fcc 100644 +--- a/vendor/go.opentelemetry.io/otel/internal/global/state.go ++++ b/vendor/go.opentelemetry.io/otel/internal/global/state.go +@@ -11,12 +11,10 @@ import ( + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/trace" ++ "go.opentelemetry.io/otel/internal/errorhandler" + ) + + type ( +- errorHandlerHolder struct { +- eh ErrorHandler +- } + + tracerProviderHolder struct { + tp trace.TracerProvider +@@ -53,7 +51,7 @@ var ( + // Subsequent calls to SetErrorHandler after the first will not forward errors + // to the new ErrorHandler for prior returned instances. + func GetErrorHandler() ErrorHandler { +- return globalErrorHandler.Load().(errorHandlerHolder).eh ++ return errorhandler.GetErrorHandler() + } + + // SetErrorHandler sets the global ErrorHandler to h. +@@ -63,26 +61,7 @@ func GetErrorHandler() ErrorHandler { + // ErrorHandler. Subsequent calls will set the global ErrorHandler, but not + // delegate errors to h. + func SetErrorHandler(h ErrorHandler) { +- current := GetErrorHandler() +- +- if _, cOk := current.(*ErrDelegator); cOk { +- if _, ehOk := h.(*ErrDelegator); ehOk && current == h { +- // Do not assign to the delegate of the default ErrDelegator to be +- // itself. +- Error( +- errors.New("no ErrorHandler delegate configured"), +- "ErrorHandler remains its current value.", +- ) +- return +- } +- } +- +- delegateErrorHandlerOnce.Do(func() { +- if def, ok := current.(*ErrDelegator); ok { +- def.setDelegate(h) +- } +- }) +- globalErrorHandler.Store(errorHandlerHolder{eh: h}) ++ errorhandler.SetErrorHandler(h) + } + + // TracerProvider is the internal implementation for global.TracerProvider. +diff --git a/vendor/go.opentelemetry.io/otel/propagation/baggage.go b/vendor/go.opentelemetry.io/otel/propagation/baggage.go +index 0518826..82b5e1e 100644 +--- a/vendor/go.opentelemetry.io/otel/propagation/baggage.go ++++ b/vendor/go.opentelemetry.io/otel/propagation/baggage.go +@@ -7,9 +7,16 @@ import ( + "context" + + "go.opentelemetry.io/otel/baggage" ++ "go.opentelemetry.io/otel/internal/errorhandler" + ) + +-const baggageHeader = "baggage" ++const ( ++ baggageHeader = "baggage" ++ ++ // W3C Baggage specification limits. ++ // https://www.w3.org/TR/baggage/#limits ++ maxMembers = 64 ++) + + // Baggage is a propagator that supports the W3C Baggage format. + // +@@ -50,6 +57,9 @@ func extractSingleBaggage(parent context.Context, carrier TextMapCarrier) contex + + bag, err := baggage.Parse(bStr) + if err != nil { ++ errorhandler.GetErrorHandler().Handle(err) ++ } ++ if bag.Len() == 0 { + return parent + } + return baggage.ContextWithBaggage(parent, bag) +@@ -64,13 +74,22 @@ func extractMultiBaggage(parent context.Context, carrier ValuesGetter) context.C + for _, bStr := range bVals { + currBag, err := baggage.Parse(bStr) + if err != nil { ++ errorhandler.GetErrorHandler().Handle(err) ++ } ++ if currBag.Len() == 0 { + continue + } + members = append(members, currBag.Members()...) ++ if len(members) >= maxMembers { ++ break ++ } + } + + b, err := baggage.New(members...) +- if err != nil || b.Len() == 0 { ++ if err != nil { ++ errorhandler.GetErrorHandler().Handle(err) ++ } ++ if b.Len() == 0 { + return parent + } + return baggage.ContextWithBaggage(parent, b) +-- +2.45.4 + 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..77b18fc2db1 --- /dev/null +++ b/SPECS/azurelinux-image-tools/CVE-2026-39882.patch @@ -0,0 +1,154 @@ +From 0012a2de6adab7e08f815b440afc656ac7408f35 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Wed, 22 Apr 2026 20:44:11 +0000 +Subject: [PATCH] Limit HTTP response body to 4 MiB for OTLP HTTP exporters; + treat excess as non-retryable error + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/open-telemetry/opentelemetry-go/commit/5e363de517dba6db62736b2f5cdef0e0929b4cd0.patch +--- + .../otlp/otlplog/otlploghttp/client.go | 20 ++++++++++++++++-- + .../otlp/otlpmetric/otlpmetrichttp/client.go | 20 ++++++++++++++++-- + .../otlp/otlptrace/otlptracehttp/client.go | 21 +++++++++++++++++-- + 3 files changed, 55 insertions(+), 6 deletions(-) + +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..da48089 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 +@@ -26,6 +26,14 @@ import ( + "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/retry" + ) + ++// 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 ++ ++ + type client struct { + uploadLogs func(context.Context, []*logpb.ResourceLogs) error + } +@@ -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..c3e288b 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 +@@ -28,6 +28,14 @@ import ( + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" + ) + ++// 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 ++ ++ + type client struct { + // req is cloned for every upload the client makes. + req *http.Request +@@ -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..42b17c7 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 +@@ -32,7 +32,16 @@ import ( + const contentTypeProto = "application/x-protobuf" + + var gzPool = sync.Pool{ ++ ++// 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 ++ + New: func() any { ++ + w := gzip.NewWriter(io.Discard) + return w + }, +@@ -174,7 +183,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 +218,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..34537cb3dd0 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,8 @@ 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-29181.patch +Patch2: CVE-2026-39882.patch BuildRequires: golang < 1.25 BuildRequires: systemd-udev Requires: %{name}-imagecustomizer = %{version}-%{release} @@ -112,6 +114,9 @@ go test -C toolkit/tools ./... %{_bindir}/osmodifier %changelog +* Wed Apr 22 2026 Azure Linux Security Servicing Account - 1.2.0-3 +- Patch for CVE-2026-39882, CVE-2026-29181 + * Thu Mar 05 2026 Azure Linux Security Servicing Account - 1.2.0-2 - Patch for CVE-2026-27141 From daf8100f5b4a198086bbaca14b07079eb979a24f Mon Sep 17 00:00:00 2001 From: Aditya Singh Date: Thu, 23 Apr 2026 06:50:35 +0000 Subject: [PATCH 2/2] Updated patch file for CVE-2026-29181 and CVE-2026-39882 --- .../CVE-2026-29181.patch | 161 +++++++++++++----- .../CVE-2026-39882.patch | 89 +++++----- 2 files changed, 172 insertions(+), 78 deletions(-) diff --git a/SPECS/azurelinux-image-tools/CVE-2026-29181.patch b/SPECS/azurelinux-image-tools/CVE-2026-29181.patch index 34ef10dd10c..95a86c201a5 100644 --- a/SPECS/azurelinux-image-tools/CVE-2026-29181.patch +++ b/SPECS/azurelinux-image-tools/CVE-2026-29181.patch @@ -1,23 +1,55 @@ -From 1a4eac167dc32ec6868d250617153c476a1307f8 Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Wed, 22 Apr 2026 20:46:08 +0000 -Subject: [PATCH] Comply with W3C Baggage limits: update maxMembers to 64, - remove per-member byte limit; add truncation for count/size, introduce - internal errorhandler, and propagate errors during extraction. +From aa1894e09e3fe66860c7885cb40f98901b35277f Mon Sep 17 00:00:00 2001 +From: Sam Xie +Date: Sat, 28 Feb 2026 20:15:17 +0100 +Subject: [PATCH] Comply with W3C Baggage specification limits (#7880) -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/open-telemetry/opentelemetry-go/commit/aa1894e09e3fe66860c7885cb40f98901b35277f.patch +Updates the baggage implementation to comply with +https://www.w3.org/TR/baggage/#limits: + +- Changed maxMembers from 180 to 64 (the W3C compliance requirement) + + > The resulting baggage-string contains 64 list-members or less. + +- Removed maxBytesPerMembers (4096) - this per-member limit was not part +of the W3C spec +- Added limit checking in extractMultiBaggage for multiple baggage +headers: + - Checks combined byte size across all headers (max 8192 bytes) + - Checks combined member count across all headers (max 64 members) + +This uses non-deterministic truncation when handling baggage limits. + +Upstream Patch Reference: https://github.com/open-telemetry/opentelemetry-go/commit/aa1894e09e3fe66860c7885cb40f98901b35277f.patch --- - .../otel/baggage/baggage.go | 102 +++++++++++++----- - .../internal/errorhandler/errorhandler.go | 96 +++++++++++++++++ - .../otel/internal/global/handler.go | 32 +----- - .../otel/internal/global/state.go | 27 +---- - .../otel/propagation/baggage.go | 23 +++- - 5 files changed, 201 insertions(+), 79 deletions(-) + vendor/go.opentelemetry.io/otel/CHANGELOG.md | 6 + + .../otel/baggage/baggage.go | 107 ++++++++++++++---- + .../internal/errorhandler/errorhandler.go | 96 ++++++++++++++++ + .../otel/internal/global/handler.go | 34 ++---- + .../otel/internal/global/state.go | 36 +----- + .../otel/propagation/baggage.go | 24 +++- + vendor/modules.txt | 1 + + 7 files changed, 218 insertions(+), 86 deletions(-) create mode 100644 vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go +diff --git a/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/vendor/go.opentelemetry.io/otel/CHANGELOG.md +index f3abcfd..13ace7d 100644 +--- a/vendor/go.opentelemetry.io/otel/CHANGELOG.md ++++ b/vendor/go.opentelemetry.io/otel/CHANGELOG.md +@@ -8,6 +8,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm + + ## [Unreleased] + ++### Fixed ++ ++- Update `Baggage` in `go.opentelemetry.io/otel/propagation` and `Parse` and `New` in `go.opentelemetry.io/otel/baggage` to comply with W3C Baggage specification limits. ++ `New` and `Parse` now return partial baggage along with an error when limits are exceeded. ++ Errors from baggage extraction are reported to the global error handler. (#7880) ++ + + + diff --git a/vendor/go.opentelemetry.io/otel/baggage/baggage.go b/vendor/go.opentelemetry.io/otel/baggage/baggage.go -index f83a448..e6e731e 100644 +index f83a448..c8bc2e7 100644 --- a/vendor/go.opentelemetry.io/otel/baggage/baggage.go +++ b/vendor/go.opentelemetry.io/otel/baggage/baggage.go @@ -14,8 +14,7 @@ import ( @@ -60,15 +92,7 @@ index f83a448..e6e731e 100644 // It expects all the provided members to have already been validated. func New(members ...Member) (Baggage, error) { if len(members) == 0 { -@@ -441,7 +439,6 @@ func New(members ...Member) (Baggage, error) { - if !m.hasData { - return Baggage{}, errInvalidMember - } -- - // OpenTelemetry resolves duplicates by last-one-wins. - b[m.key] = baggage.Item{ - Value: m.value, -@@ -449,17 +446,42 @@ func New(members ...Member) (Baggage, error) { +@@ -449,17 +447,42 @@ func New(members ...Member) (Baggage, error) { } } @@ -117,7 +141,19 @@ index f83a448..e6e731e 100644 } // Parse attempts to decode a baggage-string from the passed string. It -@@ -475,31 +497,59 @@ func Parse(bStr string) (Baggage, error) { +@@ -470,36 +493,72 @@ func New(members ...Member) (Baggage, error) { + // defined (reading left-to-right) will be the only one kept. This diverges + // from the W3C Baggage specification which allows duplicate list-members, but + // conforms to the OpenTelemetry Baggage specification. ++// ++// If the baggage-string exceeds the maximum allowed members (64) or bytes ++// (8192), members are dropped until the limits are satisfied and an error is ++// returned along with the partial result. ++// ++// Invalid members are skipped and the error is returned along with the ++// partial result containing the valid members. + func Parse(bStr string) (Baggage, error) { + if bStr == "" { return Baggage{}, nil } @@ -159,12 +195,12 @@ index f83a448..e6e731e 100644 + } else { + // New key + newTotalBytes = totalBytes + memberBytes -+ } + } + + if newTotalBytes > maxBytesPerBaggageString { + truncateErr = errors.Join(truncateErr, errBaggageBytes) + break - } ++ } + // OpenTelemetry resolves duplicates by last-one-wins. b[m.key] = baggage.Item{ @@ -183,7 +219,7 @@ index f83a448..e6e731e 100644 + if len(b) == 0 { + return Baggage{}, truncateErr } -- + - return Baggage{b}, nil + return Baggage{b}, truncateErr } @@ -292,10 +328,10 @@ index 0000000..3f0ab31 + return v +} diff --git a/vendor/go.opentelemetry.io/otel/internal/global/handler.go b/vendor/go.opentelemetry.io/otel/internal/global/handler.go -index 2e47b29..c4b0e2a 100644 +index 2e47b29..77d0425 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/handler.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/handler.go -@@ -5,33 +5,11 @@ +@@ -5,33 +5,13 @@ package global // import "go.opentelemetry.io/otel/internal/global" import ( @@ -333,26 +369,45 @@ index 2e47b29..c4b0e2a 100644 -func (d *ErrDelegator) setDelegate(eh ErrorHandler) { - d.delegate.Store(&eh) -} ++// ErrDelegator is an alias for errorhandler.ErrDelegator, kept for backward ++// compatibility with existing callers of internal/global. +type ErrDelegator = errorhandler.ErrDelegator diff --git a/vendor/go.opentelemetry.io/otel/internal/global/state.go b/vendor/go.opentelemetry.io/otel/internal/global/state.go -index 204ea14..9768fcc 100644 +index 204ea14..225c9e5 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/state.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/state.go -@@ -11,12 +11,10 @@ import ( +@@ -8,16 +8,13 @@ import ( + "sync" + "sync/atomic" + ++ "go.opentelemetry.io/otel/internal/errorhandler" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" -+ "go.opentelemetry.io/otel/internal/errorhandler" ) type ( - errorHandlerHolder struct { - eh ErrorHandler - } - +- tracerProviderHolder struct { tp trace.TracerProvider -@@ -53,7 +51,7 @@ var ( + } +@@ -32,12 +29,10 @@ type ( + ) + + var ( +- globalErrorHandler = defaultErrorHandler() + globalTracer = defaultTracerValue() + globalPropagators = defaultPropagatorsValue() + globalMeterProvider = defaultMeterProvider() + +- delegateErrorHandlerOnce sync.Once + delegateTraceOnce sync.Once + delegateTextMapPropagatorOnce sync.Once + delegateMeterOnce sync.Once +@@ -53,7 +48,7 @@ var ( // Subsequent calls to SetErrorHandler after the first will not forward errors // to the new ErrorHandler for prior returned instances. func GetErrorHandler() ErrorHandler { @@ -361,7 +416,7 @@ index 204ea14..9768fcc 100644 } // SetErrorHandler sets the global ErrorHandler to h. -@@ -63,26 +61,7 @@ func GetErrorHandler() ErrorHandler { +@@ -63,26 +58,7 @@ func GetErrorHandler() ErrorHandler { // ErrorHandler. Subsequent calls will set the global ErrorHandler, but not // delegate errors to h. func SetErrorHandler(h ErrorHandler) { @@ -389,8 +444,21 @@ index 204ea14..9768fcc 100644 } // TracerProvider is the internal implementation for global.TracerProvider. +@@ -174,12 +150,6 @@ func SetMeterProvider(mp metric.MeterProvider) { + globalMeterProvider.Store(meterProviderHolder{mp: mp}) + } + +-func defaultErrorHandler() *atomic.Value { +- v := &atomic.Value{} +- v.Store(errorHandlerHolder{eh: &ErrDelegator{}}) +- return v +-} +- + func defaultTracerValue() *atomic.Value { + v := &atomic.Value{} + v.Store(tracerProviderHolder{tp: &tracerProvider{}}) diff --git a/vendor/go.opentelemetry.io/otel/propagation/baggage.go b/vendor/go.opentelemetry.io/otel/propagation/baggage.go -index 0518826..82b5e1e 100644 +index 0518826..2ecca3f 100644 --- a/vendor/go.opentelemetry.io/otel/propagation/baggage.go +++ b/vendor/go.opentelemetry.io/otel/propagation/baggage.go @@ -7,9 +7,16 @@ import ( @@ -421,7 +489,12 @@ index 0518826..82b5e1e 100644 return parent } return baggage.ContextWithBaggage(parent, bag) -@@ -64,13 +74,22 @@ func extractMultiBaggage(parent context.Context, carrier ValuesGetter) context.C +@@ -60,17 +70,27 @@ func extractMultiBaggage(parent context.Context, carrier ValuesGetter) context.C + if len(bVals) == 0 { + return parent + } ++ + var members []baggage.Member for _, bStr := range bVals { currBag, err := baggage.Parse(bStr) if err != nil { @@ -445,6 +518,18 @@ index 0518826..82b5e1e 100644 return parent } return baggage.ContextWithBaggage(parent, b) +diff --git a/vendor/modules.txt b/vendor/modules.txt +index 30cb8bd..51aca3d 100644 +--- a/vendor/modules.txt ++++ b/vendor/modules.txt +@@ -217,6 +217,7 @@ go.opentelemetry.io/otel/attribute/internal + go.opentelemetry.io/otel/baggage + go.opentelemetry.io/otel/codes + go.opentelemetry.io/otel/internal/baggage ++go.opentelemetry.io/otel/internal/errorhandler + go.opentelemetry.io/otel/internal/global + go.opentelemetry.io/otel/propagation + go.opentelemetry.io/otel/semconv/internal -- 2.45.4 diff --git a/SPECS/azurelinux-image-tools/CVE-2026-39882.patch b/SPECS/azurelinux-image-tools/CVE-2026-39882.patch index 77b18fc2db1..906d6a32ca2 100644 --- a/SPECS/azurelinux-image-tools/CVE-2026-39882.patch +++ b/SPECS/azurelinux-image-tools/CVE-2026-39882.patch @@ -1,24 +1,38 @@ -From 0012a2de6adab7e08f815b440afc656ac7408f35 Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Wed, 22 Apr 2026 20:44:11 +0000 -Subject: [PATCH] Limit HTTP response body to 4 MiB for OTLP HTTP exporters; - treat excess as non-retryable error +From 5e363de517dba6db62736b2f5cdef0e0929b4cd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Robert=20Paj=C4=85k?= +Date: Wed, 1 Apr 2026 11:48:05 +0200 +Subject: [PATCH] limit response body size for OTLP HTTP exporters (#8108) -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/open-telemetry/opentelemetry-go/commit/5e363de517dba6db62736b2f5cdef0e0929b4cd0.patch +Per https://github.com/open-telemetry/opentelemetry-proto/pull/781 + +Upstream Patch Reference: https://github.com/open-telemetry/opentelemetry-go/commit/5e363de517dba6db62736b2f5cdef0e0929b4cd0.patch --- - .../otlp/otlplog/otlploghttp/client.go | 20 ++++++++++++++++-- - .../otlp/otlpmetric/otlpmetrichttp/client.go | 20 ++++++++++++++++-- - .../otlp/otlptrace/otlptracehttp/client.go | 21 +++++++++++++++++-- - 3 files changed, 55 insertions(+), 6 deletions(-) + vendor/go.opentelemetry.io/otel/CHANGELOG.md | 2 ++ + .../otlp/otlplog/otlploghttp/client.go | 19 +++++++++++++++++-- + .../otlp/otlpmetric/otlpmetrichttp/client.go | 19 +++++++++++++++++-- + .../otlp/otlptrace/otlptracehttp/client.go | 19 +++++++++++++++++-- + 4 files changed, 53 insertions(+), 6 deletions(-) +diff --git a/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/vendor/go.opentelemetry.io/otel/CHANGELOG.md +index 13ace7d..e38c3c7 100644 +--- a/vendor/go.opentelemetry.io/otel/CHANGELOG.md ++++ b/vendor/go.opentelemetry.io/otel/CHANGELOG.md +@@ -14,6 +14,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm + `New` and `Parse` now return partial baggage along with an error when limits are exceeded. + Errors from baggage extraction are reported to the global error handler. (#7880) + ++- Limit HTTP response body to 4 MiB in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`, `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`, and `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` to mitigate excessive memory usage caused by a misconfigured or malicious server. Responses exceeding the limit are treated as non-retryable errors. (#8108) ++ + + + 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..da48089 100644 +index 59be105..147896b 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 -@@ -26,6 +26,14 @@ import ( - "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/retry" - ) +@@ -41,6 +41,13 @@ func newNoopClient() *client { + return &client{} + } +// 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 @@ -27,11 +41,10 @@ index 59be105..da48089 100644 +// This is a variable to allow tests to override it. +var maxResponseBodySize int64 = 4 * 1024 * 1024 + -+ - type client struct { - uploadLogs func(context.Context, []*logpb.ResourceLogs) error - } -@@ -164,7 +172,11 @@ func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs) + // newHTTPClient creates a new HTTP log client. + func newHTTPClient(cfg config) (*client, error) { + hc := cfg.httpClient +@@ -164,7 +171,11 @@ func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs) // Read the partial success message, if any. var respData bytes.Buffer @@ -44,7 +57,7 @@ index 59be105..da48089 100644 return err } if respData.Len() == 0 { -@@ -195,7 +207,11 @@ func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs) +@@ -195,7 +206,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 @@ -58,12 +71,12 @@ index 59be105..da48089 100644 } 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..c3e288b 100644 +index 26af47e..d36c0c4 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 -@@ -28,6 +28,14 @@ import ( - "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" - ) +@@ -53,6 +53,13 @@ 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 @@ -72,11 +85,10 @@ index 26af47e..c3e288b 100644 +// This is a variable to allow tests to override it. +var maxResponseBodySize int64 = 4 * 1024 * 1024 + -+ - type client struct { - // req is cloned for every upload the client makes. - req *http.Request -@@ -168,7 +176,11 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou + // newClient creates a new HTTP metric client. + func newClient(cfg oconf.Config) (*client, error) { + httpClient := cfg.Metrics.HTTPClient +@@ -168,7 +175,11 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou // Read the partial success message, if any. var respData bytes.Buffer @@ -89,7 +101,7 @@ index 26af47e..c3e288b 100644 return err } if respData.Len() == 0 { -@@ -199,7 +211,11 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou +@@ -199,7 +210,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 @@ -103,14 +115,13 @@ index 26af47e..c3e288b 100644 } 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..42b17c7 100644 +index c7b1a55..d44ea29 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 -@@ -32,7 +32,16 @@ import ( +@@ -31,6 +31,13 @@ import ( + const contentTypeProto = "application/x-protobuf" - var gzPool = sync.Pool{ -+ +// 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 @@ -118,12 +129,10 @@ index c7b1a55..42b17c7 100644 +// 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) - return w - }, -@@ -174,7 +183,11 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc +@@ -174,7 +181,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 @@ -136,7 +145,7 @@ index c7b1a55..42b17c7 100644 return err } if respData.Len() == 0 { -@@ -205,7 +218,11 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc +@@ -205,7 +216,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