From 34c316267c5746b7b667a10bd907dc92b693f6a2 Mon Sep 17 00:00:00 2001 From: Adrian Coveney Date: Tue, 18 Aug 2026 12:04:34 +0100 Subject: [PATCH] Fix handling of corrupted msgs to avoid crash This adds handling of non-ASCII message bodies, which usually indicate a corrupted message, so that the message can be written out to the reject queue and avoid the receiver crashing. The altered code has been moved within the try...except (IOError, OSError) so that the new dirq add() is protected. Also add a unit test to cover the new code. --- ssm/ssm2.py | 21 +++++++++++++++++---- test/test_ssm.py | 2 ++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ssm/ssm2.py b/ssm/ssm2.py index 1bbdeffa..3d5b9d2f 100644 --- a/ssm/ssm2.py +++ b/ssm/ssm2.py @@ -322,11 +322,24 @@ def _handle_msg(self, text): def _save_msg_to_queue(self, body, empaid): """Extract message contents and add to the accept or reject queue.""" - if isinstance(body, bytes): - body = body.decode('ascii') - - extracted_msg, signer, err_msg = self._handle_msg(body) try: + if isinstance(body, bytes): + try: + body = body.decode('ascii') + except UnicodeDecodeError: + err_msg = "Non-ASCII or corrupted message" + log.warning("Message rejected: %s", err_msg) + # Extract the message body replacing malformed data with backslashed + # escape sequence (hexadecimal form of byte value with format \xhh). + body = body.decode('ascii', errors='backslashreplace') + name = self._rejectq.add({'body': body, + 'signer': 'Not available.', + 'empaid': empaid, + 'error': err_msg}) + log.info("Message saved to reject queue as %s", name) + return # Return early to skip the rest of the method. + + extracted_msg, signer, err_msg = self._handle_msg(body) # If the message is empty or the error message is not empty # then reject the message. if extracted_msg is None or err_msg is not None: diff --git a/test/test_ssm.py b/test/test_ssm.py index 5f96fd78..65b02416 100644 --- a/test/test_ssm.py +++ b/test/test_ssm.py @@ -92,6 +92,8 @@ def test_on_message(self): test_ssm.on_message({'empa-id': 'ping'}, 'body') # Check that msg with ID and no real content doesn't raise exception. test_ssm.on_message({'empa-id': '012345'}, 'body') + # Check that non-ASCII messages don't crash the receiver. + test_ssm.on_message({'empa-id': '543210'}, '^LagelosÄü'.encode('utf-8')) def test_init_expired_cert(self): """Test right exception is thrown creating an SSM with expired cert."""