CVE-2021-41690: Missing Release of Memory after Effective Lifetime (CWE-401)
value: DCMTK through 3.6.6 does not handle memory free properly. The malloced memory for storing all file information are recorded in a global variable LST and are not freed properly. Sending specific requests to the dcmqrdb program can incur a memory leak. An attacker can use it to launch a DoS attack.
CWE description: The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory.
CVSS v3 base score: 7.5
Published: 2022-06-28T13:15Z
Repository: https://github.com/DCMTK/dcmtk
Language: C++
Files changed: dcmnet/include/dcmtk/dcmnet/dulstruc.h, dcmnet/include/dcmtk/dcmnet/helpers.h, dcmnet/libsrc/CMakeLists.txt, dcmnet/libsrc/Makefile.in, dcmnet/libsrc/assoc.cc, dcmnet/libsrc/dcuserid.cc, dcmnet/libsrc/dul.cc, dcmnet/libsrc/dulconst.cc, dcmnet/libsrc/dulextra.cc, dcmnet/libsrc/dulfsm.cc, dcmnet/libsrc/dulparse.cc, dcmnet/libsrc/dulpres.cc, dcmnet/libsrc/helpers.cc
Commit date: 2021-10-02 00:36:16 +0200
Commit message: Fixed poss. NULL pointer dereference/double free.

Thanks to Jinsheng Ba <bajinsheng@u.nus.edu> for the report and some patches.

Diff: diff --git a/dcmnet/libsrc/dulstruc.h b/dcmnet/include/dcmtk/dcmnet/dulstruc.h
similarity index 98%
rename from dcmnet/libsrc/dulstruc.h
rename to dcmnet/include/dcmtk/dcmnet/dulstruc.h
index 22da6ece1..6ac9a8f5d 100644
--- a/dcmnet/libsrc/dulstruc.h
+++ b/dcmnet/include/dcmtk/dcmnet/dulstruc.h
@@ -69,10 +69,15 @@
 #define DULSTRUC_H
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 #include "dcmtk/dcmnet/extneg.h"
 #include "dcmtk/dcmnet/dcuserid.h"
+#include "dcmtk/dcmnet/dicom.h"
+#include "dcmtk/dcmnet/dntypes.h"
+#include "dcmtk/dcmnet/dul.h"
+#include "dcmtk/dcmnet/lst.h"
+
 
 class DcmTransportConnection;
 class DcmTransportLayer;
 
 #define NETWORK_DISCONNECTED  2
@@ -288,10 +293,13 @@ typedef struct dul_datapdu {
     unsigned char rsv1;
     unsigned long length;
     DUL_PRESENTATIONDATAVALUE presentationDataValue;
 }   DUL_DATAPDU;
 
+
+
+
 #define DUL_PROTOCOL      (unsigned short) 0x01
 
 #define DUL_TYPEAPPLICATIONCONTEXT  (unsigned char)0x10
 #define DUL_TYPEPRESENTATIONCONTEXTRQ (unsigned char)0x20
 #define DUL_TYPEPRESENTATIONCONTEXTAC (unsigned char)0x21
diff --git a/dcmnet/include/dcmtk/dcmnet/helpers.h b/dcmnet/include/dcmtk/dcmnet/helpers.h
new file mode 100644
index 000000000..7d7e382be
--- /dev/null
+++ b/dcmnet/include/dcmtk/dcmnet/helpers.h
@@ -0,0 +1,38 @@
+/*
+ *
+ *  Copyright (C) 2021, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were partly developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmnet
+ *
+ *  Author: Michael Onken
+ *
+ *  Purpose: Collection of helper functions
+ *
+ */
+
+#ifndef DCMHET_HELPERS_H
+#define DCMHET_HELPERS_H
+
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/dcmnet/dulstruc.h"
+
+struct T_ASC_Parameters;
+class LST_HEAD;
+
+
+void
+destroyPresentationContextList(LST_HEAD ** l);
+
+void
+destroyUserInformationLists(DUL_USERINFO * userInfo);
+
+#endif
diff --git a/dcmnet/libsrc/CMakeLists.txt b/dcmnet/libsrc/CMakeLists.txt
index 2b97767ca..7ab209616 100644
--- a/dcmnet/libsrc/CMakeLists.txt
+++ b/dcmnet/libsrc/CMakeLists.txt
@@ -33,10 +33,11 @@ DCMTK_ADD_LIBRARY(dcmnet
   dulfsm.cc
   dulparse.cc
   dulpres.cc
   dwrap.c
   extneg.cc
+  helpers.cc
   lst.cc
   scp.cc
   scpcfg.cc
   scppool.cc
   scpthrd.cc
diff --git a/dcmnet/libsrc/Makefile.in b/dcmnet/libsrc/Makefile.in
index 66d8c527b..d767bea35 100644
--- a/dcmnet/libsrc/Makefile.in
+++ b/dcmnet/libsrc/Makefile.in
@@ -23,11 +23,11 @@ LOCALDEFS =
 objs = assoc.o cond.o dcompat.o dimcancl.o dimcmd.o dimdump.o dimecho.o \
 	dimfind.o dimmove.o dimse.o dimstore.o diutil.o dulconst.o dulextra.o \
 	dulfsm.o dulparse.o dulpres.o dul.o lst.o extneg.o dimget.o dcmlayer.o \
 	dcmtrans.o dcasccfg.o dcasccff.o dccfuidh.o dccftsmp.o dccfpcmp.o \
 	dccfrsmp.o dccfenmp.o dccfprmp.o dfindscu.o dstorscp.o dstorscu.o \
-	dcuserid.o scu.o scp.o scpcfg.o scpthrd.o scppool.o dwrap.o
+	dcuserid.o helper.o scu.o scp.o scpcfg.o scpthrd.o scppool.o dwrap.o
 
 library = libdcmnet.$(LIBEXT)
 
 
 all: $(library)
diff --git a/dcmnet/libsrc/assoc.cc b/dcmnet/libsrc/assoc.cc
index e69329031..a9a42a88e 100644
--- a/dcmnet/libsrc/assoc.cc
+++ b/dcmnet/libsrc/assoc.cc
@@ -116,10 +116,11 @@
 #include "dcmtk/dcmnet/cond.h"
 #include "dcmtk/dcmdata/dcuid.h"
 #include "dcmtk/ofstd/ofconsol.h"
 #include "dcmtk/ofstd/ofstd.h"
 #include "dcmtk/dcmnet/dcmtrans.h"
+#include "dcmtk/dcmnet/helpers.h"
 
 /*
 ** Constant Definitions
 */
 
@@ -334,29 +335,10 @@ ASC_createAssociationParameters(T_ASC_Parameters ** params,
 
     (*params)->DULparams.useSecureLayer = OFFalse;
     return EC_Normal;
 }
 
-static void
-destroyPresentationContextList(LST_HEAD ** lst)
-{
-    DUL_PRESENTATIONCONTEXT *pc;
-    DUL_TRANSFERSYNTAX *ts;
-
-    if ((lst == NULL) || (*lst == NULL))
-        return;
-    while ((pc = (DUL_PRESENTATIONCONTEXT*) LST_Dequeue(lst)) != NULL) {
-        if (pc->proposedTransferSyntax != NULL) {
-            while ((ts = (DUL_TRANSFERSYNTAX*) LST_Dequeue(&pc->proposedTransferSyntax)) != NULL) {
-                free(ts);
-            }
-            LST_Destroy(&pc->proposedTransferSyntax);
-        }
-        free(pc);
-    }
-    LST_Destroy(lst);
-}
 
 OFCondition
 ASC_destroyAssociationParameters(T_ASC_Parameters ** params)
 {
 
@@ -1697,12 +1679,11 @@ ASC_destroyAssociation(T_ASC_Association ** association)
     if ((*association)->DULassociation != NULL) {
         ASC_dropAssociation(*association);
     }
 
     if ((*association)->params != NULL) {
-        cond = ASC_destroyAssociationParameters(&(*association)->params);
-        if (cond.bad()) return cond;
+        ASC_destroyAssociationParameters(&(*association)->params);
     }
 
     if ((*association)->sendPDVBuffer != NULL)
         free((*association)->sendPDVBuffer);
 
diff --git a/dcmnet/libsrc/dcuserid.cc b/dcmnet/libsrc/dcuserid.cc
index 6a2d72a20..f1530fe79 100644
--- a/dcmnet/libsrc/dcuserid.cc
+++ b/dcmnet/libsrc/dcuserid.cc
@@ -1,8 +1,8 @@
 /*
  *
- *  Copyright (C) 1997-2018, OFFIS e.V.
+ *  Copyright (C) 1997-2021, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
  *
  *    OFFIS e.V.
@@ -21,11 +21,11 @@
 
 
 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
 #include "dcmtk/dcmnet/dcuserid.h"
 #include "dcmtk/dcmnet/dul.h"
-#include "dulstruc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
 
 /* ************************************************************************* */
 /*       Implementation of class UserIdentityNegotiationSubItem              */
 /* ************************************************************************* */
 
diff --git a/dcmnet/libsrc/dul.cc b/dcmnet/libsrc/dul.cc
index 49ef18886..1aba744d7 100644
--- a/dcmnet/libsrc/dul.cc
+++ b/dcmnet/libsrc/dul.cc
@@ -123,11 +123,11 @@ END_EXTERN_C
 #include "dcmtk/dcmnet/lst.h"
 #include "dcmtk/ofstd/ofconsol.h"
 #include "dcmtk/ofstd/ofstd.h"
 
 #include "dcmtk/dcmnet/dul.h"
-#include "dulstruc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
 #include "dulpriv.h"
 #include "dulfsm.h"
 #include "dcmtk/dcmnet/dcmtrans.h"
 #include "dcmtk/dcmnet/dcmlayer.h"
 #include "dcmtk/ofstd/ofstd.h"
diff --git a/dcmnet/libsrc/dulconst.cc b/dcmnet/libsrc/dulconst.cc
index d91b0379e..5900b7b7e 100644
--- a/dcmnet/libsrc/dulconst.cc
+++ b/dcmnet/libsrc/dulconst.cc
@@ -70,11 +70,11 @@
 #include "dcmtk/dcmnet/dicom.h"
 #include "dcmtk/dcmnet/cond.h"
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/lst.h"
 #include "dcmtk/dcmnet/dul.h"
-#include "dulstruc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
 #include "dulpriv.h"
 #include "dcmtk/ofstd/ofconsol.h"
 
 static OFCondition
 constructSubItem(char *name, unsigned char type,
diff --git a/dcmnet/libsrc/dulextra.cc b/dcmnet/libsrc/dulextra.cc
index b11b65aa1..06079a942 100644
--- a/dcmnet/libsrc/dulextra.cc
+++ b/dcmnet/libsrc/dulextra.cc
@@ -94,11 +94,11 @@
 
 #include "dcmtk/dcmnet/dicom.h"
 #include "dcmtk/dcmnet/lst.h"
 #include "dcmtk/dcmnet/cond.h"
 #include "dcmtk/dcmnet/dul.h"
-#include "dulstruc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
 #include "dulpriv.h"
 #include "dcmtk/dcmnet/dcmtrans.h"
 #include "dcmtk/dcmnet/diutil.h"
 
 OFBool
diff --git a/dcmnet/libsrc/dulfsm.cc b/dcmnet/libsrc/dulfsm.cc
index b3a0aaf42..92b34f3b2 100644
--- a/dcmnet/libsrc/dulfsm.cc
+++ b/dcmnet/libsrc/dulfsm.cc
@@ -103,19 +103,20 @@ END_EXTERN_C
 #include "dcmtk/ofstd/ofstdinc.h"
 #include "dcmtk/dcmnet/dicom.h"
 #include "dcmtk/dcmnet/lst.h"
 #include "dcmtk/dcmnet/cond.h"
 #include "dcmtk/dcmnet/dul.h"
-#include "dulstruc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
 #include "dulpriv.h"
 #include "dulfsm.h"
 #include "dcmtk/ofstd/ofbmanip.h"
 #include "dcmtk/ofstd/ofconsol.h"
 #include "dcmtk/dcmnet/assoc.h"    /* for ASC_MAXIMUMPDUSIZE */
 #include "dcmtk/dcmnet/dcmtrans.h"
 #include "dcmtk/dcmnet/dcmlayer.h"
 #include "dcmtk/dcmnet/diutil.h"
+#include "dcmtk/dcmnet/helpers.h"
 #include "dcmtk/ofstd/ofsockad.h" /* for class OFSockAddr */
 #include <ctime>
 
 
 /* At least Solaris doesn't define this */
@@ -302,13 +303,10 @@ DUL_PRESENTATIONCONTEXT *
 findPresentationCtx(LST_HEAD ** lst, DUL_PRESENTATIONCONTEXTID contextID);
 
 PRV_SCUSCPROLE *
 findSCUSCPRole(LST_HEAD ** lst, char *abstractSyntax);
 
-void destroyPresentationContextList(LST_HEAD ** l);
-void destroyUserInformationLists(DUL_USERINFO * userInfo);
-
 static volatile FSM_Event_Description Event_Table[] = {
     {A_ASSOCIATE_REQ_LOCAL_USER, "A-ASSOCIATE request (local user)"},
     {TRANS_CONN_CONFIRM_LOCAL_USER, "Transport conn confirmation (local)"},
     {A_ASSOCIATE_AC_PDU_RCV, "A-ASSOCIATE-AC PDU (on transport)"},
     {A_ASSOCIATE_RJ_PDU_RCV, "A-ASSOCIATE-RJ PDU (on transport)"},
@@ -3976,50 +3974,5 @@ findSCUSCPRole(LST_HEAD ** lst, char *abstractSyntax)
 
         role = (PRV_SCUSCPROLE*)LST_Next(lst);
     }
     return NULL;
 }
-
-void
-destroyPresentationContextList(LST_HEAD ** l)
-{
-    PRV_PRESENTATIONCONTEXTITEM
-    * prvCtx;
-    DUL_SUBITEM
-        * subItem;
-
-    if (*l == NULL)
-        return;
-
-    prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
-    while (prvCtx != NULL) {
-        subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
-        while (subItem != NULL) {
-            free(subItem);
-            subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
-        }
-        LST_Destroy(&prvCtx->transferSyntaxList);
-        free(prvCtx);
-        prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
-    }
-    LST_Destroy(l);
-}
-
-void
-destroyUserInformationLists(DUL_USERINFO * userInfo)
-{
-    PRV_SCUSCPROLE
-    * role;
-
-    role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
-    while (role != NULL) {
-        free(role);
-        role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
-    }
-    LST_Destroy(&userInfo->SCUSCPRoleList);
-
-    /* extended negotiation */
-    delete userInfo->extNegList; userInfo->extNegList = NULL;
-
-    /* user identity negotiation */
-    delete userInfo->usrIdent; userInfo->usrIdent = NULL;
-}
diff --git a/dcmnet/libsrc/dulparse.cc b/dcmnet/libsrc/dulparse.cc
index ea28c11ce..5f9faebba 100644
--- a/dcmnet/libsrc/dulparse.cc
+++ b/dcmnet/libsrc/dulparse.cc
@@ -68,11 +68,12 @@
 #include "dcmtk/dcmnet/dicom.h"
 #include "dcmtk/dcmnet/cond.h"
 #include "dcmtk/dcmnet/lst.h"
 #include "dcmtk/dcmnet/dul.h"
 #include "dcmtk/dcmnet/diutil.h"
-#include "dulstruc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
+#include "dcmtk/dcmnet/helpers.h"
 #include "dulpriv.h"
 #include "dcmtk/ofstd/ofconsol.h"
 
 static OFCondition
 parseSubItem(DUL_SUBITEM * subItem, unsigned char *buf,
@@ -140,13 +141,10 @@ parseAssociate(unsigned char *buf, unsigned long pduLength,
         itemLength;
     PRV_PRESENTATIONCONTEXTITEM
         * context;
 
     (void) memset(assoc, 0, sizeof(*assoc));
-    if ((assoc->presentationContextList = LST_Create()) == NULL) return EC_MemoryExhausted;
-    if ((assoc->userInfo.SCUSCPRoleList = LST_Create()) == NULL) return EC_MemoryExhausted;
-
     // Check if the PDU actually is long enough for the fields we read
     if (pduLength < 2 + 2 + 16 + 16 + 32)
         return makeLengthError("associate PDU", pduLength, 2 + 2 + 16 + 16 + 32);
 
     assoc->type = *buf++;
@@ -203,10 +201,12 @@ parseAssociate(unsigned char *buf, unsigned long pduLength,
             << STD_NAMESPACE hex << assoc->protocol
             << STD_NAMESPACE dec << OFendl
             << "Called AP Title:  " << assoc->calledAPTitle << OFendl
             << "Calling AP Title: " << assoc->callingAPTitle);
     }
+    if ((assoc->presentationContextList = LST_Create()) == NULL) return EC_MemoryExhausted;
+    if ((assoc->userInfo.SCUSCPRoleList = LST_Create()) == NULL) return EC_MemoryExhausted;
     while ((cond.good()) && (pduLength > 0))
     {
         type = *buf;
         DCMNET_TRACE("Parsing remaining " << pduLength << " bytes of A-ASSOCIATE PDU" << OFendl
                 << "Next item type: "
@@ -217,48 +217,84 @@ parseAssociate(unsigned char *buf, unsigned long pduLength,
                                 buf, &itemLength, pduLength);
             if (cond.good())
             {
                 buf += itemLength;
                 if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
-                  return makeUnderflowError("Application Context item", pduLength, itemLength);
-                DCMNET_TRACE("Successfully parsed Application Context");
+                {
+                    cond = makeUnderflowError("Application Context item", pduLength, itemLength);
+                }
+                else
+                {
+                    DCMNET_TRACE("Successfully parsed Application Context");
+                }
             }
             break;
         case DUL_TYPEPRESENTATIONCONTEXTRQ:
         case DUL_TYPEPRESENTATIONCONTEXTAC:
             context = (PRV_PRESENTATIONCONTEXTITEM*)malloc(sizeof(PRV_PRESENTATIONCONTEXTITEM));
-            if (context == NULL) return EC_MemoryExhausted;
-            (void) memset(context, 0, sizeof(*context));
-            cond = parsePresentationContext(type, context, buf, &itemLength, pduLength);
-            if (cond.bad()) return cond;
-            buf += itemLength;
-            if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
-              return makeUnderflowError("Presentation Context item", pduLength, itemLength);
-            LST_Enqueue(&assoc->presentationContextList, (LST_NODE*)context);
-            DCMNET_TRACE("Successfully parsed Presentation Context");
+            if (context != NULL)
+            {
+                (void) memset(context, 0, sizeof(*context));
+                cond = parsePresentationContext(type, context, buf, &itemLength, pduLength);
+                if (cond.bad())
+                {
+                    free(context);
+                }
+                else
+                {
+                    buf += itemLength;
+                    if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
+                    {
+                        cond =  makeUnderflowError("Presentation Context item", pduLength, itemLength);
+                    }
+                    else
+                    {
+                        LST_Enqueue(&assoc->presentationContextList, (LST_NODE*)context);
+                        DCMNET_TRACE("Successfully parsed Presentation Context");
+                    }
+                }
+            }
+            else
+            {
+                cond = EC_MemoryExhausted;
+            }
             break;
         case DUL_TYPEUSERINFO:
             // parse user info, which can contain several sub-items like User
             // Identity Negotiation or SOP Class Extended Negotiation
             cond = parseUserInfo(&assoc->userInfo, buf, &itemLength, assoc->type, pduLength);
-            if (cond.bad())
-                return cond;
-            buf += itemLength;
-            if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
-              return makeUnderflowError("User Information item", pduLength, itemLength);
-            DCMNET_TRACE("Successfully parsed User Information");
+            if (cond.good())
+            {
+                buf += itemLength;
+                if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
+                {
+                    cond = makeUnderflowError("User Information item", pduLength, itemLength);
+                }
+                else
+                {
+                    DCMNET_TRACE("Successfully parsed User Information");
+                }
+            }
             break;
         default:
             cond = parseDummy(buf, &itemLength, pduLength);
-            if (cond.bad())
-                return cond;
-            buf += itemLength;
-            if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
-              return makeUnderflowError("unknown item type", pduLength, itemLength);
+            if (cond.good())
+            {
+                buf += itemLength;
+                if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
+                {
+                    cond = makeUnderflowError("unknown item type", pduLength, itemLength);
+                }
+            }
             break;
         }
     }
+    if (cond.bad())
+    {
+      destroyPresentationContextList(&assoc->presentationContextList);
+      destroyUserInformationLists(&assoc->userInfo);
+    }
     return cond;
 }
 
 
 /* ============================================================
@@ -402,11 +438,15 @@ parsePresentationContext(unsigned char type,
                 break;
             case DUL_TYPETRANSFERSYNTAX:
                 subItem = (DUL_SUBITEM*)malloc(sizeof(DUL_SUBITEM));
                 if (subItem == NULL) return EC_MemoryExhausted;
                 cond = parseSubItem(subItem, buf, &length, presentationLength);
-                if (cond.bad()) return cond;
+                if (cond.bad())
+                {
+                    free(subItem);
+                    return cond;
+                }
                 LST_Enqueue(&context->transferSyntaxList, (LST_NODE*)subItem);
                 buf += length;
                 if (!OFStandard::safeSubtract(presentationLength, length, presentationLength))
                   return makeUnderflowError("Transfer Syntax", presentationLength, length);
                 DCMNET_TRACE("Successfully parsed Transfer Syntax");
@@ -523,11 +563,15 @@ parseUserInfo(DUL_USERINFO * userInfo,
             break;
         case DUL_TYPESCUSCPROLE:
             role = (PRV_SCUSCPROLE*)malloc(sizeof(PRV_SCUSCPROLE));
             if (role == NULL) return EC_MemoryExhausted;
             cond = parseSCUSCPRole(role, buf, &length, userLength);
-            if (cond.bad()) return cond;
+            if (cond.bad())
+            {
+                free(role);
+                return cond;
+            }
             LST_Enqueue(&userInfo->SCUSCPRoleList, (LST_NODE*)role);
             buf += length;
             if (!OFStandard::safeSubtract(userLength, OFstatic_cast(short unsigned int, length), userLength))
               return makeLengthError("SCP/SCU Role Selection sub-item", userLength, length);
             break;
diff --git a/dcmnet/libsrc/dulpres.cc b/dcmnet/libsrc/dulpres.cc
index ece31a063..7ba3beef1 100644
--- a/dcmnet/libsrc/dulpres.cc
+++ b/dcmnet/libsrc/dulpres.cc
@@ -64,11 +64,11 @@
 
 #include "dcmtk/dcmnet/dicom.h"
 #include "dcmtk/dcmnet/cond.h"
 #include "dcmtk/dcmnet/lst.h"
 #include "dcmtk/dcmnet/dul.h"
-#include "dulstruc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
 #include "dulpriv.h"
 #include "dulfsm.h"
 
 
 /* DUL_MakePresentationCtx
diff --git a/dcmnet/libsrc/helpers.cc b/dcmnet/libsrc/helpers.cc
new file mode 100644
index 000000000..9cd20cefc
--- /dev/null
+++ b/dcmnet/libsrc/helpers.cc
@@ -0,0 +1,71 @@
+/*
+ *
+ *  Copyright (C) 2021, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were partly developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmnet
+ *
+ *  Author: Michael Onken
+ *
+ *  Purpose: Collection of helper functions
+ *
+ */
+
+#include "dcmtk/dcmnet/helpers.h"
+#include "dcmtk/dcmnet/lst.h"
+#include "dcmtk/dcmnet/assoc.h"
+#include "dcmtk/dcmnet/dulstruc.h"
+
+
+void
+destroyPresentationContextList(LST_HEAD ** l)
+{
+    PRV_PRESENTATIONCONTEXTITEM
+    * prvCtx;
+    DUL_SUBITEM
+        * subItem;
+
+    if (*l == NULL)
+        return;
+
+    prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
+    while (prvCtx != NULL) {
+        subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
+        while (subItem != NULL) {
+            free(subItem);
+            subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
+        }
+        LST_Destroy(&prvCtx->transferSyntaxList);
+        free(prvCtx);
+        prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
+    }
+    LST_Destroy(l);
+}
+
+void
+destroyUserInformationLists(DUL_USERINFO * userInfo)
+{
+    PRV_SCUSCPROLE
+    * role;
+
+    role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
+    while (role != NULL) {
+        free(role);
+        role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
+    }
+    LST_Destroy(&userInfo->SCUSCPRoleList);
+
+    /* extended negotiation */
+    delete userInfo->extNegList; userInfo->extNegList = NULL;
+
+    /* user identity negotiation */
+    delete userInfo->usrIdent; userInfo->usrIdent = NULL;
+}

Vulnerable code: 	dcuserid.o scu.o scp.o scpcfg.o scpthrd.o scppool.o dwrap.o
static void
destroyPresentationContextList(LST_HEAD ** lst)
{
    DUL_PRESENTATIONCONTEXT *pc;
    DUL_TRANSFERSYNTAX *ts;

    if ((lst == NULL) || (*lst == NULL))
        return;
    while ((pc = (DUL_PRESENTATIONCONTEXT*) LST_Dequeue(lst)) != NULL) {
        if (pc->proposedTransferSyntax != NULL) {
            while ((ts = (DUL_TRANSFERSYNTAX*) LST_Dequeue(&pc->proposedTransferSyntax)) != NULL) {
                free(ts);
            }
            LST_Destroy(&pc->proposedTransferSyntax);
        }
        free(pc);
    }
    LST_Destroy(lst);
}
        cond = ASC_destroyAssociationParameters(&(*association)->params);
        if (cond.bad()) return cond;
 *  Copyright (C) 1997-2018, OFFIS e.V.
#include "dulstruc.h"
#include "dulstruc.h"
#include "dulstruc.h"
#include "dulstruc.h"
#include "dulstruc.h"
void destroyPresentationContextList(LST_HEAD ** l);
void destroyUserInformationLists(DUL_USERINFO * userInfo);


void
destroyPresentationContextList(LST_HEAD ** l)
{
    PRV_PRESENTATIONCONTEXTITEM
    * prvCtx;
    DUL_SUBITEM
        * subItem;

    if (*l == NULL)
        return;

    prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
    while (prvCtx != NULL) {
        subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
        while (subItem != NULL) {
            free(subItem);
            subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
        }
        LST_Destroy(&prvCtx->transferSyntaxList);
        free(prvCtx);
        prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
    }
    LST_Destroy(l);
}

void
destroyUserInformationLists(DUL_USERINFO * userInfo)
{
    PRV_SCUSCPROLE
    * role;

    role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
    while (role != NULL) {
        free(role);
        role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
    }
    LST_Destroy(&userInfo->SCUSCPRoleList);

    /* extended negotiation */
    delete userInfo->extNegList; userInfo->extNegList = NULL;

    /* user identity negotiation */
    delete userInfo->usrIdent; userInfo->usrIdent = NULL;
}
#include "dulstruc.h"
    if ((assoc->presentationContextList = LST_Create()) == NULL) return EC_MemoryExhausted;
    if ((assoc->userInfo.SCUSCPRoleList = LST_Create()) == NULL) return EC_MemoryExhausted;

                  return makeUnderflowError("Application Context item", pduLength, itemLength);
                DCMNET_TRACE("Successfully parsed Application Context");
            if (context == NULL) return EC_MemoryExhausted;
            (void) memset(context, 0, sizeof(*context));
            cond = parsePresentationContext(type, context, buf, &itemLength, pduLength);
            if (cond.bad()) return cond;
            buf += itemLength;
            if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
              return makeUnderflowError("Presentation Context item", pduLength, itemLength);
            LST_Enqueue(&assoc->presentationContextList, (LST_NODE*)context);
            DCMNET_TRACE("Successfully parsed Presentation Context");
            if (cond.bad())
                return cond;
            buf += itemLength;
            if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
              return makeUnderflowError("User Information item", pduLength, itemLength);
            DCMNET_TRACE("Successfully parsed User Information");
            if (cond.bad())
                return cond;
            buf += itemLength;
            if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
              return makeUnderflowError("unknown item type", pduLength, itemLength);
                if (cond.bad()) return cond;
            if (cond.bad()) return cond;
#include "dulstruc.h"
Fixed code: #include "dcmtk/dcmnet/dicom.h"
#include "dcmtk/dcmnet/dntypes.h"
#include "dcmtk/dcmnet/dul.h"
#include "dcmtk/dcmnet/lst.h"




/*
 *
 *  Copyright (C) 2021, OFFIS e.V.
 *  All rights reserved.  See COPYRIGHT file for details.
 *
 *  This software and supporting documentation were partly developed by
 *
 *    OFFIS e.V.
 *    R&D Division Health
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *
 *  Module: dcmnet
 *
 *  Author: Michael Onken
 *
 *  Purpose: Collection of helper functions
 *
 */

#ifndef DCMHET_HELPERS_H
#define DCMHET_HELPERS_H

#include "dcmtk/ofstd/ofcond.h"
#include "dcmtk/dcmnet/dulstruc.h"

struct T_ASC_Parameters;
class LST_HEAD;


void
destroyPresentationContextList(LST_HEAD ** l);

void
destroyUserInformationLists(DUL_USERINFO * userInfo);

#endif
  helpers.cc
	dcuserid.o helper.o scu.o scp.o scpcfg.o scpthrd.o scppool.o dwrap.o
#include "dcmtk/dcmnet/helpers.h"
        ASC_destroyAssociationParameters(&(*association)->params);
 *  Copyright (C) 1997-2021, OFFIS e.V.
#include "dcmtk/dcmnet/dulstruc.h"
#include "dcmtk/dcmnet/dulstruc.h"
#include "dcmtk/dcmnet/dulstruc.h"
#include "dcmtk/dcmnet/dulstruc.h"
#include "dcmtk/dcmnet/dulstruc.h"
#include "dcmtk/dcmnet/helpers.h"
#include "dcmtk/dcmnet/dulstruc.h"
#include "dcmtk/dcmnet/helpers.h"
    if ((assoc->presentationContextList = LST_Create()) == NULL) return EC_MemoryExhausted;
    if ((assoc->userInfo.SCUSCPRoleList = LST_Create()) == NULL) return EC_MemoryExhausted;
                {
                    cond = makeUnderflowError("Application Context item", pduLength, itemLength);
                }
                else
                {
                    DCMNET_TRACE("Successfully parsed Application Context");
                }
            if (context != NULL)
            {
                (void) memset(context, 0, sizeof(*context));
                cond = parsePresentationContext(type, context, buf, &itemLength, pduLength);
                if (cond.bad())
                {
                    free(context);
                }
                else
                {
                    buf += itemLength;
                    if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
                    {
                        cond =  makeUnderflowError("Presentation Context item", pduLength, itemLength);
                    }
                    else
                    {
                        LST_Enqueue(&assoc->presentationContextList, (LST_NODE*)context);
                        DCMNET_TRACE("Successfully parsed Presentation Context");
                    }
                }
            }
            else
            {
                cond = EC_MemoryExhausted;
            }
            if (cond.good())
            {
                buf += itemLength;
                if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
                {
                    cond = makeUnderflowError("User Information item", pduLength, itemLength);
                }
                else
                {
                    DCMNET_TRACE("Successfully parsed User Information");
                }
            }
            if (cond.good())
            {
                buf += itemLength;
                if (!OFStandard::safeSubtract(pduLength, itemLength, pduLength))
                {
                    cond = makeUnderflowError("unknown item type", pduLength, itemLength);
                }
            }
    if (cond.bad())
    {
      destroyPresentationContextList(&assoc->presentationContextList);
      destroyUserInformationLists(&assoc->userInfo);
    }
                if (cond.bad())
                {
                    free(subItem);
                    return cond;
                }
            if (cond.bad())
            {
                free(role);
                return cond;
            }
#include "dcmtk/dcmnet/dulstruc.h"
/*
 *
 *  Copyright (C) 2021, OFFIS e.V.
 *  All rights reserved.  See COPYRIGHT file for details.
 *
 *  This software and supporting documentation were partly developed by
 *
 *    OFFIS e.V.
 *    R&D Division Health
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *
 *  Module: dcmnet
 *
 *  Author: Michael Onken
 *
 *  Purpose: Collection of helper functions
 *
 */

#include "dcmtk/dcmnet/helpers.h"
#include "dcmtk/dcmnet/lst.h"
#include "dcmtk/dcmnet/assoc.h"
#include "dcmtk/dcmnet/dulstruc.h"


void
destroyPresentationContextList(LST_HEAD ** l)
{
    PRV_PRESENTATIONCONTEXTITEM
    * prvCtx;
    DUL_SUBITEM
        * subItem;

    if (*l == NULL)
        return;

    prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
    while (prvCtx != NULL) {
        subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
        while (subItem != NULL) {
            free(subItem);
            subItem = (DUL_SUBITEM*)LST_Dequeue(&prvCtx->transferSyntaxList);
        }
        LST_Destroy(&prvCtx->transferSyntaxList);
        free(prvCtx);
        prvCtx = (PRV_PRESENTATIONCONTEXTITEM*)LST_Dequeue(l);
    }
    LST_Destroy(l);
}

void
destroyUserInformationLists(DUL_USERINFO * userInfo)
{
    PRV_SCUSCPROLE
    * role;

    role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
    while (role != NULL) {
        free(role);
        role = (PRV_SCUSCPROLE*)LST_Dequeue(&userInfo->SCUSCPRoleList);
    }
    LST_Destroy(&userInfo->SCUSCPRoleList);

    /* extended negotiation */
    delete userInfo->extNegList; userInfo->extNegList = NULL;

    /* user identity negotiation */
    delete userInfo->usrIdent; userInfo->usrIdent = NULL;
}