Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package amazon-cloudwatch-agent for 
openSUSE:Factory checked in at 2026-03-25 21:21:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/amazon-cloudwatch-agent (Old)
 and      /work/SRC/openSUSE:Factory/.amazon-cloudwatch-agent.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "amazon-cloudwatch-agent"

Wed Mar 25 21:21:50 2026 rev:2 rq:1342498 version:1.300064.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/amazon-cloudwatch-agent/amazon-cloudwatch-agent.changes
  2026-03-02 17:41:58.499447694 +0100
+++ 
/work/SRC/openSUSE:Factory/.amazon-cloudwatch-agent.new.8177/amazon-cloudwatch-agent.changes
        2026-03-27 06:35:49.676151096 +0100
@@ -1,0 +2,6 @@
+Wed Mar 25 08:25:36 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Add CVE-2026-33186.patch to fix authorization bypass in grpc-go due to 
improper
+  validation of the HTTP/2 :path pseudo-header (bsc#1260314, CVE-2026-33186)
+
+-------------------------------------------------------------------

New:
----
  CVE-2026-33186.patch

----------(New B)----------
  New:
- Add CVE-2026-33186.patch to fix authorization bypass in grpc-go due to 
improper
  validation of the HTTP/2 :path pseudo-header (bsc#1260314, CVE-2026-33186)
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ amazon-cloudwatch-agent.spec ++++++
--- /var/tmp/diff_new_pack.QVuqPc/_old  2026-03-27 06:35:50.512185554 +0100
+++ /var/tmp/diff_new_pack.QVuqPc/_new  2026-03-27 06:35:50.516185719 +0100
@@ -31,6 +31,8 @@
 URL:            https://github.com/aws/amazon-cloudwatch-agent
 Source0:        %{repo}-%{version}.tar.gz
 Source1:        vendor.tar.gz
+# PATCH-FIX-UPSTREAM - grpc: enforce strict path checking for incoming 
requests on the server
+Patch0:         CVE-2026-33186.patch
 BuildRequires:  go >= 1.23.6
 BuildRequires:  golang-packaging
 ExcludeArch:    %{arm} %{ix86}
@@ -45,6 +47,9 @@
 %prep
 %setup -q -n %{repo}-%{version}
 %setup -q -D -T -a 1 -n %{repo}-%{version}
+pushd vendor/google.golang.org/grpc
+%patch -P0 -p1
+popd
 
 %build
 %goprep %{import_path}

++++++ CVE-2026-33186.patch ++++++
>From 89d1a70cc1b25ec820344760ab9aed24ef81cb26 Mon Sep 17 00:00:00 2001
From: Easwar Swaminathan <[email protected]>
Date: Tue, 17 Mar 2026 16:35:32 -0700
Subject: [PATCH] grpc: enforce strict path checking for incoming requests on
 the server (#8985)

RELEASE NOTES:
* server: fix an authorization bypass where malformed :path headers
(missing the leading slash) could bypass path-based restricted "deny"
rules in interceptors like `grpc/authz`. Any request with a
non-canonical path is now immediately rejected with an `Unimplemented`
error.
---
 internal/envconfig/envconfig.go |  16 +++
 server.go                       |  57 +++++++---
 test/malformed_method_test.go   | 177 ++++++++++++++++++++++++++++++++
 3 files changed, 234 insertions(+), 16 deletions(-)
 create mode 100644 test/malformed_method_test.go

diff --git a/internal/envconfig/envconfig.go b/internal/envconfig/envconfig.go
index cc5713fd..ea7cdd97 100644
--- a/internal/envconfig/envconfig.go
+++ b/internal/envconfig/envconfig.go
@@ -69,6 +69,22 @@ var (
        // to gRFC A76. It can be enabled by setting the environment variable
        // "GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY" to "true".
        RingHashSetRequestHashKey = 
boolFromEnv("GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY", false)
+
+       // DisableStrictPathChecking indicates whether strict path checking is
+       // disabled. This feature can be disabled by setting the environment
+       // variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to "true".
+       //
+       // When strict path checking is enabled, gRPC will reject requests with
+       // paths that do not conform to the gRPC over HTTP/2 specification 
found at
+       // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md.
+       //
+       // When disabled, gRPC will allow paths that do not contain a leading 
slash.
+       // Enabling strict path checking is recommended for security reasons, 
as it
+       // prevents potential path traversal vulnerabilities.
+       //
+       // A future release will remove this environment variable, enabling 
strict
+       // path checking behavior unconditionally.
+       DisableStrictPathChecking = 
boolFromEnv("GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING", false)
 )
 
 func boolFromEnv(envVar string, def bool) bool {
diff --git a/server.go b/server.go
index 976e70ae..e62d3532 100644
--- a/server.go
+++ b/server.go
@@ -42,6 +42,7 @@ import (
        "google.golang.org/grpc/internal"
        "google.golang.org/grpc/internal/binarylog"
        "google.golang.org/grpc/internal/channelz"
+       "google.golang.org/grpc/internal/envconfig"
        "google.golang.org/grpc/internal/grpcsync"
        "google.golang.org/grpc/internal/grpcutil"
        istats "google.golang.org/grpc/internal/stats"
@@ -148,6 +149,8 @@ type Server struct {
 
        serverWorkerChannel      chan func()
        serverWorkerChannelClose func()
+
+       strictPathCheckingLogEmitted atomic.Bool
 }
 
 type serverOptions struct {
@@ -1745,6 +1748,24 @@ func (s *Server) processStreamingRPC(ctx 
context.Context, stream *transport.Serv
        return ss.s.WriteStatus(statusOK)
 }
 
+func (s *Server) handleMalformedMethodName(stream *transport.ServerStream, ti 
*traceInfo) {
+       if ti != nil {
+               ti.tr.LazyLog(&fmtStringer{"Malformed method name %q", 
[]any{stream.Method()}}, true)
+               ti.tr.SetError()
+       }
+       errDesc := fmt.Sprintf("malformed method name: %q", stream.Method())
+       if err := stream.WriteStatus(status.New(codes.Unimplemented, errDesc)); 
err != nil {
+               if ti != nil {
+                       ti.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
+                       ti.tr.SetError()
+               }
+               channelz.Warningf(logger, s.channelz, "grpc: 
Server.handleStream failed to write status: %v", err)
+       }
+       if ti != nil {
+               ti.tr.Finish()
+       }
+}
+
 func (s *Server) handleStream(t transport.ServerTransport, stream 
*transport.ServerStream) {
        ctx := stream.Context()
        ctx = contextWithServer(ctx, s)
@@ -1765,26 +1786,30 @@ func (s *Server) handleStream(t 
transport.ServerTransport, stream *transport.Ser
        }
 
        sm := stream.Method()
-       if sm != "" && sm[0] == '/' {
+       if sm == "" {
+               s.handleMalformedMethodName(stream, ti)
+               return
+       }
+       if sm[0] != '/' {
+               // TODO(easwars): Add a link to the CVE in the below log 
messages once
+               // published.
+               if envconfig.DisableStrictPathChecking {
+                       if old := s.strictPathCheckingLogEmitted.Swap(true); 
!old {
+                               channelz.Warningf(logger, s.channelz, "grpc: 
Server.handleStream received malformed method name %q. Allowing it because the 
environment variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING is set 
to true, but this option will be removed in a future release.", sm)
+                       }
+               } else {
+                       if old := s.strictPathCheckingLogEmitted.Swap(true); 
!old {
+                               channelz.Warningf(logger, s.channelz, "grpc: 
Server.handleStream rejected malformed method name %q. To temporarily allow 
such requests, set the environment variable 
GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to true. Note that this is 
not recommended as it may allow requests to bypass security policies.", sm)
+                       }
+                       s.handleMalformedMethodName(stream, ti)
+                       return
+               }
+       } else {
                sm = sm[1:]
        }
        pos := strings.LastIndex(sm, "/")
        if pos == -1 {
-               if ti != nil {
-                       ti.tr.LazyLog(&fmtStringer{"Malformed method name %q", 
[]any{sm}}, true)
-                       ti.tr.SetError()
-               }
-               errDesc := fmt.Sprintf("malformed method name: %q", 
stream.Method())
-               if err := stream.WriteStatus(status.New(codes.Unimplemented, 
errDesc)); err != nil {
-                       if ti != nil {
-                               ti.tr.LazyLog(&fmtStringer{"%v", []any{err}}, 
true)
-                               ti.tr.SetError()
-                       }
-                       channelz.Warningf(logger, s.channelz, "grpc: 
Server.handleStream failed to write status: %v", err)
-               }
-               if ti != nil {
-                       ti.tr.Finish()
-               }
+               s.handleMalformedMethodName(stream, ti)
                return
        }
        service := sm[:pos]
diff --git a/test/malformed_method_test.go b/test/malformed_method_test.go
new file mode 100644
index 00000000..00e391a2
--- /dev/null
+++ b/test/malformed_method_test.go
@@ -0,0 +1,177 @@
+/*
+ *
+ * Copyright 2026 gRPC authors.
+ *
+ * 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.
+ *
+ */
+
+package test
+
+import (
+       "bytes"
+       "context"
+       "net"
+       "testing"
+
+       "golang.org/x/net/http2"
+       "golang.org/x/net/http2/hpack"
+       "google.golang.org/grpc/internal/envconfig"
+       "google.golang.org/grpc/internal/stubserver"
+       "google.golang.org/grpc/internal/testutils"
+
+       testpb "google.golang.org/grpc/interop/grpc_testing"
+)
+
+// TestMalformedMethodPath tests that the server responds with Unimplemented
+// when the method path is malformed. This verifies that the server does not
+// route requests with a malformed method path to the application handler.
+func (s) TestMalformedMethodPath(t *testing.T) {
+       tests := []struct {
+               name       string
+               path       string
+               envVar     bool
+               wantStatus string // string representation of codes.Code
+       }{
+               {
+                       name:       
"missing_leading_slash_disableStrictPathChecking_false",
+                       path:       "grpc.testing.TestService/UnaryCall",
+                       wantStatus: "12", // Unimplemented
+               },
+               {
+                       name:       
"empty_path_disableStrictPathChecking_false",
+                       path:       "",
+                       wantStatus: "12", // Unimplemented
+               },
+               {
+                       name:       
"just_slash_disableStrictPathChecking_false",
+                       path:       "/",
+                       wantStatus: "12", // Unimplemented
+               },
+               {
+                       name:       
"missing_leading_slash_disableStrictPathChecking_true",
+                       path:       "grpc.testing.TestService/UnaryCall",
+                       envVar:     true,
+                       wantStatus: "0", // OK
+               },
+               {
+                       name:       "empty_path_disableStrictPathChecking_true",
+                       path:       "",
+                       envVar:     true,
+                       wantStatus: "12", // Unimplemented
+               },
+               {
+                       name:       "just_slash_disableStrictPathChecking_true",
+                       path:       "/",
+                       envVar:     true,
+                       wantStatus: "12", // Unimplemented
+               },
+       }
+
+       for _, tc := range tests {
+               t.Run(tc.name, func(t *testing.T) {
+                       ctx, cancel := 
context.WithTimeout(context.Background(), defaultTestTimeout)
+                       defer cancel()
+
+                       testutils.SetEnvConfig(t, 
&envconfig.DisableStrictPathChecking, tc.envVar)
+
+                       ss := &stubserver.StubServer{
+                               UnaryCallF: func(context.Context, 
*testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
+                                       return &testpb.SimpleResponse{Payload: 
&testpb.Payload{Body: []byte("pwned")}}, nil
+                               },
+                       }
+                       if err := ss.Start(nil); err != nil {
+                               t.Fatalf("Error starting endpoint server: %v", 
err)
+                       }
+                       defer ss.Stop()
+
+                       // Open a raw TCP connection to the server and speak 
HTTP/2 directly.
+                       tcpConn, err := net.Dial("tcp", ss.Address)
+                       if err != nil {
+                               t.Fatalf("Failed to dial tcp: %v", err)
+                       }
+                       defer tcpConn.Close()
+
+                       // Write the HTTP/2 connection preface and the initial 
settings frame.
+                       if _, err := tcpConn.Write([]byte("PRI * 
HTTP/2.0\r\n\r\nSM\r\n\r\n")); err != nil {
+                               t.Fatalf("Failed to write preface: %v", err)
+                       }
+                       framer := http2.NewFramer(tcpConn, tcpConn)
+                       if err := framer.WriteSettings(); err != nil {
+                               t.Fatalf("Failed to write settings: %v", err)
+                       }
+
+                       // Encode and write the HEADERS frame.
+                       var headerBuf bytes.Buffer
+                       enc := hpack.NewEncoder(&headerBuf)
+                       writeHeader := func(name, value string) {
+                               enc.WriteField(hpack.HeaderField{Name: name, 
Value: value})
+                       }
+                       writeHeader(":method", "POST")
+                       writeHeader(":scheme", "http")
+                       writeHeader(":authority", ss.Address)
+                       writeHeader(":path", tc.path)
+                       writeHeader("content-type", "application/grpc")
+                       writeHeader("te", "trailers")
+                       if err := framer.WriteHeaders(http2.HeadersFrameParam{
+                               StreamID:      1,
+                               BlockFragment: headerBuf.Bytes(),
+                               EndStream:     false,
+                               EndHeaders:    true,
+                       }); err != nil {
+                               t.Fatalf("Failed to write headers: %v", err)
+                       }
+
+                       // Send a small gRPC-encoded data frame (0 length).
+                       if err := framer.WriteData(1, true, []byte{0, 0, 0, 0, 
0}); err != nil {
+                               t.Fatalf("Failed to write data: %v", err)
+                       }
+
+                       // Read responses and look for grpc-status.
+                       gotStatus := ""
+                       dec := hpack.NewDecoder(4096, func(f hpack.HeaderField) 
{
+                               if f.Name == "grpc-status" {
+                                       gotStatus = f.Value
+                               }
+                       })
+                       done := make(chan struct{})
+                       go func() {
+                               defer close(done)
+                               for {
+                                       frame, err := framer.ReadFrame()
+                                       if err != nil {
+                                               return
+                                       }
+                                       if headers, ok := 
frame.(*http2.HeadersFrame); ok {
+                                               if _, err := 
dec.Write(headers.HeaderBlockFragment()); err != nil {
+                                                       return
+                                               }
+                                               if headers.StreamEnded() {
+                                                       return
+                                               }
+                                       }
+                               }
+                       }()
+
+                       select {
+                       case <-done:
+                       case <-ctx.Done():
+                               t.Fatalf("Timed out waiting for response")
+                       }
+
+                       if gotStatus != tc.wantStatus {
+                               t.Errorf("Got grpc-status %v, want %v", 
gotStatus, tc.wantStatus)
+                       }
+               })
+       }
+}
-- 
2.53.0

Reply via email to