Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rabbitmq-c for openSUSE:Factory 
checked in at 2026-09-28 10:43:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rabbitmq-c (Old)
 and      /work/SRC/openSUSE:Factory/.rabbitmq-c.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rabbitmq-c"

Mon Sep 28 10:43:24 2026 rev:15 rq:1380684 version:0.18.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/rabbitmq-c/rabbitmq-c.changes    2026-08-28 
19:51:02.148638642 +0200
+++ /work/SRC/openSUSE:Factory/.rabbitmq-c.new.383539/rabbitmq-c.changes        
2026-09-28 10:43:28.216455991 +0200
@@ -1,0 +2,14 @@
+Fri Sep 25 12:42:53 UTC 2026 - Petr Gajdos <[email protected]> + gemini
+
+- Update to 0.18.0:
+  * Security:
+    - Fix client-side memory-exhaustion DoS in amqp_handle_input
+      (GHSA-5fp7-wg2f-hhgp, #899)
+  * Fixed:
+    - amqp_login/amqp_login_with_properties return an error instead
+      of crashing on NULL SASL credentials for
+      AMQP_SASL_METHOD_PLAIN; NULL and "" are now accepted for the
+      AMQP_SASL_METHOD_EXTERNAL identity argument (#898, #900)
+    - Fix pkgconfig bindings on Windows (#897)
+
+-------------------------------------------------------------------

Old:
----
  rabbitmq-c-0.17.0.tar.gz

New:
----
  rabbitmq-c-0.18.0.tar.gz

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

Other differences:
------------------
++++++ rabbitmq-c.spec ++++++
--- /var/tmp/diff_new_pack.YJXiYu/_old  2026-09-28 10:43:29.062491420 +0200
+++ /var/tmp/diff_new_pack.YJXiYu/_new  2026-09-28 10:43:29.064491504 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package rabbitmq-c
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 # Copyright (c) 2012-2015 Remi Collet
 #
 # All modifications and additions to the file contributed by third parties
@@ -20,7 +20,7 @@
 %global libname     librabbitmq
 %global majsonum    4
 Name:           rabbitmq-c
-Version:        0.17.0
+Version:        0.18.0
 Release:        0
 Summary:        Client library for AMQP
 License:        MIT
@@ -28,7 +28,7 @@
 Source0:        
https://github.com/alanxz/rabbitmq-c/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
 # [bsc#1232541], https://github.com/alanxz/rabbitmq-c/issues/846
 Patch0:         rabbitmq-c-default-cacert-location.patch
-BuildRequires:  cmake > 2.8.12
+BuildRequires:  cmake >= 3.22
 BuildRequires:  gcc
 BuildRequires:  openssl-devel
 BuildRequires:  pkgconfig

++++++ rabbitmq-c-0.17.0.tar.gz -> rabbitmq-c-0.18.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rabbitmq-c-0.17.0/CMakeLists.txt 
new/rabbitmq-c-0.18.0/CMakeLists.txt
--- old/rabbitmq-c-0.17.0/CMakeLists.txt        2026-07-02 05:45:59.000000000 
+0200
+++ new/rabbitmq-c-0.18.0/CMakeLists.txt        2026-09-15 02:07:49.000000000 
+0200
@@ -14,7 +14,7 @@
 # 4. If any interfaces have been removed since the last public release, then 
set age to 0.
 
 set(RMQ_SOVERSION_CURRENT   11)
-set(RMQ_SOVERSION_REVISION  2)
+set(RMQ_SOVERSION_REVISION  3)
 set(RMQ_SOVERSION_AGE       7)
 
 include(VersionFunctions)
@@ -207,7 +207,9 @@
 foreach (lib ${SOCKET_LIBRARIES})
     set(libs_private "${libs_private} -l${lib}")
 endforeach(lib)
-set(libs_private "${libs_private} -l${LIBRT}")
+if(LIBRT)
+  set(libs_private "${libs_private} -l${LIBRT}")
+endif()
 if (ENABLE_SSL_SUPPORT)
   set(libs_private "${libs_private} -lssl -lcrypto ${CMAKE_THREAD_LIBS_INIT}")
 endif()
@@ -218,6 +220,15 @@
 cmake_path(APPEND includedir "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
 
 configure_file(cmake/config.h.in 
${CMAKE_CURRENT_BINARY_DIR}/librabbitmq/config.h)
+
+set(RMQ_LIBRARY_NAME rabbitmq)
+if(WIN32)
+  if(BUILD_SHARED_LIBS)
+    set(RMQ_LIBRARY_NAME "rabbitmq.${RMQ_SOVERSION}")
+  else()
+    set(RMQ_LIBRARY_NAME "librabbitmq.${RMQ_SOVERSION}")
+  endif()
+endif()
 configure_file(librabbitmq.pc.in ${CMAKE_CURRENT_BINARY_DIR}/librabbitmq.pc 
@ONLY)
 
 include(CMakePackageConfigHelpers)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rabbitmq-c-0.17.0/ChangeLog.md 
new/rabbitmq-c-0.18.0/ChangeLog.md
--- old/rabbitmq-c-0.17.0/ChangeLog.md  2026-07-02 05:45:59.000000000 +0200
+++ new/rabbitmq-c-0.18.0/ChangeLog.md  2026-09-15 02:07:49.000000000 +0200
@@ -1,4 +1,13 @@
 # Change Log
+## v0.18.0 - 2026-09-14
+
+### Security
+- Fix client-side memory-exhaustion DoS in `amqp_handle_input` 
(GHSA-5fp7-wg2f-hhgp, #899)
+
+### Fixed
+- `amqp_login`/`amqp_login_with_properties` return an error instead of 
crashing on `NULL` SASL credentials for `AMQP_SASL_METHOD_PLAIN`; `NULL` and 
`""` are now accepted for the `AMQP_SASL_METHOD_EXTERNAL` identity argument 
(#898, #900)
+- Fix pkgconfig bindings on Windows (#897)
+
 ## v0.17.0 - 2026-07-01
 
 ### Security
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rabbitmq-c-0.17.0/include/rabbitmq-c/amqp.h 
new/rabbitmq-c-0.18.0/include/rabbitmq-c/amqp.h
--- old/rabbitmq-c-0.17.0/include/rabbitmq-c/amqp.h     2026-07-02 
05:45:59.000000000 +0200
+++ new/rabbitmq-c-0.18.0/include/rabbitmq-c/amqp.h     2026-09-15 
02:07:49.000000000 +0200
@@ -118,7 +118,7 @@
  */
 
 #define AMQP_VERSION_MAJOR 0
-#define AMQP_VERSION_MINOR 17
+#define AMQP_VERSION_MINOR 18
 #define AMQP_VERSION_PATCH 0
 #define AMQP_VERSION_IS_RELEASE 1
 
@@ -1693,8 +1693,13 @@
  *                 should be followed by two arguments in this order:
  *                 const char* username, and const char* password.
  *              -  AMQP_SASL_METHOD_EXTERNAL, the AMQP_SASL_METHOD_EXTERNAL
- *                 argument should be followed one argument:
- *                 const char* identity.
+ *                 argument must be followed by one argument:
+ *                 const char* identity. NULL and an empty string ("") are
+ *                 both accepted and are equivalent: they indicate the
+ *                 caller has no authorization identity to send, and the
+ *                 broker should rely on the identity established by the
+ *                 underlying transport (e.g. the TLS client certificate).
+ *                 See RFC 4422 Appendix A.
  * \return amqp_rpc_reply_t indicating success or failure.
  *  - r.reply_type == AMQP_RESPONSE_NORMAL. Login completed successfully
  *  - r.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION. In most cases errors
@@ -1759,8 +1764,13 @@
  *                should be followed by two arguments in this order:
  *                const char* username, and const char* password.
  *             -  AMQP_SASL_METHOD_EXTERNAL, the AMQP_SASL_METHOD_EXTERNAL
- *                argument should be followed one argument:
- *                const char* identity.
+ *                argument must be followed by one argument:
+ *                const char* identity. NULL and an empty string ("") are
+ *                both accepted and are equivalent: they indicate the
+ *                caller has no authorization identity to send, and the
+ *                broker should rely on the identity established by the
+ *                underlying transport (e.g. the TLS client certificate).
+ *                See RFC 4422 Appendix A.
  * \return amqp_rpc_reply_t indicating success or failure.
  *  - r.reply_type == AMQP_RESPONSE_NORMAL. Login completed successfully
  *  - r.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION. In most cases errors
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rabbitmq-c-0.17.0/librabbitmq/amqp_connection.c 
new/rabbitmq-c-0.18.0/librabbitmq/amqp_connection.c
--- old/rabbitmq-c-0.17.0/librabbitmq/amqp_connection.c 2026-07-02 
05:45:59.000000000 +0200
+++ new/rabbitmq-c-0.18.0/librabbitmq/amqp_connection.c 2026-09-15 
02:07:49.000000000 +0200
@@ -263,6 +263,16 @@
 
       channel = amqp_d16(amqp_offset(raw_frame, 1));
 
+      /* channel_max == 0 means no explicit limit, AMQP sets this as 65535. */
+      {
+        amqp_channel_t max_channel = (0 != state->channel_max)
+                                         ? (amqp_channel_t)state->channel_max
+                                         : (amqp_channel_t)UINT16_MAX;
+        if (channel > max_channel) {
+          return AMQP_STATUS_BAD_AMQP_DATA;
+        }
+      }
+
       /* frame length is 3 bytes in */
       frame_size = amqp_d32(amqp_offset(raw_frame, 3));
       /* To prevent the target_size calculation below from overflowing, check
@@ -384,12 +394,15 @@
           break;
 
         case AMQP_FRAME_HEARTBEAT:
+          /* Heartbeat frames must be sent on the connection channel. */
+          if (0 != decoded_frame->channel) {
+            return AMQP_STATUS_BAD_AMQP_DATA;
+          }
           break;
 
         default:
-          /* Ignore the frame */
-          decoded_frame->frame_type = 0;
-          break;
+          /* Unrecognized frame type: this is a framing error per AMQP spec. */
+          return AMQP_STATUS_BAD_AMQP_DATA;
       }
 
       return_to_idle(state);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rabbitmq-c-0.17.0/librabbitmq/amqp_socket.c 
new/rabbitmq-c-0.18.0/librabbitmq/amqp_socket.c
--- old/rabbitmq-c-0.17.0/librabbitmq/amqp_socket.c     2026-07-02 
05:45:59.000000000 +0200
+++ new/rabbitmq-c-0.18.0/librabbitmq/amqp_socket.c     2026-09-15 
02:07:49.000000000 +0200
@@ -569,23 +569,34 @@
 }
 
 static amqp_bytes_t sasl_response(amqp_pool_t *pool,
-                                  amqp_sasl_method_enum method, va_list args) {
-  amqp_bytes_t response;
+                                  amqp_sasl_method_enum method, va_list args,
+                                  int *status) {
+  amqp_bytes_t response = amqp_empty_bytes;
+
+  *status = AMQP_STATUS_OK;
 
   switch (method) {
     case AMQP_SASL_METHOD_PLAIN: {
       char *username = va_arg(args, char *);
-      size_t username_len = strlen(username);
       char *password = va_arg(args, char *);
-      size_t password_len = strlen(password);
+      size_t username_len;
+      size_t password_len;
       char *response_buf;
 
-      amqp_pool_alloc_bytes(pool, strlen(username) + strlen(password) + 2,
-                            &response);
+      if (username == NULL || password == NULL) {
+        *status = AMQP_STATUS_INVALID_PARAMETER;
+        return response;
+      }
+
+      username_len = strlen(username);
+      password_len = strlen(password);
+
+      amqp_pool_alloc_bytes(pool, username_len + password_len + 2, &response);
       if (response.bytes == NULL)
       /* We never request a zero-length block, because of the +2
          above, so a NULL here really is ENOMEM. */
       {
+        *status = AMQP_STATUS_NO_MEMORY;
         return response;
       }
 
@@ -598,10 +609,27 @@
     }
     case AMQP_SASL_METHOD_EXTERNAL: {
       char *identity = va_arg(args, char *);
-      size_t identity_len = strlen(identity);
+      size_t identity_len;
+
+      /* NULL is treated the same as an empty identity: the caller has no
+         authorization identity to send and the broker should rely on the
+         identity established by the underlying transport (e.g. the TLS
+         client certificate). See RFC 4422 Appendix A. */
+      if (identity == NULL) {
+        identity = "";
+      }
+
+      identity_len = strlen(identity);
+      if (identity_len == 0) {
+        /* response is already amqp_empty_bytes; amqp_pool_alloc_bytes()
+           would return NULL for a zero-length request, which is
+           indistinguishable from ENOMEM, so skip the allocation entirely. */
+        break;
+      }
 
       amqp_pool_alloc_bytes(pool, identity_len, &response);
       if (response.bytes == NULL) {
+        *status = AMQP_STATUS_NO_MEMORY;
         return response;
       }
 
@@ -1291,9 +1319,12 @@
       goto error_res;
     }
 
-    response_bytes = sasl_response(channel_pool, sasl_method, vl);
-    if (response_bytes.bytes == NULL) {
-      res = AMQP_STATUS_NO_MEMORY;
+    response_bytes = sasl_response(channel_pool, sasl_method, vl, &res);
+    if (AMQP_STATUS_OK != res) {
+      /* Note: response_bytes.bytes == NULL is not itself an error here: a
+         zero-length response (e.g. AMQP_SASL_METHOD_EXTERNAL with an empty
+         identity) is a valid, successful result. sasl_response() reports
+         real allocation failures via res. */
       goto error_res;
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rabbitmq-c-0.17.0/librabbitmq.pc.in 
new/rabbitmq-c-0.18.0/librabbitmq.pc.in
--- old/rabbitmq-c-0.17.0/librabbitmq.pc.in     2026-07-02 05:45:59.000000000 
+0200
+++ new/rabbitmq-c-0.18.0/librabbitmq.pc.in     2026-09-15 02:07:49.000000000 
+0200
@@ -8,6 +8,6 @@
 Version: @RMQ_VERSION@
 URL: https://github.com/alanxz/rabbitmq-c
 Requires.private: @requires_private@
-Libs: -L${libdir} -lrabbitmq
+Libs: -L${libdir} -l@RMQ_LIBRARY_NAME@
 Libs.private: @libs_private@
 Cflags: -I${includedir}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rabbitmq-c-0.17.0/tests/CMakeLists.txt 
new/rabbitmq-c-0.18.0/tests/CMakeLists.txt
--- old/rabbitmq-c-0.17.0/tests/CMakeLists.txt  2026-07-02 05:45:59.000000000 
+0200
+++ new/rabbitmq-c-0.18.0/tests/CMakeLists.txt  2026-09-15 02:07:49.000000000 
+0200
@@ -52,3 +52,7 @@
 add_executable(test_decode_bytes test_decode_bytes.c)
 target_link_libraries(test_decode_bytes rabbitmq-static)
 add_test(decode_bytes test_decode_bytes)
+
+add_executable(test_handle_input_frame_validation 
test_handle_input_frame_validation.c)
+target_link_libraries(test_handle_input_frame_validation rabbitmq-static)
+add_test(handle_input_frame_validation test_handle_input_frame_validation)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/rabbitmq-c-0.17.0/tests/test_handle_input_frame_validation.c 
new/rabbitmq-c-0.18.0/tests/test_handle_input_frame_validation.c
--- old/rabbitmq-c-0.17.0/tests/test_handle_input_frame_validation.c    
1970-01-01 01:00:00.000000000 +0100
+++ new/rabbitmq-c-0.18.0/tests/test_handle_input_frame_validation.c    
2026-09-15 02:07:49.000000000 +0200
@@ -0,0 +1,185 @@
+// Copyright 2007 - 2021, Alan Antonuk and the rabbitmq-c contributors.
+// SPDX-License-Identifier: mit
+
+/* Regression test for a client-side memory-exhaustion DoS: frames on
+ * channels beyond channel_max, or with an unrecognized frame type, were
+ * accepted instead of rejected, letting a peer grow per-channel pool
+ * memory without bound. */
+
+#include "amqp_private.h"
+#include <rabbitmq-c/amqp.h>
+#include <rabbitmq-c/framing.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static amqp_connection_state_t new_ready_state(int channel_max, int frame_max) 
{
+  amqp_connection_state_t state = amqp_new_connection();
+  if (state == NULL) {
+    fprintf(stderr, "amqp_new_connection failed\n");
+    abort();
+  }
+
+  /* Mirrors the private return_to_idle() helper, so amqp_handle_input()
+   * parses an ordinary frame instead of expecting a protocol header. */
+  state->inbound_buffer.bytes = state->header_buffer;
+  state->inbound_buffer.len = sizeof(state->header_buffer);
+  state->inbound_offset = 0;
+  state->target_size = HEADER_SIZE;
+  state->state = CONNECTION_STATE_IDLE;
+  state->channel_max = channel_max;
+  state->frame_max = frame_max;
+
+  return state;
+}
+
+/* Builds a minimal frame: header (type, channel, size) + empty payload +
+ * frame-end footer. */
+static size_t build_empty_frame(uint8_t *buf, uint8_t frame_type,
+                                uint16_t channel) {
+  buf[0] = frame_type;
+  amqp_e16(channel, buf + 1);
+  amqp_e32(0, buf + 3);
+  buf[7] = AMQP_FRAME_END;
+  return 8;
+}
+
+static void test_channel_exceeding_channel_max_rejected(void) {
+  amqp_connection_state_t state = new_ready_state(1, AMQP_FRAME_MIN_SIZE);
+  amqp_frame_t frame;
+  amqp_bytes_t data;
+  uint8_t buf[8];
+  int res;
+
+  data.len = build_empty_frame(buf, 0xff, 2);
+  data.bytes = buf;
+
+  res = amqp_handle_input(state, data, &frame);
+  if (res != AMQP_STATUS_BAD_AMQP_DATA) {
+    fprintf(stderr,
+            "expected AMQP_STATUS_BAD_AMQP_DATA (%d) for channel > "
+            "channel_max, got %d\n",
+            AMQP_STATUS_BAD_AMQP_DATA, res);
+    abort();
+  }
+
+  if (amqp_get_channel_pool(state, 2) != NULL) {
+    fprintf(stderr,
+            "channel pool was created for a channel beyond channel_max\n");
+    abort();
+  }
+
+  amqp_destroy_connection(state);
+}
+
+/* channel_max == 0 means no explicit limit, which per spec caps channels
+ * at 65535 rather than leaving them unbounded. */
+static void test_channel_max_zero_means_protocol_max(void) {
+  amqp_connection_state_t state = new_ready_state(0, AMQP_FRAME_MIN_SIZE);
+  amqp_frame_t frame;
+  amqp_bytes_t data;
+  uint8_t buf[8];
+  int res;
+
+  data.len = build_empty_frame(buf, AMQP_FRAME_BODY, 65535);
+  data.bytes = buf;
+
+  res = amqp_handle_input(state, data, &frame);
+  if (res != (int)data.len) {
+    fprintf(stderr, "expected frame to be consumed (%d), got %d\n",
+            (int)data.len, res);
+    abort();
+  }
+  if (frame.frame_type != AMQP_FRAME_BODY || frame.channel != 65535) {
+    fprintf(stderr, "expected a body frame on channel 65535 to be accepted\n");
+    abort();
+  }
+
+  amqp_destroy_connection(state);
+}
+
+static void test_heartbeat_on_nonzero_channel_rejected(void) {
+  amqp_connection_state_t state = new_ready_state(0, AMQP_FRAME_MIN_SIZE);
+  amqp_frame_t frame;
+  amqp_bytes_t data;
+  uint8_t buf[8];
+  int res;
+
+  data.len = build_empty_frame(buf, AMQP_FRAME_HEARTBEAT, 1);
+  data.bytes = buf;
+
+  res = amqp_handle_input(state, data, &frame);
+  if (res != AMQP_STATUS_BAD_AMQP_DATA) {
+    fprintf(stderr,
+            "expected AMQP_STATUS_BAD_AMQP_DATA (%d) for heartbeat on "
+            "non-zero channel, got %d\n",
+            AMQP_STATUS_BAD_AMQP_DATA, res);
+    abort();
+  }
+
+  amqp_destroy_connection(state);
+}
+
+static void test_unknown_frame_type_rejected(void) {
+  amqp_connection_state_t state = new_ready_state(1, AMQP_FRAME_MIN_SIZE);
+  amqp_frame_t frame;
+  amqp_bytes_t data;
+  uint8_t buf[8];
+  int res;
+
+  data.len = build_empty_frame(buf, 0xff, 1);
+  data.bytes = buf;
+
+  res = amqp_handle_input(state, data, &frame);
+  if (res != AMQP_STATUS_BAD_AMQP_DATA) {
+    fprintf(stderr,
+            "expected AMQP_STATUS_BAD_AMQP_DATA (%d) for an unrecognized "
+            "frame type, got %d\n",
+            AMQP_STATUS_BAD_AMQP_DATA, res);
+    abort();
+  }
+
+  amqp_destroy_connection(state);
+}
+
+/* Unlike test_unknown_frame_type_rejected, also checks that no pool memory
+ * accumulates before the rejection. */
+static void test_unknown_frame_type_stream_rejected_immediately(void) {
+  amqp_connection_state_t state = new_ready_state(1, AMQP_FRAME_MIN_SIZE);
+  amqp_pool_t *pool;
+  amqp_frame_t frame;
+  amqp_bytes_t data;
+  uint8_t buf[8];
+  int res;
+
+  data.len = build_empty_frame(buf, 0xff, 1);
+  data.bytes = buf;
+
+  res = amqp_handle_input(state, data, &frame);
+  if (res != AMQP_STATUS_BAD_AMQP_DATA) {
+    fprintf(stderr,
+            "expected the first unrecognized frame to be rejected "
+            "immediately, got %d\n",
+            res);
+    abort();
+  }
+
+  pool = amqp_get_channel_pool(state, 1);
+  if (pool != NULL && pool->pages.num_blocks > 1) {
+    fprintf(stderr,
+            "channel pool grew to %d pages after a single rejected frame\n",
+            pool->pages.num_blocks);
+    abort();
+  }
+
+  amqp_destroy_connection(state);
+}
+
+int main(void) {
+  test_channel_exceeding_channel_max_rejected();
+  test_channel_max_zero_means_protocol_max();
+  test_heartbeat_on_nonzero_channel_rejected();
+  test_unknown_frame_type_rejected();
+  test_unknown_frame_type_stream_rejected_immediately();
+  return 0;
+}

Reply via email to