Просмотр исходного кода

Merge remote-tracking branch 'EIPStackGroup_OpENer/master'

micsat 5 лет назад
Родитель
Сommit
ae68462773

+ 51 - 0
README.md

@@ -127,6 +127,57 @@ use the GIT version you will need the program Doxygen for generating the HTML
 documentation. You can generate the documentation by invoking doxygen from the 
 command line in the opener main directory.
 
+
+Fuzzing
+--------------
+### Intro
+Fuzzing is an automated testing method that directs varying input data to a program in 
+order to monitor output. It is a way to test for overall reliability as well as identify 
+potential security bugs.
+
+The fuzzer we are using is AFL, a fuzzer that uses runtime guided techniques to create input for the tested program. From a high-level prespective AFL works as follows:
+- Forks the fuzzed process
+- Genereates a new test case based on a predefined input
+- Feeds the fuzzed process with the test case through STDIN
+- Monitors the execution and registers which paths are reachable
+
+![Alt text](fuzz/imgs/fuzz.png "AFL Fuzzing")
+
+### Compile
+To start fuzzing this project with AFL you'll need to compile it with AFL.
+First make sure you have AFL installed:
+```
+sudo apt install build-essential
+wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
+tar xzf afl-latest.tgz
+cd afl*
+make && sudo make install
+echo "AFL is ready at: $(which afl-fuzz)"
+
+```
+
+Then, compile OpENer with AFL:
+1. Change to the ``OpENer/bin/posix`` directory
+2. Compile OpENer with AFL ``./setup_posix_fuzz_afl.sh`` 
+3. Run ``make``
+
+### Fuzz
+Finally, generate some test cases and start AFL:
+```
+# Generate inputs
+mkdir inputs
+echo 630000000000000000000000000000000000000000000000 | xxd -r -p > ./inputs/enip_req_list_identity
+# You can also use the inputs we prepared from OpENer/fuzz/inputs
+# Finally, let's fuzz!
+afl-fuzz -i inputs -o findings ./src/ports/POSIX/OpENer <interface_name>
+```
+
+### Reproduce a crash
+Usually to reproduce a crash it's enough to retransmit the testcase using ``cat testcase | nc IP_ADDR 44818``
+However, since CIP runs over the EtherNet/IP layer, it must first register a valid session. Therefore, we need to use a dedicated script:
+`python fuzz/scripts/send_testcase.py IP testcase_path`
+
+
 Porting OpENer:
 ---------------
 For porting OpENer to new platforms please see the porting section in the 

+ 1 - 1
bin/posix/setup_posix.sh

@@ -1,2 +1,2 @@
-cmake -DOpENer_PLATFORM:STRING="POSIX" -DCMAKE_BUILD_TYPE:STRING="" -DBUILD_SHARED_LIBS:BOOL=OFF ../../source
+cmake -DCMAKE_C_COMPILER=gcc -DOpENer_PLATFORM:STRING="POSIX" -DCMAKE_BUILD_TYPE:STRING="" -DBUILD_SHARED_LIBS:BOOL=OFF ../../source
 

+ 2 - 0
bin/posix/setup_posix_fuzz_afl.sh

@@ -0,0 +1,2 @@
+cmake -DCMAKE_C_COMPILER=afl-clang-fast -DUSE_FUZZ_AFL=ON -DOpENer_PLATFORM:STRING="POSIX" -DCMAKE_BUILD_TYPE:STRING="" -DBUILD_SHARED_LIBS:BOOL=OFF ../../source
+

BIN
fuzz/imgs/fuzz.png


BIN
fuzz/inputs/cip_req_forward_open


BIN
fuzz/inputs/cip_req_list_identity_cip


BIN
fuzz/inputs/enip_req_list_identity


BIN
fuzz/inputs/enip_req_register_session


+ 38 - 0
fuzz/scripts/send_testcase.py

@@ -0,0 +1,38 @@
+import sys
+import socket
+import struct
+
+if len(sys.argv) != 3:
+	print("python {} IP TESTCASE_PATH".format(sys.argv[0]))
+	sys.exit(1)
+
+HOST_IP = sys.argv[1]
+HOST_PORT = 44818
+TESTCASE_PATH = sys.argv[2]
+
+ENIP_SESSION_CONTEXT = b"\x92\x83J\x0b=\x9e\x0cW"
+ENIP_INIT_SESSION_PACKET = b"e\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00" + ENIP_SESSION_CONTEXT + b"\x00\x00\x00\x00\x01\x00\x00\x00"
+
+
+print("[-] Connecting to {}:{}".format(HOST_IP, HOST_PORT))
+s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+s.connect((HOST_IP, HOST_PORT))
+
+print("[-] Init ENIP session")
+s.sendall(ENIP_INIT_SESSION_PACKET)
+enip_session = s.recv(1024)
+session_handle = enip_session[4:8]
+print("[-] Got ENIP Session Handle: {}".format(struct.unpack("<I", session_handle)[0]))
+print("[-] Reading testcase from: '{}'".format(TESTCASE_PATH))
+with open(TESTCASE_PATH, "rb") as f:
+	testcase_data = f.read()
+
+print("[-] Patching sender context and session handle")
+testcase = testcase_data[:4]		# command, len
+testcase += session_handle 		# session handle
+testcase += testcase_data[8:12] 	# status
+testcase += ENIP_SESSION_CONTEXT 	# session context
+testcase += testcase_data[20:]		# options and payload
+print("[-] Sending testcase of {} bytes".format(len(testcase)))
+s.send(testcase)
+s.close()

+ 122 - 285
source/src/enet_encap/cpf.c

@@ -24,58 +24,39 @@ const size_t kSequencedAddressItemLength = 8;
 
 CipCommonPacketFormatData g_common_packet_format_data_item; /**< CPF global data items */
 
-static void InitializeMessageRouterResponse(
-  CipMessageRouterResponse *const message_router_response) {
-  memset(message_router_response, 0, sizeof(*message_router_response) );
+static void InitializeMessageRouterResponse(CipMessageRouterResponse *const message_router_response) {
+  memset(message_router_response, 0, sizeof(*message_router_response));
   InitializeENIPMessage(&message_router_response->message);
 }
 
-EipStatus NotifyCommonPacketFormat(const EncapsulationData *const received_data,
-                                   const struct sockaddr *const originator_address,
-                                   ENIPMessage *const outgoing_message) {
+EipStatus NotifyCommonPacketFormat(const EncapsulationData *const received_data, const struct sockaddr *const originator_address,
+    ENIPMessage *const outgoing_message) {
   EipStatus return_value = kEipStatusError;
   CipMessageRouterResponse message_router_response;
   InitializeMessageRouterResponse(&message_router_response);
 
   if(kEipStatusError
-     == (return_value =
-           CreateCommonPacketFormatStructure(received_data->
-                                             current_communication_buffer_position,
-                                             received_data->data_length,
-                                             &
-                                             g_common_packet_format_data_item) ) )
-  {
+    == (return_value = CreateCommonPacketFormatStructure(received_data->current_communication_buffer_position, received_data->data_length,
+      &g_common_packet_format_data_item))) {
     OPENER_TRACE_ERR("notifyCPF: error from createCPFstructure\n");
   } else {
     return_value = kEipStatusOkSend; /* In cases of errors we normally need to send an error response */
-    if(g_common_packet_format_data_item.address_item.type_id ==
-       kCipItemIdNullAddress)                                                          /* check if NullAddressItem received, otherwise it is no unconnected message and should not be here*/
+    if(g_common_packet_format_data_item.address_item.type_id == kCipItemIdNullAddress) /* check if NullAddressItem received, otherwise it is no unconnected message and should not be here*/
     { /* found null address item*/
-      if(g_common_packet_format_data_item.data_item.type_id ==
-         kCipItemIdUnconnectedDataItem) {                                                       /* unconnected data item received*/
-        return_value = NotifyMessageRouter(
-          g_common_packet_format_data_item.data_item.data,
-          g_common_packet_format_data_item.data_item.length,
-          &message_router_response,
-          originator_address,
-          received_data->session_handle);
+      if(g_common_packet_format_data_item.data_item.type_id == kCipItemIdUnconnectedDataItem) { /* unconnected data item received*/
+        return_value = NotifyMessageRouter(g_common_packet_format_data_item.data_item.data, g_common_packet_format_data_item.data_item.length,
+          &message_router_response, originator_address, received_data->session_handle);
         if(return_value != kEipStatusError) {
           SkipEncapsulationHeader(outgoing_message);
           /* TODO: Here we get the status. What to do? kEipStatusError from AssembleLinearMessage().
            *  Its not clear how to transport this error information to the requester. */
-          EipStatus status = AssembleLinearMessage(&message_router_response,
-                                                   &g_common_packet_format_data_item,
-                                                   outgoing_message);
+          EipStatus status = AssembleLinearMessage(&message_router_response, &g_common_packet_format_data_item, outgoing_message);
 
           /* Save pointer and move to start for Encapusulation Header */
           CipOctet *buffer = outgoing_message->current_message_position;
-          outgoing_message->current_message_position =
-            outgoing_message->message_buffer;
-          GenerateEncapsulationHeader(received_data,
-                                      outgoing_message->used_message_length,
-                                      received_data->session_handle,
-                                      kEncapsulationProtocolSuccess,
-                                      outgoing_message);
+          outgoing_message->current_message_position = outgoing_message->message_buffer;
+          GenerateEncapsulationHeader(received_data, outgoing_message->used_message_length, received_data->session_handle, kEncapsulationProtocolSuccess,
+            outgoing_message);
           /* Move pointer back to last octet */
           outgoing_message->current_message_position = buffer;
           return_value = kEipStatusOkSend;
@@ -83,137 +64,97 @@ EipStatus NotifyCommonPacketFormat(const EncapsulationData *const received_data,
       } else {
         /* wrong data item detected*/
         OPENER_TRACE_ERR(
-          "notifyCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
-        GenerateEncapsulationHeader(received_data,
-                                    0,
-                                    received_data->session_handle,
-                                    kEncapsulationProtocolIncorrectData,
-                                    outgoing_message);
+            "notifyCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
+        GenerateEncapsulationHeader(received_data, 0, received_data->session_handle, kEncapsulationProtocolIncorrectData, outgoing_message);
         return_value = kEipStatusOkSend;
       }
     } else {
       OPENER_TRACE_ERR(
-        "notifyCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
-      GenerateEncapsulationHeader(received_data,
-                                  0,
-                                  received_data->session_handle,
-                                  kEncapsulationProtocolIncorrectData,
-                                  outgoing_message);
+          "notifyCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
+      GenerateEncapsulationHeader(received_data, 0, received_data->session_handle, kEncapsulationProtocolIncorrectData, outgoing_message);
       return_value = kEipStatusOkSend;
     }
   }
   return return_value;
 }
 
-EipStatus NotifyConnectedCommonPacketFormat(
-  const EncapsulationData *const received_data,
-  const struct sockaddr *const originator_address,
-  ENIPMessage *const outgoing_message) {
+EipStatus NotifyConnectedCommonPacketFormat(const EncapsulationData *const received_data, const struct sockaddr *const originator_address,
+    ENIPMessage *const outgoing_message) {
 
-  EipStatus return_value = CreateCommonPacketFormatStructure(
-    received_data->current_communication_buffer_position,
-    received_data->data_length,
+  EipStatus return_value = CreateCommonPacketFormatStructure(received_data->current_communication_buffer_position, received_data->data_length,
     &g_common_packet_format_data_item);
 
   if(kEipStatusError == return_value) {
     OPENER_TRACE_ERR("notifyConnectedCPF: error from createCPFstructure\n");
   } else {
     return_value = kEipStatusError; /* For connected explicit messages status always has to be 0*/
-    if(g_common_packet_format_data_item.address_item.type_id ==
-       kCipItemIdConnectionAddress)                                                          /* check if ConnectedAddressItem received, otherwise it is no connected message and should not be here*/
+    if(g_common_packet_format_data_item.address_item.type_id == kCipItemIdConnectionAddress) /* check if ConnectedAddressItem received, otherwise it is no connected message and should not be here*/
     { /* ConnectedAddressItem item */
-      CipConnectionObject *connection_object = GetConnectedObject(
-        g_common_packet_format_data_item.address_item.data.connection_identifier);
+      CipConnectionObject *connection_object = GetConnectedObject(g_common_packet_format_data_item.address_item.data.connection_identifier);
       if(NULL != connection_object) {
         /* reset the watchdog timer */
         ConnectionObjectResetInactivityWatchdogTimerValue(connection_object);
 
         /*TODO check connection id  and sequence count */
-        if(g_common_packet_format_data_item.data_item.type_id ==
-           kCipItemIdConnectedDataItem) {                                                       /* connected data item received*/
+        if(g_common_packet_format_data_item.data_item.type_id == kCipItemIdConnectedDataItem) { /* connected data item received*/
           EipUint8 *buffer = g_common_packet_format_data_item.data_item.data;
-          g_common_packet_format_data_item.address_item.data.sequence_number =
-            GetUintFromMessage( (const EipUint8 **const ) &buffer );
+          g_common_packet_format_data_item.address_item.data.sequence_number = GetUintFromMessage((const EipUint8** const ) &buffer);
           OPENER_TRACE_INFO(
-            "Class 3 sequence number: %d, last sequence number: %d\n",
-            g_common_packet_format_data_item.address_item.data.sequence_number,
-            connection_object->sequence_count_consuming);
-          if(connection_object->sequence_count_consuming ==
-             g_common_packet_format_data_item.address_item.data.sequence_number)
-          {
-            memcpy(outgoing_message,
-                   &(connection_object->last_reply_sent),
-                   sizeof(ENIPMessage) );
-            outgoing_message->current_message_position =
-              outgoing_message->message_buffer;
+              "Class 3 sequence number: %d, last sequence number: %d\n",
+              g_common_packet_format_data_item.address_item.data.sequence_number,
+              connection_object->sequence_count_consuming);
+          if(connection_object->sequence_count_consuming == g_common_packet_format_data_item.address_item.data.sequence_number) {
+            memcpy(outgoing_message, &(connection_object->last_reply_sent), sizeof(ENIPMessage));
+            outgoing_message->current_message_position = outgoing_message->message_buffer;
             /* Regenerate encapsulation header for new message */
             outgoing_message->used_message_length -=
-              ENCAPSULATION_HEADER_LENGTH;
-            GenerateEncapsulationHeader(received_data,
-                                        outgoing_message->used_message_length,
-                                        received_data->session_handle,
-                                        kEncapsulationProtocolSuccess,
-                                        outgoing_message);
+            ENCAPSULATION_HEADER_LENGTH;
+            GenerateEncapsulationHeader(received_data, outgoing_message->used_message_length, received_data->session_handle, kEncapsulationProtocolSuccess,
+              outgoing_message);
             outgoing_message->current_message_position = buffer;
             /* End regenerate encapsulation header for new message */
             return kEipStatusOkSend;
           }
-          connection_object->sequence_count_consuming =
-            g_common_packet_format_data_item.address_item.data.sequence_number;
+          connection_object->sequence_count_consuming = g_common_packet_format_data_item.address_item.data.sequence_number;
 
           ConnectionObjectResetInactivityWatchdogTimerValue(connection_object);
 
           CipMessageRouterResponse message_router_response;
           InitializeMessageRouterResponse(&message_router_response);
-          return_value = NotifyMessageRouter(buffer,
-                                             g_common_packet_format_data_item.data_item.length - 2,
-                                             &message_router_response,
-                                             originator_address,
-                                             received_data->session_handle);
+          return_value = NotifyMessageRouter(buffer, g_common_packet_format_data_item.data_item.length - 2, &message_router_response, originator_address,
+            received_data->session_handle);
 
           if(return_value != kEipStatusError) {
-            g_common_packet_format_data_item.address_item.data.
-            connection_identifier =
-              connection_object->cip_produced_connection_id;
+            g_common_packet_format_data_item.address_item.data.connection_identifier = connection_object->cip_produced_connection_id;
             SkipEncapsulationHeader(outgoing_message);
             /* TODO: Here we get the status. What to do? kEipStatusError from AssembleLinearMessage().
              *  Its not clear how to transport this error information to the requester. */
-            EipStatus status = AssembleLinearMessage(&message_router_response,
-                                                     &g_common_packet_format_data_item,
-                                                     outgoing_message);
+            EipStatus status = AssembleLinearMessage(&message_router_response, &g_common_packet_format_data_item, outgoing_message);
 
             CipOctet *buffer = outgoing_message->current_message_position;
-            outgoing_message->current_message_position =
-              outgoing_message->message_buffer;
-            GenerateEncapsulationHeader(received_data,
-                                        outgoing_message->used_message_length,
-                                        received_data->session_handle,
-                                        kEncapsulationProtocolSuccess,
-                                        outgoing_message);
+            outgoing_message->current_message_position = outgoing_message->message_buffer;
+            GenerateEncapsulationHeader(received_data, outgoing_message->used_message_length, received_data->session_handle, kEncapsulationProtocolSuccess,
+              outgoing_message);
             outgoing_message->current_message_position = buffer;
-            memcpy(&connection_object->last_reply_sent,
-                   outgoing_message,
-                   sizeof(ENIPMessage) );
+            memcpy(&connection_object->last_reply_sent, outgoing_message, sizeof(ENIPMessage));
             return_value = kEipStatusOkSend;
           }
         } else {
           /* wrong data item detected*/
           OPENER_TRACE_ERR(
-            "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
+              "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
         }
       } else {
         OPENER_TRACE_ERR(
-          "notifyConnectedCPF: connection with given ID could not be found\n");
+            "notifyConnectedCPF: connection with given ID could not be found\n");
       }
     } else {
       OPENER_TRACE_ERR(
-        "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
+          "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
     }
   }
   // return outgoing_message->used_message_length;
-  return (0 !=
-          outgoing_message->used_message_length ? kEipStatusOkSend :
-          kEipStatusOk);                                                                 /* TODO: What would the right EipStatus to return? */
+  return (0 != outgoing_message->used_message_length ? kEipStatusOkSend : kEipStatusOk); /* TODO: What would the right EipStatus to return? */
 }
 
 /**
@@ -225,17 +166,14 @@ EipStatus NotifyConnectedCommonPacketFormat(
  *   @return kEipStatusOk .. success
  *             kEipStatusError .. error
  */
-EipStatus CreateCommonPacketFormatStructure(const EipUint8 *data,
-                                            size_t data_length,
-                                            CipCommonPacketFormatData *common_packet_format_data)
-{
+EipStatus CreateCommonPacketFormatStructure(const EipUint8 *data, size_t data_length, CipCommonPacketFormatData *common_packet_format_data) {
 
   common_packet_format_data->address_info_item[0].type_id = 0;
   common_packet_format_data->address_info_item[1].type_id = 0;
 
   int length_count = 0;
   CipUint item_count = GetUintFromMessage(&data);
-  OPENER_ASSERT(4U >= item_count);/* Sanitizing data - probably needs to be changed for productive code */
+  //OPENER_ASSERT(4U >= item_count);/* Sanitizing data - probably needs to be changed for productive code */
   common_packet_format_data->item_count = item_count;
   length_count += 2;
   if(common_packet_format_data->item_count >= 1U) {
@@ -243,42 +181,34 @@ EipStatus CreateCommonPacketFormatStructure(const EipUint8 *data,
     common_packet_format_data->address_item.length = GetUintFromMessage(&data);
     length_count += 4;
     if(common_packet_format_data->address_item.length >= 4) {
-      common_packet_format_data->address_item.data.connection_identifier =
-        GetUdintFromMessage(&data);
+      common_packet_format_data->address_item.data.connection_identifier = GetUdintFromMessage(&data);
       length_count += 4;
     }
     if(common_packet_format_data->address_item.length == 8) {
-      common_packet_format_data->address_item.data.sequence_number =
-        GetUdintFromMessage(&data);
+      common_packet_format_data->address_item.data.sequence_number = GetUdintFromMessage(&data);
       length_count += 4;
     }
   }
   if(common_packet_format_data->item_count >= 2) {
     common_packet_format_data->data_item.type_id = GetUintFromMessage(&data);
     common_packet_format_data->data_item.length = GetUintFromMessage(&data);
-    common_packet_format_data->data_item.data = (EipUint8 *) data;
+    common_packet_format_data->data_item.data = (EipUint8*) data;
     data += common_packet_format_data->data_item.length;
     length_count += (4 + common_packet_format_data->data_item.length);
 
-    for(size_t j = 0; j < (common_packet_format_data->item_count - 2); j++) /* TODO there needs to be a limit check here???*/
+    CipUsint address_item_count = common_packet_format_data->item_count - 2;
+    for(size_t j = 0; j < (address_item_count > 2 ? 2 : address_item_count); j++) /* TODO there needs to be a limit check here???*/
     {
-      common_packet_format_data->address_info_item[j].type_id =
-        GetIntFromMessage(&data);
+      common_packet_format_data->address_info_item[j].type_id = GetIntFromMessage(&data);
       OPENER_TRACE_INFO("Sockaddr type id: %x\n",
-                        common_packet_format_data->address_info_item[j].type_id);
+          common_packet_format_data->address_info_item[j].type_id);
       length_count += 2;
-      if( (common_packet_format_data->address_info_item[j].type_id ==
-           kCipItemIdSocketAddressInfoOriginatorToTarget)
-          || (common_packet_format_data->address_info_item[j].type_id ==
-              kCipItemIdSocketAddressInfoTargetToOriginator) ) {
-        common_packet_format_data->address_info_item[j].length =
-          GetIntFromMessage(&data);
-        common_packet_format_data->address_info_item[j].sin_family =
-          GetIntFromMessage(&data);
-        common_packet_format_data->address_info_item[j].sin_port =
-          GetIntFromMessage(&data);
-        common_packet_format_data->address_info_item[j].sin_addr =
-          GetUdintFromMessage(&data);
+      if((common_packet_format_data->address_info_item[j].type_id == kCipItemIdSocketAddressInfoOriginatorToTarget)
+        || (common_packet_format_data->address_info_item[j].type_id == kCipItemIdSocketAddressInfoTargetToOriginator)) {
+        common_packet_format_data->address_info_item[j].length = GetIntFromMessage(&data);
+        common_packet_format_data->address_info_item[j].sin_family = GetIntFromMessage(&data);
+        common_packet_format_data->address_info_item[j].sin_port = GetIntFromMessage(&data);
+        common_packet_format_data->address_info_item[j].sin_addr = GetUdintFromMessage(&data);
         for(size_t i = 0; i < 8; i++) {
           common_packet_format_data->address_info_item[j].nasin_zero[i] = *data;
           data++;
@@ -301,7 +231,7 @@ EipStatus CreateCommonPacketFormatStructure(const EipUint8 *data,
     return kEipStatusOk;
   } else {
     OPENER_TRACE_WARN(
-      "something is wrong with the length in Message Router @ CreateCommonPacketFormatStructure\n");
+        "something is wrong with the length in Message Router @ CreateCommonPacketFormatStructure\n");
     if(common_packet_format_data->item_count > 2) {
       /* there is an optional packet in data stream which is not sockaddr item */
       return kEipStatusOk;
@@ -326,15 +256,11 @@ void EncodeNullAddressItem(ENIPMessage *const outgoing_message) {
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
  */
-void EncodeConnectedAddressItem(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
+void EncodeConnectedAddressItem(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
   /* connected data item -> address length set to 4 and copy ConnectionIdentifier */
   AddIntToMessage(kCipItemIdConnectionAddress, outgoing_message);
   AddIntToMessage(4, outgoing_message);
-  AddDintToMessage(
-    common_packet_format_data_item->address_item.data.connection_identifier,
-    outgoing_message);
+  AddDintToMessage(common_packet_format_data_item->address_item.data.connection_identifier, outgoing_message);
 }
 
 /**
@@ -343,18 +269,12 @@ void EncodeConnectedAddressItem(
  * @param common_packet_format_data_item Common Packet Format item which is used in the encoding
  * @param outgoing_message The outgoing message object
  */
-void EncodeSequencedAddressItem(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
+void EncodeSequencedAddressItem(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
   /* sequenced address item -> address length set to 8 and copy ConnectionIdentifier and SequenceNumber */
   AddIntToMessage(kCipItemIdSequencedAddressItem, outgoing_message);
   AddIntToMessage(kSequencedAddressItemLength, outgoing_message);
-  AddDintToMessage(
-    common_packet_format_data_item->address_item.data.connection_identifier,
-    outgoing_message);
-  AddDintToMessage(
-    common_packet_format_data_item->address_item.data.sequence_number,
-    outgoing_message);
+  AddDintToMessage(common_packet_format_data_item->address_item.data.connection_identifier, outgoing_message);
+  AddDintToMessage(common_packet_format_data_item->address_item.data.sequence_number, outgoing_message);
 }
 
 /**
@@ -363,9 +283,7 @@ void EncodeSequencedAddressItem(
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
  */
-void EncodeItemCount(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
+void EncodeItemCount(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
   AddIntToMessage(common_packet_format_data_item->item_count, outgoing_message); /* item count */
 }
 
@@ -375,11 +293,8 @@ void EncodeItemCount(
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
  */
-void EncodeDataItemType(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
-  AddIntToMessage(common_packet_format_data_item->data_item.type_id,
-                  outgoing_message);
+void EncodeDataItemType(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
+  AddIntToMessage(common_packet_format_data_item->data_item.type_id, outgoing_message);
 }
 
 /**
@@ -388,11 +303,8 @@ void EncodeDataItemType(
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
  */
-void EncodeDataItemLength(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
-  AddIntToMessage(common_packet_format_data_item->data_item.length,
-                  outgoing_message);
+void EncodeDataItemLength(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
+  AddIntToMessage(common_packet_format_data_item->data_item.length, outgoing_message);
 }
 
 /**
@@ -401,16 +313,10 @@ void EncodeDataItemLength(
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
  */
-void EncodeDataItemData(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
-  memcpy(outgoing_message->current_message_position,
-         common_packet_format_data_item->data_item.data,
-         common_packet_format_data_item->data_item.length);
-  outgoing_message->current_message_position +=
-    common_packet_format_data_item->data_item.length;
-  outgoing_message->used_message_length +=
-    common_packet_format_data_item->data_item.length;
+void EncodeDataItemData(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
+  memcpy(outgoing_message->current_message_position, common_packet_format_data_item->data_item.data, common_packet_format_data_item->data_item.length);
+  outgoing_message->current_message_position += common_packet_format_data_item->data_item.length;
+  outgoing_message->used_message_length += common_packet_format_data_item->data_item.length;
 }
 
 /**
@@ -420,15 +326,9 @@ void EncodeDataItemData(
  * @param outgoing_message The outgoing message object
  */
 
-void EncodeConnectedDataItemLength(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
-  AddIntToMessage( (EipUint16) (message_router_response->message.
-                                used_message_length + 4 + 2                                 /* TODO: Magic numbers */
-                                + (2 *
-                                   message_router_response->
-                                   size_of_additional_status) ),
-                   outgoing_message );
+void EncodeConnectedDataItemLength(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
+  AddIntToMessage((EipUint16) (message_router_response->message.used_message_length + 4 + 2 /* TODO: Magic numbers */
+  + (2 * message_router_response->size_of_additional_status)), outgoing_message);
 }
 
 /**
@@ -437,12 +337,8 @@ void EncodeConnectedDataItemLength(
  * @param common_packet_format_data_item
  * @param outgoing_message The outgoing message object
  */
-void EncodeSequenceNumber(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
-  AddIntToMessage(
-     (EipUint16) common_packet_format_data_item->address_item.data.sequence_number,
-    outgoing_message );
+void EncodeSequenceNumber(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
+  AddIntToMessage((EipUint16) common_packet_format_data_item->address_item.data.sequence_number, outgoing_message);
 }
 
 /**
@@ -451,9 +347,7 @@ void EncodeSequenceNumber(
  * @param message_router_response The router response message data structure to be processed
  * @param outgoing_message The outgoing message object
  */
-void EncodeReplyService(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
+void EncodeReplyService(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
   AddSintToMessage(message_router_response->reply_service, outgoing_message);
 }
 
@@ -463,9 +357,7 @@ void EncodeReplyService(
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
  */
-void EncodeReservedFieldOfLengthByte(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
+void EncodeReservedFieldOfLengthByte(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
   AddSintToMessage(message_router_response->reserved, outgoing_message);
 }
 
@@ -475,9 +367,7 @@ void EncodeReservedFieldOfLengthByte(
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
  */
-void EncodeGeneralStatus(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
+void EncodeGeneralStatus(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
   AddSintToMessage(message_router_response->general_status, outgoing_message);
 }
 
@@ -488,11 +378,8 @@ void EncodeGeneralStatus(
  * @param outgoing_message The outgoing message object
  */
 
-void EncodeExtendedStatusLength(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
-  AddSintToMessage(message_router_response->size_of_additional_status,
-                   outgoing_message);
+void EncodeExtendedStatusLength(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
+  AddSintToMessage(message_router_response->size_of_additional_status, outgoing_message);
 }
 
 /**
@@ -501,14 +388,9 @@ void EncodeExtendedStatusLength(
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
  */
-void EncodeExtendedStatusDataItems(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
-  for(size_t i = 0;
-      i < message_router_response->size_of_additional_status &&
-      i < MAX_SIZE_OF_ADD_STATUS; i++) {
-    AddIntToMessage(message_router_response->additional_status[i],
-                    outgoing_message);
+void EncodeExtendedStatusDataItems(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
+  for(size_t i = 0; i < message_router_response->size_of_additional_status && i < MAX_SIZE_OF_ADD_STATUS; i++) {
+    AddIntToMessage(message_router_response->additional_status[i], outgoing_message);
   }
 }
 
@@ -522,9 +404,7 @@ void EncodeExtendedStatusDataItems(
  * @param outgoing_message The outgoing message object
  */
 
-void EncodeExtendedStatus(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
+void EncodeExtendedStatus(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
   EncodeExtendedStatusLength(message_router_response, outgoing_message);
   EncodeExtendedStatusDataItems(message_router_response, outgoing_message);
 }
@@ -536,15 +416,9 @@ void EncodeExtendedStatus(
  * @param outgoing_message The outgoing message object
  *
  */
-void EncodeUnconnectedDataItemLength(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
-  AddIntToMessage( (EipUint16) (message_router_response->message.
-                                used_message_length + 4                                 /* TODO: Magic number */
-                                + (2 *
-                                   message_router_response->
-                                   size_of_additional_status) ),
-                   outgoing_message );
+void EncodeUnconnectedDataItemLength(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
+  AddIntToMessage((EipUint16) (message_router_response->message.used_message_length + 4 /* TODO: Magic number */
+  + (2 * message_router_response->size_of_additional_status)), outgoing_message);
 }
 
 /**
@@ -553,17 +427,11 @@ void EncodeUnconnectedDataItemLength(
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
  */
-void EncodeMessageRouterResponseData(
-  const CipMessageRouterResponse *const message_router_response,
-  ENIPMessage *const outgoing_message) {
-  memcpy(outgoing_message->current_message_position,
-         message_router_response->message.message_buffer,
-         message_router_response->message.used_message_length);
-
-  outgoing_message->current_message_position +=
-    message_router_response->message.used_message_length;
-  outgoing_message->used_message_length +=
-    message_router_response->message.used_message_length;
+void EncodeMessageRouterResponseData(const CipMessageRouterResponse *const message_router_response, ENIPMessage *const outgoing_message) {
+  memcpy(outgoing_message->current_message_position, message_router_response->message.message_buffer, message_router_response->message.used_message_length);
+
+  outgoing_message->current_message_position += message_router_response->message.used_message_length;
+  outgoing_message->used_message_length += message_router_response->message.used_message_length;
 }
 
 /**
@@ -573,13 +441,9 @@ void EncodeMessageRouterResponseData(
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
  */
-void EncodeSockaddrInfoItemTypeId(int item_type,
-                                  const CipCommonPacketFormatData *const common_packet_format_data_item,
-                                  ENIPMessage *const outgoing_message) {
+void EncodeSockaddrInfoItemTypeId(int item_type, const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
   OPENER_ASSERT(item_type == 0 || item_type == 1);
-  AddIntToMessage(
-    common_packet_format_data_item->address_info_item[item_type].type_id,
-    outgoing_message);
+  AddIntToMessage(common_packet_format_data_item->address_info_item[item_type].type_id, outgoing_message);
 }
 
 /**
@@ -589,18 +453,12 @@ void EncodeSockaddrInfoItemTypeId(int item_type,
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
  */
-void EncodeSockaddrInfoLength(int item_type,
-                              const CipCommonPacketFormatData *const common_packet_format_data_item,
-                              ENIPMessage *const outgoing_message) {
-  AddIntToMessage(
-    common_packet_format_data_item->address_info_item[item_type].length,
-    outgoing_message);
+void EncodeSockaddrInfoLength(int item_type, const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
+  AddIntToMessage(common_packet_format_data_item->address_info_item[item_type].length, outgoing_message);
 }
 
-EipStatus AssembleLinearMessage(
-  const CipMessageRouterResponse *const message_router_response,
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
+EipStatus AssembleLinearMessage(const CipMessageRouterResponse *const message_router_response,
+    const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
 
   if(message_router_response) {
     /* add Interface Handle and Timeout = 0 -> only for SendRRData and SendUnitData necessary */
@@ -611,19 +469,17 @@ EipStatus AssembleLinearMessage(
   EncodeItemCount(common_packet_format_data_item, outgoing_message);
 
   /* process Address Item */
-  switch(common_packet_format_data_item->address_item.type_id) {
+  switch(common_packet_format_data_item->address_item.type_id){
     case kCipItemIdNullAddress: {
       EncodeNullAddressItem(outgoing_message);
       break;
     }
     case kCipItemIdConnectionAddress: {
-      EncodeConnectedAddressItem(common_packet_format_data_item,
-                                 outgoing_message);
+      EncodeConnectedAddressItem(common_packet_format_data_item, outgoing_message);
       break;
     }
     case kCipItemIdSequencedAddressItem: {
-      EncodeSequencedAddressItem(common_packet_format_data_item,
-                                 outgoing_message);
+      EncodeSequencedAddressItem(common_packet_format_data_item, outgoing_message);
       break;
     }
     default:
@@ -632,34 +488,26 @@ EipStatus AssembleLinearMessage(
   }
 
   /* process Data Item */
-  if( (common_packet_format_data_item->data_item.type_id ==
-       kCipItemIdUnconnectedDataItem)
-      || (common_packet_format_data_item->data_item.type_id ==
-          kCipItemIdConnectedDataItem) ) {
+  if((common_packet_format_data_item->data_item.type_id == kCipItemIdUnconnectedDataItem)
+    || (common_packet_format_data_item->data_item.type_id == kCipItemIdConnectedDataItem)) {
 
     if(message_router_response) {
       EncodeDataItemType(common_packet_format_data_item, outgoing_message);
 
-      if(common_packet_format_data_item->data_item.type_id ==
-         kCipItemIdConnectedDataItem) {                                                      /* Connected Item */
-        EncodeConnectedDataItemLength(message_router_response,
-                                      outgoing_message);
-        EncodeSequenceNumber(&g_common_packet_format_data_item,
-                             outgoing_message);
+      if(common_packet_format_data_item->data_item.type_id == kCipItemIdConnectedDataItem) { /* Connected Item */
+        EncodeConnectedDataItemLength(message_router_response, outgoing_message);
+        EncodeSequenceNumber(&g_common_packet_format_data_item, outgoing_message);
 
       } else { /* Unconnected Item */
-        EncodeUnconnectedDataItemLength(message_router_response,
-                                        outgoing_message);
+        EncodeUnconnectedDataItemLength(message_router_response, outgoing_message);
       }
 
       /* write message router response into linear memory */
       EncodeReplyService(message_router_response, outgoing_message);
-      EncodeReservedFieldOfLengthByte(message_router_response,
-                                      outgoing_message);
+      EncodeReservedFieldOfLengthByte(message_router_response, outgoing_message);
       EncodeGeneralStatus(message_router_response, outgoing_message);
       EncodeExtendedStatus(message_router_response, outgoing_message);
-      EncodeMessageRouterResponseData(message_router_response,
-                                      outgoing_message);
+      EncodeMessageRouterResponseData(message_router_response, outgoing_message);
     } else { /* connected IO Message to send */
       EncodeDataItemType(common_packet_format_data_item, outgoing_message);
 
@@ -674,26 +522,17 @@ EipStatus AssembleLinearMessage(
    * EtherNet/IP specification doesn't demand it, but there are EIP
    * devices which depend on CPF items to appear in the order of their
    * ID number */
-  for(int type = kCipItemIdSocketAddressInfoOriginatorToTarget;
-      type <= kCipItemIdSocketAddressInfoTargetToOriginator; type++) {
+  for(int type = kCipItemIdSocketAddressInfoOriginatorToTarget; type <= kCipItemIdSocketAddressInfoTargetToOriginator; type++) {
     for(int j = 0; j < 2; j++) {
       if(common_packet_format_data_item->address_info_item[j].type_id == type) {
-        EncodeSockaddrInfoItemTypeId(j,
-                                     common_packet_format_data_item,
-                                     outgoing_message);
+        EncodeSockaddrInfoItemTypeId(j, common_packet_format_data_item, outgoing_message);
 
-        EncodeSockaddrInfoLength(j,
-                                 common_packet_format_data_item,
-                                 outgoing_message);
+        EncodeSockaddrInfoLength(j, common_packet_format_data_item, outgoing_message);
 
-        EncapsulateIpAddress(
-          common_packet_format_data_item->address_info_item[j].sin_port,
-          common_packet_format_data_item->address_info_item[j].sin_addr,
+        EncapsulateIpAddress(common_packet_format_data_item->address_info_item[j].sin_port, common_packet_format_data_item->address_info_item[j].sin_addr,
           outgoing_message);
 
-        FillNextNMessageOctetsWithValueAndMoveToNextPosition(0,
-                                                             8,
-                                                             outgoing_message);
+        FillNextNMessageOctetsWithValueAndMoveToNextPosition(0, 8, outgoing_message);
         break;
       }
     }
@@ -701,8 +540,6 @@ EipStatus AssembleLinearMessage(
   return kEipStatusOk;
 }
 
-void AssembleIOMessage(
-  const CipCommonPacketFormatData *const common_packet_format_data_item,
-  ENIPMessage *const outgoing_message) {
+void AssembleIOMessage(const CipCommonPacketFormatData *const common_packet_format_data_item, ENIPMessage *const outgoing_message) {
   AssembleLinearMessage(0, common_packet_format_data_item, outgoing_message);
 }

+ 9 - 0
source/src/enet_encap/encap.c

@@ -749,6 +749,15 @@ EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer,
  */
 SessionStatus CheckRegisteredSessions(
   const EncapsulationData *const receive_data) {
+
+/* Skip the check when fuzzing
+    in order to increase our code coverage 
+    we are simply bypassing all the session checks
+*/
+#ifdef FUZZING_AFL
+  return kSessionStatusValid;
+#endif
+
   if( (0 < receive_data->session_handle) && (receive_data->session_handle <=
                                              OPENER_NUMBER_OF_SUPPORTED_SESSIONS) )
   {

+ 7 - 0
source/src/ports/POSIX/CMakeLists.txt

@@ -12,6 +12,13 @@ if(OpENer_RT)
   add_definitions(-DOPENER_RT_THREAD_SIZE=${OpENer_RT_Additional_Stacksize})
 endif(OpENer_RT)
 
+#######################################
+# AFL Fuzzing                         #
+#######################################
+if(USE_FUZZ_AFL)
+  add_definitions( -DFUZZING_AFL )
+endif(USE_FUZZ_AFL)
+
 #######################################
 # Add common includes                 #
 #######################################

+ 39 - 0
source/src/ports/POSIX/main.c

@@ -6,6 +6,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <unistd.h>
 #include <sys/capability.h>
 
 #ifdef OPENER_RT
@@ -50,6 +51,12 @@ static void LeaveStack(int signal);
  */
 static void *executeEventLoop(void *pthread_arg);
 
+/******************************************************************************/
+/** @brief Fuzz TCP packets handling flow with AFL.
+ *
+ */
+static void fuzzHandlePacketFlow(void);
+
 /*****************************************************************************/
 /** @brief Flag indicating if the stack should end its execution
  */
@@ -127,6 +134,12 @@ int main(int argc,
    */
   GetHostName(&g_tcpip.hostname);
 
+  /* Fuzzing UDP/TCP handle packet flow */
+#ifdef FUZZING_AFL
+  fuzzHandlePacketFlow();
+  return EXIT_SUCCESS;
+#endif 
+
   /* The CIP objects are now created and initialized with their default values.
    *  After that any NV data values are loaded to change the attribute contents
    *  to the stored configuration.
@@ -277,3 +290,29 @@ static void *executeEventLoop(void *pthread_arg) {
 
   return &pthread_dummy_ret;
 }
+
+static void fuzzHandlePacketFlow(void) {
+#ifdef FUZZING_AFL
+  int socket_fd = 0;   // Fake socket fd
+  uint8_t buff[512];   // Input buffer
+  struct sockaddr_in from_address = { 0 }; // Fake socket address
+  int remaining_bytes = 0; // Fake reamining bytes
+  ENIPMessage outgoing_message;
+
+  /* AFL persistent mode */
+  while(__AFL_LOOP(100000)) {
+    /* Read input from STDIN and enter the handle receive flow */
+    memset(buff, 0, 512);
+    ssize_t received_size = read(STDIN_FILENO, buff, 512);
+    EipUint8 *receive_buffer = &buff[0];
+
+    InitializeENIPMessage(&outgoing_message);
+
+    // Fuzz UDP
+    //EipStatus need_to_send = HandleReceivedExplictUdpData(socket_fd, &from_address, receive_buffer, received_size, &remaining_bytes, true, &outgoing_message);
+
+    // Fuzz TCP
+    EipStatus need_to_send = HandleReceivedExplictTcpData(socket_fd, receive_buffer, received_size, &remaining_bytes, &from_address, &outgoing_message);
+  }
+#endif
+}

Разница между файлами не показана из-за своего большого размера
+ 206 - 320
source/src/ports/generic_networkhandler.c


Некоторые файлы не были показаны из-за большого количества измененных файлов