]> git.seodisparate.com - UDPConnection/commitdiff
Fix potential memory corruption bug
authorStephen Seo <seo.disparate@gmail.com>
Wed, 21 Jun 2023 04:23:26 +0000 (13:23 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 21 Jun 2023 04:23:26 +0000 (13:23 +0900)
UDPC_atostr(...) uses a uint32_t as an offset into a buffer inside the
UDPC Context such that there can be at most 32 different addr-strings.
The call is thread-safe, up to a point (at most 32 concurrent calls will
return correct strings). The problem was that the offset was not being
reset to 0 and was always being incremented by 40. Should the offset
overflow, the offset into the buffer will be "mis-aligned" such that the
32nd offset into the buffer can possibly overwrite memory past the
buffer's end if the addr string is long enough.

The fix is to use a mutex instead of an atomic uint32_t to lock a
code-block that will always prevent overflow (using modulus operator).

I think the speed-loss is negligable (using a lock instead of an atomic
uint32_t) since it isn't expected for programs using UDPC to use
UDPC_atostr(...) very frequently.

src/UDPC_Defines.hpp
src/UDPConnection.cpp

index 46d036fd747f8c8bc105ef72cd46b35aee192030..c506fafc8a749f1dacde85c0bfdf16ddc85e375f 100644 (file)
@@ -230,7 +230,6 @@ public:
     std::atomic_uint_fast8_t loggingType;
     // See UDPC_AuthPolicy enum in UDPC.h for possible values
     std::atomic_uint_fast8_t authPolicy;
-    std::atomic_uint32_t atostrBufIndex;
     char atostrBuf[UDPC_ATOSTR_SIZE];
 
     UDPC_SOCKETTYPE socketHandle;
@@ -267,6 +266,9 @@ public:
     unsigned char pk[crypto_sign_PUBLICKEYBYTES];
     std::atomic_bool keysSet;
 
+    std::mutex atostrBufIndexMutex;
+    std::uint32_t atostrBufIndex;
+
 }; // struct Context
 
 Context *verifyContext(UDPC_HContext ctx);
index 8f9e32728314e0937cf5026d4f93964d8ea75a23..5de1052a3e46901b027f802b9be04f6c7165d5a7 100644 (file)
@@ -223,12 +223,12 @@ loggingType(UDPC_DEBUG),
 #else
 loggingType(UDPC_WARNING),
 #endif
-atostrBufIndex(0),
 receivedPkts(),
 cSendPkts(),
 rng_engine(),
 conMapMutex(),
-peerPKWhitelistMutex()
+peerPKWhitelistMutex(),
+atostrBufIndex(0)
 {
     std::memset(atostrBuf, 0, UDPC_ATOSTR_SIZE);
 
@@ -2633,8 +2633,13 @@ const char *UDPC_atostr(UDPC_HContext ctx, UDPC_IPV6_ADDR_TYPE addr) {
     if(!c) {
         return nullptr;
     }
-    const uint32_t headIndex =
-        c->atostrBufIndex.fetch_add(UDPC_ATOSTR_BUFSIZE) % UDPC_ATOSTR_SIZE;
+    uint32_t headIndex;
+    {
+        // Use a lock to ensure that "atostrBufIndex" is always a valid value.
+        std::lock_guard<std::mutex> indexLock(c->atostrBufIndexMutex);
+        c->atostrBufIndex = (c->atostrBufIndex + UDPC_ATOSTR_BUFSIZE) % UDPC_ATOSTR_SIZE;
+        headIndex = c->atostrBufIndex;
+    }
     uint32_t index = headIndex;
     bool usedDouble = false;