Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package nng for openSUSE:Factory checked in 
at 2026-10-17 21:24:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nng (Old)
 and      /work/SRC/openSUSE:Factory/.nng.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nng"

Sat Oct 17 21:24:36 2026 rev:11 rq:1385258 version:1.12.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/nng/nng.changes  2026-09-11 18:05:15.343676677 
+0200
+++ /work/SRC/openSUSE:Factory/.nng.new.3698736/nng.changes     2026-10-17 
21:24:38.803988817 +0200
@@ -1,0 +2,20 @@
+Fri Oct 16 12:51:38 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 1.12.4 (no upstream release notes published
+  for 1.12.4; changes mined from the v1.12.2...v1.12.4 range):
+  * 1.12.3: fix a potential overflow in the HTTP chunk-size
+    parser that let a malicious server crash a client
+    (gh#nanomsg/nng#2284).
+  * 1.12.3: refuse unreasonable allocation sizes instead of
+    attempting them.
+  * 1.12.3: harden WebSocket against sender-driven
+    allocations: cap allocations and frame counts to avoid
+    quadratic compute growth from many small or empty frames.
+  * 1.12.4: reject unsafe HTTP request targets.
+  * 1.12.4: validate directory handler paths, further
+    hardening the directory serving fixed in 1.12.2.
+  * No CVE has been assigned to any of these fixes, and no
+    open VUL bug exists for nng. The ABI soversion is
+    unchanged at 1.
+
+-------------------------------------------------------------------

Old:
----
  nng-1.12.2.tar.gz

New:
----
  nng-1.12.4.tar.gz

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

Other differences:
------------------
++++++ nng.spec ++++++
--- /var/tmp/diff_new_pack.agDLB2/_old  2026-10-17 21:24:39.478016936 +0200
+++ /var/tmp/diff_new_pack.agDLB2/_new  2026-10-17 21:24:39.479016977 +0200
@@ -19,7 +19,7 @@
 
 %define sover 1
 Name:           nng
-Version:        1.12.2
+Version:        1.12.4
 Release:        0
 Summary:        Nanomsg NG - brokerless messaging
 License:        MIT

++++++ nng-1.12.2.tar.gz -> nng-1.12.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nng-1.12.2/include/nng/nng.h 
new/nng-1.12.4/include/nng/nng.h
--- old/nng-1.12.2/include/nng/nng.h    2026-08-22 22:58:48.000000000 +0200
+++ new/nng-1.12.4/include/nng/nng.h    2026-08-30 20:21:33.000000000 +0200
@@ -1,5 +1,5 @@
 //
-// Copyright 2025 Staysail Systems, Inc. <[email protected]>
+// Copyright 2026 Staysail Systems, Inc. <[email protected]>
 // Copyright 2018 Capitar IT Group BV <[email protected]>
 //
 // This software is supplied under the terms of the MIT License, a
@@ -58,7 +58,7 @@
 // may not necessarily match the ABI versions.
 #define NNG_MAJOR_VERSION 1
 #define NNG_MINOR_VERSION 12
-#define NNG_PATCH_VERSION 2
+#define NNG_PATCH_VERSION 4
 // if non-empty (i.e. "pre"), this is a pre-release
 #define NNG_RELEASE_SUFFIX ""
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nng-1.12.2/src/core/message.c 
new/nng-1.12.4/src/core/message.c
--- old/nng-1.12.2/src/core/message.c   2026-08-22 22:58:48.000000000 +0200
+++ new/nng-1.12.4/src/core/message.c   2026-08-30 20:21:33.000000000 +0200
@@ -396,6 +396,11 @@
        nni_msg *m;
        int      rv;
 
+       // Avoid overflows, and reserve the upper four bits
+       // for use by SP stream transports.
+       if ((uint64_t)sz > 0x0fffffffffffffffull) {
+               return (NNG_EMSGSIZE);
+       }
        if ((m = NNI_ALLOC_STRUCT(m)) == NULL) {
                return (NNG_ENOMEM);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nng-1.12.2/src/supplemental/http/http_chunk.c 
new/nng-1.12.4/src/supplemental/http/http_chunk.c
--- old/nng-1.12.2/src/supplemental/http/http_chunk.c   2026-08-22 
22:58:48.000000000 +0200
+++ new/nng-1.12.4/src/supplemental/http/http_chunk.c   2026-08-30 
20:21:33.000000000 +0200
@@ -44,6 +44,7 @@
 struct nng_http_chunks {
        nni_list         cl_chunks;
        size_t           cl_maxsz;
+       size_t           cl_total; // total size of all chunks
        size_t           cl_size; // parsed size (so far)
        size_t           cl_line; // bytes since last newline
        enum chunk_state cl_state;
@@ -100,12 +101,7 @@
 size_t
 nni_http_chunks_size(nni_http_chunks *cl)
 {
-       size_t          tot = 0;
-       nni_http_chunk *ch;
-       NNI_LIST_FOREACH (&cl->cl_chunks, ch) {
-               tot += ch->c_size;
-       }
-       return (tot);
+       return (cl->cl_total);
 }
 
 size_t
@@ -123,22 +119,28 @@
 static int
 chunk_ingest_len(nni_http_chunks *cl, char c)
 {
-       if (isdigit(c)) {
-               cl->cl_size *= 16;
-               cl->cl_size += (c - '0');
+       size_t digit;
+
+       if (isdigit((unsigned char) c)) {
+               digit = (size_t) (c - '0');
        } else if ((c >= 'A') && (c <= 'F')) {
-               cl->cl_size *= 16;
-               cl->cl_size += (c - 'A') + 10;
+               digit = (size_t) ((c - 'A') + 10);
        } else if ((c >= 'a') && (c <= 'f')) {
-               cl->cl_size *= 16;
-               cl->cl_size += (c - 'a') + 10;
+               digit = (size_t) ((c - 'a') + 10);
        } else if (c == ';') {
                cl->cl_state = CS_EXT;
+               return (0);
        } else if (c == '\r') {
                cl->cl_state = CS_CR;
+               return (0);
        } else {
                return (NNG_EPROTO);
        }
+       if (cl->cl_size > ((SIZE_MAX - digit) / 16)) {
+               return (NNG_EMSGSIZE);
+       }
+       cl->cl_size *= 16;
+       cl->cl_size += digit;
        return (0);
 }
 
@@ -147,7 +149,7 @@
 {
        if (c == '\r') {
                cl->cl_state = CS_CR;
-       } else if (!isprint(c)) {
+       } else if (!isprint((unsigned char) c)) {
                return (NNG_EPROTO);
        }
        return (0);
@@ -166,8 +168,11 @@
                cl->cl_state = CS_TRLR;
                return (0);
        }
-       if ((cl->cl_maxsz > 0) &&
-           ((nni_http_chunks_size(cl) + cl->cl_size) > cl->cl_maxsz)) {
+       if ((cl->cl_size > (SIZE_MAX - 2)) ||
+           (cl->cl_size > (SIZE_MAX - cl->cl_total)) ||
+           ((cl->cl_maxsz > 0) &&
+               ((cl->cl_total > cl->cl_maxsz) ||
+                   (cl->cl_size > (cl->cl_maxsz - cl->cl_total))))) {
                return (NNG_EMSGSIZE);
        }
        if ((chunk = NNI_ALLOC_STRUCT(chunk)) == NULL) {
@@ -186,6 +191,7 @@
        chunk->c_size  = cl->cl_size;
        chunk->c_alloc = cl->cl_size + 2;
        chunk->c_resid = chunk->c_alloc;
+       cl->cl_total += cl->cl_size;
        nni_list_append(&cl->cl_chunks, chunk);
 
        return (0);
@@ -198,7 +204,7 @@
                cl->cl_state = CS_TRLRCR;
                return (0);
        }
-       if (!isprint(c)) {
+       if (!isprint((unsigned char) c)) {
                return (NNG_EPROTO);
        }
        cl->cl_line++;
@@ -226,7 +232,7 @@
        int rv;
        switch (cl->cl_state) {
        case CS_INIT:
-               if (!isalnum(c)) {
+               if (!isalnum((unsigned char) c)) {
                        rv = NNG_EPROTO;
                        break;
                }
@@ -281,6 +287,7 @@
 
                if ((chunk->c_data[chunk->c_size] != '\r') ||
                    (chunk->c_data[chunk->c_size + 1] != '\n')) {
+                       *lenp = n;
                        return (NNG_EPROTO);
                }
                chunk->c_resid = 0;
@@ -315,8 +322,10 @@
                        break;
 
                case CS_DATA:
-                       if ((rv = chunk_ingest_data(cl, src + i, n - i, &cnt)) 
!=
-                           0) {
+                       cnt = 0;
+                       if ((rv = chunk_ingest_data(
+                                cl, src + i, n - i, &cnt)) != 0) {
+                               *lenp = i + cnt;
                                return (rv);
                        }
                        i += cnt;
@@ -326,6 +335,7 @@
                        // All others character by character parse through
                        // the state machine grinder.
                        if ((rv = chunk_ingest_char(cl, src[i])) != 0) {
+                               *lenp = i;
                                return (rv);
                        }
                        i++;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nng-1.12.2/src/supplemental/http/http_msg.c 
new/nng-1.12.4/src/supplemental/http/http_msg.c
--- old/nng-1.12.2/src/supplemental/http/http_msg.c     2026-08-22 
22:58:48.000000000 +0200
+++ new/nng-1.12.4/src/supplemental/http/http_msg.c     2026-08-30 
20:21:33.000000000 +0200
@@ -785,6 +785,14 @@
        *version = '\0';
        version++;
 
+       // A request-target cannot contain a fragment or a backslash.  Fragments
+       // are only meaningful in URI references, and a backslash can become a
+       // directory separator on Windows.  Reject them here rather than 
allowing
+       // a file handler to interpret them as part of a local path.
+       if ((strchr(uri, '#') != NULL) || (strchr(uri, '\\') != NULL)) {
+               return (NNG_EPROTO);
+       }
+
        if ((rv = nni_url_canonify_uri(&canon_uri, uri)) != 0) {
                return (rv);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nng-1.12.2/src/supplemental/http/http_msg_test.c 
new/nng-1.12.4/src/supplemental/http/http_msg_test.c
--- old/nng-1.12.2/src/supplemental/http/http_msg_test.c        2026-08-22 
22:58:48.000000000 +0200
+++ new/nng-1.12.4/src/supplemental/http/http_msg_test.c        2026-08-30 
20:21:33.000000000 +0200
@@ -20,6 +20,8 @@
        char          plain[] = "GET /../../outside.txt HTTP/1.1\r\n\r\n";
        char          encoded[] =
            "GET /%2e%2e/%2E%2e/outside.txt HTTP/1.1\r\n\r\n";
+       char fragment[] = "GET /#/../../outside.txt HTTP/1.1\r\n\r\n";
+       char backslash[] = "GET /..\\..\\outside.txt HTTP/1.1\r\n\r\n";
        size_t        len;
 
        NUTS_PASS(nni_http_req_alloc(&req, NULL));
@@ -31,9 +33,47 @@
        NUTS_PASS(nni_http_req_parse(req, encoded, strlen(encoded), &len));
        NUTS_MATCH(nni_http_req_get_uri(req), "/outside.txt");
        nni_http_req_free(req);
+
+       NUTS_PASS(nni_http_req_alloc(&req, NULL));
+       NUTS_FAIL(nni_http_req_parse(req, fragment, strlen(fragment), &len),
+           NNG_EPROTO);
+       nni_http_req_free(req);
+
+       NUTS_PASS(nni_http_req_alloc(&req, NULL));
+       NUTS_FAIL(nni_http_req_parse(req, backslash, strlen(backslash), &len),
+           NNG_EPROTO);
+       nni_http_req_free(req);
+}
+
+static void
+test_http_chunk_size_overflow(void)
+{
+       nni_http_chunks *chunks = NULL;
+       char             body[] = "10000000000000000\r\n";
+       size_t           len    = 0;
+
+       NUTS_PASS(nni_http_chunks_init(&chunks, 0));
+       NUTS_FAIL(nni_http_chunks_parse(chunks, body, strlen(body), &len),
+           NNG_EMSGSIZE);
+       nni_http_chunks_free(chunks);
+}
+
+static void
+test_http_chunk_alloc_overflow(void)
+{
+       nni_http_chunks *chunks = NULL;
+       char             body[] = "ffffffffffffffff\r\n";
+       size_t           len    = 0;
+
+       NUTS_PASS(nni_http_chunks_init(&chunks, 0));
+       NUTS_FAIL(nni_http_chunks_parse(chunks, body, strlen(body), &len),
+           NNG_EMSGSIZE);
+       nni_http_chunks_free(chunks);
 }
 
 NUTS_TESTS = {
        { "http request URI canonicalization", test_http_req_canonify_uri },
+       { "http chunk size overflow", test_http_chunk_size_overflow },
+       { "http chunk allocation overflow", test_http_chunk_alloc_overflow },
        { NULL, NULL },
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nng-1.12.2/src/supplemental/http/http_server.c 
new/nng-1.12.4/src/supplemental/http/http_server.c
--- old/nng-1.12.2/src/supplemental/http/http_server.c  2026-08-22 
22:58:48.000000000 +0200
+++ new/nng-1.12.4/src/supplemental/http/http_server.c  2026-08-30 
20:21:33.000000000 +0200
@@ -1547,6 +1547,22 @@
                return;
        }
 
+       // The request parser rejects these characters, but check again before
+       // building a filesystem path in case a request reaches this handler by
+       // another route.  A fragment is not part of an HTTP request-target, 
and a
+       // backslash is a directory separator on Windows.
+       if ((strchr(uri + len, '#') != NULL) ||
+           (strchr(uri + len, '\\') != NULL)) {
+               if ((rv = nni_http_res_alloc_error(
+                        &res, NNG_HTTP_STATUS_BAD_REQUEST)) != 0) {
+                       nni_aio_finish_error(aio, rv);
+                       return;
+               }
+               nni_aio_set_output(aio, 0, res);
+               nni_aio_finish(aio, 0, 0);
+               return;
+       }
+
        // simple worst case is every character in path is a separator
        // It's never actually that bad, because we we have /<something>/.
        pnsz = (strlen(path) + strlen(uri) + 2) * strlen(NNG_PLATFORM_DIR_SEP);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nng-1.12.2/src/supplemental/websocket/websocket.c 
new/nng-1.12.4/src/supplemental/websocket/websocket.c
--- old/nng-1.12.2/src/supplemental/websocket/websocket.c       2026-08-22 
22:58:48.000000000 +0200
+++ new/nng-1.12.4/src/supplemental/websocket/websocket.c       2026-08-30 
20:21:33.000000000 +0200
@@ -32,6 +32,10 @@
 #define WS_DEF_MAXRXFRAME (1U << 20) // 1MB Frame size (recv)
 #define WS_DEF_MAXTXFRAME (1U << 16) // 64KB Frame size (send)
 
+#ifndef WS_DEF_MAXFRAMES
+#define WS_DEF_MAXFRAMES (1 << 12) // 4K frames in a single message
+#endif
+
 // Alias for checking the prefix of a string.
 #define startswith(s, t) (strncmp(s, t, strlen(t)) == 0)
 
@@ -62,6 +66,8 @@
        nni_list         recvq;
        nni_list         txq;
        nni_list         rxq;
+       int              rxq_len;
+       size_t           rxq_size;
        ws_frame        *txframe;
        ws_frame        *rxframe;
        nni_aio         *txaio; // physical aios
@@ -947,17 +953,31 @@
 static void
 ws_read_frame_cb(nni_ws *ws, ws_frame *frame)
 {
+       bool message_done = false;
+
        switch (frame->op) {
        case WS_CONT:
                if (!ws->inmsg) {
                        ws_close(ws, WS_CLOSE_PROTOCOL_ERR);
                        return;
                }
+               if (ws->rxq_len >= WS_DEF_MAXFRAMES) {
+                       ws_close(ws, WS_CLOSE_TOO_BIG);
+                       return;
+               }
                if (frame->final) {
                        ws->inmsg = false;
+                       message_done = true;
                }
                ws->rxframe = NULL;
-               nni_list_append(&ws->rxq, frame);
+               if (frame->len == 0) {
+                       // drop empty middle frames
+                       ws_frame_fini(frame);
+               } else {
+                       nni_list_append(&ws->rxq, frame);
+                       ws->rxq_len++;
+                       ws->rxq_size += frame->len;
+               }
                break;
        case WS_TEXT:
                if (!ws->recv_text) {
@@ -972,8 +992,13 @@
                }
                if (!frame->final) {
                        ws->inmsg = true;
+               } else {
+                       message_done = true;
                }
                ws->rxframe = NULL;
+               ws->rxq_size = frame->len;
+               ws->rxq_len++;
+               NNI_ASSERT(ws->rxq_len == 1);
                nni_list_append(&ws->rxq, frame);
                break;
 
@@ -1010,6 +1035,10 @@
                return;
        }
 
+       if (message_done) {
+               ws->rxq_len  = 0;
+               ws->rxq_size = 0;
+       }
        ws_read_finish(ws);
 }
 
@@ -1101,12 +1130,7 @@
                // length of the message has not exceeded our recvmax.
                // (Protect against an infinite stream of small messages!)
                if ((!ws->isstream) && (ws->recvmax > 0)) {
-                       size_t    totlen = frame->len;
-                       ws_frame *fr2;
-                       NNI_LIST_FOREACH (&ws->rxq, fr2) {
-                               totlen += fr2->len;
-                       }
-                       if (totlen > ws->recvmax) {
+                       if (ws->rxq_size + frame->len > ws->recvmax)  {
                                ws_close(ws, WS_CLOSE_TOO_BIG);
                                nni_mtx_unlock(&ws->mtx);
                                return;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nng-1.12.2/src/supplemental/websocket/websocket_test.c 
new/nng-1.12.4/src/supplemental/websocket/websocket_test.c
--- old/nng-1.12.2/src/supplemental/websocket/websocket_test.c  2026-08-22 
22:58:48.000000000 +0200
+++ new/nng-1.12.4/src/supplemental/websocket/websocket_test.c  2026-08-30 
20:21:33.000000000 +0200
@@ -13,6 +13,8 @@
 
 #include <nuts.h>
 
+#define WS_OPT_MSGMODE "ws:msgmode"
+
 void
 test_websocket_wildcard(void)
 {
@@ -340,6 +342,108 @@
        nng_stream_dialer_free(d);
 }
 
+void
+test_websocket_frame_limit(void)
+{
+       nng_stream_listener *l = NULL;
+       nng_stream_dialer   *d = NULL;
+       nng_stream          *c = NULL;
+       nng_stream          *s = NULL;
+       nng_aio             *daio = NULL;
+       nng_aio             *laio = NULL;
+       nng_aio             *raio = NULL;
+       nng_aio             *saio = NULL;
+       nng_msg             *msg;
+       char                 url[64];
+       uint16_t             port;
+       const size_t         maxframes = 1U << 12;
+       int                  rv;
+
+       NUTS_PASS(nng_aio_alloc(&daio, NULL, NULL));
+       NUTS_PASS(nng_aio_alloc(&laio, NULL, NULL));
+       NUTS_PASS(nng_aio_alloc(&raio, NULL, NULL));
+       NUTS_PASS(nng_aio_alloc(&saio, NULL, NULL));
+       nng_aio_set_timeout(daio, 5000);
+       nng_aio_set_timeout(laio, 5000);
+       nng_aio_set_timeout(raio, 5000);
+       nng_aio_set_timeout(saio, 5000);
+
+       for (int i = 0; i < 256; i++) {
+               port = nuts_next_port();
+               (void) snprintf(
+                   url, sizeof(url), "ws://127.0.0.1:%d/test", port);
+               NUTS_PASS(nng_stream_listener_alloc(&l, url));
+               NUTS_PASS(nng_stream_dialer_alloc(&d, url));
+               NUTS_PASS(nng_stream_listener_set_bool(
+                   l, WS_OPT_MSGMODE, true));
+               NUTS_PASS(nng_stream_dialer_set_bool(
+                   d, WS_OPT_MSGMODE, true));
+               NUTS_PASS(nng_stream_listener_set_size(
+                   l, NNG_OPT_WS_SENDMAXFRAME, 1));
+               rv = nng_stream_listener_listen(l);
+               if (rv != NNG_EADDRINUSE) {
+                       break;
+               }
+               nng_stream_listener_free(l);
+               nng_stream_dialer_free(d);
+       }
+       NUTS_PASS(rv);
+
+       nng_stream_listener_accept(l, laio);
+       nng_stream_dialer_dial(d, daio);
+       nng_aio_wait(laio);
+       nng_aio_wait(daio);
+       NUTS_PASS(nng_aio_result(laio));
+       NUTS_PASS(nng_aio_result(daio));
+       s = nng_aio_get_output(laio, 0);
+       c = nng_aio_get_output(daio, 0);
+
+       // Two messages at the limit must be accepted.  Receiving the first
+       // one verifies that the accounting is reset before receiving the next.
+       for (int i = 0; i < 2; i++) {
+               NUTS_PASS(nng_msg_alloc(&msg, maxframes));
+               memset(nng_msg_body(msg), 'A' + i, maxframes);
+               nng_aio_set_msg(saio, msg);
+               nng_stream_recv(c, raio);
+               nng_stream_send(s, saio);
+               nng_aio_wait(saio);
+               nng_aio_wait(raio);
+               NUTS_PASS(nng_aio_result(saio));
+               NUTS_PASS(nng_aio_result(raio));
+               msg = nng_aio_get_msg(raio);
+               NUTS_TRUE(nng_msg_len(msg) == maxframes);
+               nng_aio_set_msg(raio, NULL);
+               nng_msg_free(msg);
+       }
+
+       // One more fragment than the limit must close the receiver.
+       NUTS_PASS(nng_msg_alloc(&msg, maxframes + 1));
+       memset(nng_msg_body(msg), 'X', maxframes + 1);
+       nng_aio_set_msg(saio, msg);
+       nng_stream_recv(c, raio);
+       nng_stream_send(s, saio);
+       nng_aio_wait(raio);
+       NUTS_FAIL(nng_aio_result(raio), NNG_ECLOSED);
+       nng_aio_wait(saio);
+       NUTS_TRUE((nng_aio_result(saio) == 0) ||
+           (nng_aio_result(saio) == NNG_ECLOSED));
+       if ((msg = nng_aio_get_msg(saio)) != NULL) {
+               nng_aio_set_msg(saio, NULL);
+               nng_msg_free(msg);
+       }
+
+       nng_stream_close(c);
+       nng_stream_free(c);
+       nng_stream_close(s);
+       nng_stream_free(s);
+       nng_aio_free(saio);
+       nng_aio_free(raio);
+       nng_aio_free(laio);
+       nng_aio_free(daio);
+       nng_stream_listener_free(l);
+       nng_stream_dialer_free(d);
+}
+
 typedef struct recv_state {
        nng_stream  *c;
        int          total;
@@ -515,5 +619,6 @@
        { "websocket conn properties", test_websocket_conn_props },
        { "websocket fragmentation", test_websocket_fragmentation },
        { "websocket text mode", test_websocket_text_mode },
+       { "websocket frame limit", test_websocket_frame_limit },
        { NULL, NULL },
 };

Reply via email to