This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-site.git


The following commit(s) were added to refs/heads/master by this push:
     new 273732fc7 Added a warning regarding the serialization impact with the 
newer versions. Added some documentation about the TLS inernal handling
273732fc7 is described below

commit 273732fc795b4a2050dcb51174ca26735a02114a
Author: emmanuel lecharny <[email protected]>
AuthorDate: Tue Sep 15 09:46:59 2026 +0200

    Added a warning regarding the serialization impact with the newer versions. 
Added some documentation about the TLS inernal handling
---
 source/mina-project/__index.md                     |  12 +-
 .../technical-documentation/ssl-tls-internal.md    | 171 ++++++++++++++++++++-
 2 files changed, 181 insertions(+), 2 deletions(-)

diff --git a/source/mina-project/__index.md b/source/mina-project/__index.md
index 2e3312724..0a736b3d9 100644
--- a/source/mina-project/__index.md
+++ b/source/mina-project/__index.md
@@ -18,7 +18,17 @@ Apache MINA is often called:
 
 However, it's much more than that.  Please take a look around the list of the 
*[features](features.html)* that enable rapid network application development, 
and *[what people says about MINA](testimonials.html)*.  
 
-Please grab yourself a *[2.0.x download](downloads_2_0.html)* or a *[2.1.x 
download](downloads_2_1.html)*, try our *[Quick Start 
Guide](quick-start-guide.html)*, surf our *[FAQ](faq.html)* or start join us on 
*[our community](../contact.html)*
+Please grab yourself a *[2.1.x download](downloads_2_2.html)*, a *[2.1.x 
download](downloads_2_1.html)* or a *[2.0.x download](downloads_2_0.html)*, try 
our *[Quick Start Guide](quick-start-guide.html)*, surf our *[FAQ](faq.html)* 
or start join us on *[our community](../contact.html)*
+
+## WARNING
+
+The fix for **CVE-2026-47065** changed the form **MINA** writes for serialized 
objects exchanged through _IoBuffer.putObject_ / _getObject_ and 
_ObjectSerializationCodecFactory_: after the class name, the full standard 
**Java** serialization class descriptor is now written. 
+
+Streams produced by **2.2.7**, **2.1.12** or **2.0.28** and earlier cannot be 
read by **2.2.8**, **2.1.13** or **2.0.29** and later, and streams produced by 
the newer releases cannot be read by the older ones. 
+
+Arrays, primitives and non-Serializable classes are unaffected. 
+
+Upgrades across this boundary fail with a _BufferDataException_ wrapping an 
_EOFException_ or a _StreamCorruptedException_, and payloads persisted before 
the upgrade become unreadable after it.
 
 <div class="news">
     {{< grabpage "mina-project/news.md" >}}
diff --git a/source/mina-project/technical-documentation/ssl-tls-internal.md 
b/source/mina-project/technical-documentation/ssl-tls-internal.md
index 3fac1c4cf..864c34435 100644
--- a/source/mina-project/technical-documentation/ssl-tls-internal.md
+++ b/source/mina-project/technical-documentation/ssl-tls-internal.md
@@ -112,7 +112,7 @@ Most of the time, records will be smaller (and the packet 
size is stored in the
 
 Now, considering the very nature of **TCP**, we may receive a TLS record in 
small chunks, or more than one TLS record in a packet of data. We have to deal 
with both cases.
 
-We will use an internal pending buffer that will contain the incoming data 
until they can be fully processed. The important point is that the *SslEngine* 
class is using *ByteBuffer* to get things done, though a set of methods:
+We will use an internal pending buffer that will contain the incoming data 
until they can be fully processed. The important point is that the *SslEngine* 
class is using *ByteBuffer* to get things done, through a set of methods:
 
 * _wrap(ByteBuffer src, [int offset, int length,] ByteBuffer dst)_: Encrypt 
the data from the source buffer into the destination buffer
 * _unwrap(ByteBuffer src, [int offset, int length,] ByteBuffer dst)_: Decrypt 
the data from the source buffer into the destination buffer
@@ -134,6 +134,175 @@ The following schema shows that we are switching from an 
incoming _IoBuffer_ to
                                                                       
+----------------+
 ```
 
+Also note that we receive data by chunks (starting with a 1024 buffer), which 
may not be decodable. And this is problematic froma performance piont of vue: 
Imagine we are going to receive a block of 55Kb of data, it won't fit on a 
single TLS packet. We will need 4 TLS packets to contain all the data. And we 
start by reading a 1024 bytes buffer...
+
+Here is how MINA will proceed:
+* Read 1024 bytes in the incoming buffer
+* Allocate a buffer capable of storing the size defined in the TLS packet
+* Try to decode it (it will fail)
+* So free the destination buffer
+* Resize the incoming buffer, increasing its size to hold 2048 more bytes
+* Try to read 2048 bytes (we now have 3072 bytes in the buffer)
+* Allocate a buffer capable of storing the size defined in the TLS packet
+* Try to decode it (it will fail again...)
+* So free the destination buffer
+* Resize the incoming buffer, adding 4096 bytes into it
+* Repeat reading 4096 bytes stored in the 3072 + 4096 sized buffer (7168 bytes)
+* Allocate a buffer capable of storing the size defined in the TLS packet
+* Try to decode it (it will still fail...): The TLS packet contains 16384 - 
padding bytes of data.
+* So free the destination buffer
+* Resize again the incoming buffer, adding 8192 bytes
+* Read 8192 bytes leading to a incoming buffer containing 15360 bytes
+* Allocate a buffer capable of storing the size defined in the TLS packet
+* Which won't be decoded either
+* So free the destination buffer
+* Resize the incoming buffer, adding 16384 bytes, leading to a 31744 bytes 
buffer
+* Read 16384 bytes of data
+* Allocate a buffer capable of storing the size defined in the TLS packet
+* And now the decoding could work!
+* Copy the decoded buffer into a buffer that will be send to the IoHandler
+* Free the decoing buffer
+* and as we have some remaining data in the incoming buffer,
+* Allocate a buffer capable of storing the size defined in the TLS packet
+* Try to decode it (and it will fail...)
+* Free the buffer
+* etc etc until we have read and processed all the data.
+
+Here is how it translates in method calls:
+
+```
+AbstractPollingIoProcessor.read
+  IoBuffer.allocate(1024)
+  ...
+    SslFilter.messageReceived
+      SslHandler.receive
+        receive_start
+          resume_decode_buffer
+            mDecodedBuffer <- message
+          receive_loop
+            dest <- allocate(ZERO)
+            SslEngine.unwrap() -> BUFFER_OVERFLOW
+            dest free
+          suspend_decode_buffer
+        throw_pending_error
+        forward_writes
+        forward_received
+        forward_events
+  IoBuffer.allocate(2048)
+  ...
+    SslFilter.messageReceived
+      SslHandler.receive
+        receive_start
+          resume_decode_buffer
+            mDecodedBuffer.expand -> 3072
+            source free
+          receive_loop
+            dest <- allocate(ZERO)
+            SslEngine.unwrap() -> BUFFER_OVERFLOW
+            dest free
+          suspend_decode_buffer
+        throw_pending_error
+        forward_writes
+        forward_received
+        forward_events
+  IoBuffer.allocate(4096)
+  ...
+    SslFilter.messageReceived
+      SslHandler.receive
+        receive_start
+          resume_decode_buffer
+            mDecodedBuffer.expand -> 7168
+            source free
+          receive_loop
+            dest <- allocate(ZERO)
+            SslEngine.unwrap() -> BUFFER_OVERFLOW
+            dest free
+          suspend_decode_buffer
+        throw_pending_error
+        forward_writes
+        forward_received
+        forward_events
+  IoBuffer.allocate(8192)
+  ...
+    SslFilter.messageReceived
+      SslHandler.receive
+        receive_start
+          resume_decode_buffer
+            mDecodedBuffer.expand -> 15360
+            source free
+          receive_loop
+            dest <- allocate(ZERO)
+            SslEngine.unwrap() -> BUFFER_OVERFLOW
+            dest free
+          suspend_decode_buffer
+        throw_pending_error
+        forward_writes
+        forward_received
+        forward_events
+  IoBuffer.allocate(16384)
+  ...
+    SslFilter.messageReceived
+      SslHandler.receive
+        receive_start
+          resume_decode_buffer
+            mDecodedBuffer.expand -> 31744
+            source free
+          receive_loop
+            dest <- allocate(16400)
+            SslEngine.unwrap() -> OK
+            mReceiveQueue <- dest (16367 useful data, 33 padding removed)
+            receive_loop
+              dest <- allocate(ZERO)
+              SslEngine.unwrap() -> BUFFER_OVERFLOW
+              dest free
+          suspend_decode_buffer
+        throw_pending_error
+        forward_writes
+        forward_received
+          next.messageReceived -> We are propagating the first chunk of data 
to the IoHandler
+        forward_events
+```
+
+As we can see, the mDecodedBuffer has been expended 4 times, so is the session 
receiving buffer, and we have allocated 5 destination buffer (although four 
have been allocated with a 0 size).
+
+To schematize, here are the allocated (or resized) buffers:
+
+```
+input     mDecodedBuffer
++----+    +----+
+|1024| -> |1024|
++----+    +----+
+
++--------+    +----+--------+
+|  2048  | -> |1024|  2048  | 3072
++--------+    +----+--------+
+
++------------+    +----+--------+------------+
+|    4096    | -> |1024|  2048  |    4096    | 7168
++------------+    +----+--------+------------+
+
++----------------+    +----+--------+------------+----------------+
+|      8192      | -> |1024|  2048  |    4096    |      8192      | 15360
++----------------+    +----+--------+------------+----------------+
+
++--------------------+    
+----+--------+------------+----------------+--------------------+
+|        16384       | -> |1024|  2048  |    4096    |      8192      |        
16384       | 31744
++--------------------+    
+----+--------+------------+----------------+--------------------+
+                           ^                                             ^     
           ^
+                           |                                             |     
           |
+                           +----- First chunk of data, 16367 bytes ------+-- 
some more  --+
+```
+
+
+As we can see it's a VERY costly process, where we allocate *many* buffers 
that get discardd immediately. There is a lot of room for improvement!
+
+We can decide to use a bigger input buffer. By default, it's sized to 1Kb in 
order to avoid using a lot of memory, and it's fine when we only receive small 
chunk of data. For big data exchanges, it would be valuable to define a bigger 
size.
+The key here is that there is an adaptative mechanism where we double the size 
of the input buffer if the read data fulfilled it (uo to a limit), and divide 
it by two if we read less than what the buffer could contain. This adaptative 
mechanism is fine when we don't know the size of the receivd data, ad if it can 
vary a lot. When the incoming data are stable, we will oscillate between two 
sizes (doubling the buffer size, then divide it by two) which is a huge penalty 
to pay.
+
+Regarding the mDecoderBuffer, it's the same thing: until we can successfully 
decode it its size will increase. As a TLS record is always maxing to 16384 
bytes, it would be a better idea to allocate a buffer this size and use it, 
when we know we will be able to decode it (ie when the input bufffer is bigger 
than the TLS data size, plus some margin, because of the padding bytes).
+
+All in all, when in TLS mode, the proper strategy would be to use a 16Kb + 
padding input buffer, and same thing for the mDecodedBuffer, when we have 
received enough data. 
+
 #### Receiving small chunks
 
 In the case we receive a **TLS** record split in several packets, we won't be 
able to uncrypt them until we have received a full **TLS** record.

Reply via email to