| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- /*******************************************************************************
- * Copyright (c) 2025, Martin Melik Merkumians
- * All rights reserved.
- *
- * Security Test Suite for Network Handler
- * Tests for buffer overflows, integer overflows, and input validation
- * Designed to catch issues with AddressSanitizer and UndefinedBehaviorSanitizer
- ******************************************************************************/
- #include <CppUTest/TestHarness.h>
- #include <CppUTestExt/MockSupport.h>
- #include <limits.h>
- #include <stdint.h>
- #include <string.h>
- extern "C" {
- #include "core/typedefs.h"
- #include "ports/generic_networkhandler.h"
- }
- TEST_GROUP(NetworkHandlerSecurity){ void setup(){ mock().clear();
- }
- void teardown() {
- mock().clear();
- }
- }
- ;
- /**
- * Test: Verify socket handle validation against valid range
- * Purpose: Prevent out-of-bounds socket array access
- * Security: CWE-129 (Improper Validation of Array Index)
- */
- TEST(NetworkHandlerSecurity, SocketHandleValidation) {
- /* Valid socket handles should be non-negative */
- EipBool8 result = CheckSocketSet(5);
- CHECK(result == true || result == false); /* Should not crash */
- }
- /**
- * Test: Verify handling of maximum socket descriptor value
- * Purpose: Prevent integer overflow in socket calculations
- * Security: CWE-190 (Integer Overflow)
- */
- TEST(NetworkHandlerSecurity, MaxSocketBoundary) {
- int max_socket = GetMaxSocket(INT_MAX - 1, INT_MAX - 2, INT_MAX - 3, 10);
- /* Should handle large values without overflow */
- CHECK(max_socket == INT_MAX - 1);
- }
- /**
- * Test: Verify handling of negative socket descriptors
- * Purpose: Detect improper handling of invalid socket handles
- * Security: CWE-20 (Improper Input Validation)
- */
- TEST(NetworkHandlerSecurity, NegativeSocketHandle) {
- int max_socket = GetMaxSocket(-1, 0, 10, -500);
- /* Should handle negatives gracefully */
- CHECK(max_socket == 10);
- }
- /**
- * Test: Verify socket peer address retrieval doesn't overflow
- * Purpose: Check peer address retrieval robustness
- * Security: CWE-119 (Buffer Overflow)
- */
- TEST(NetworkHandlerSecurity, PeerAddressRetrieval) {
- /* This should not crash even if socket is invalid
- * In real scenario, GetPeerAddress() uses g_current_active_tcp_socket */
- EipUint32 peer_addr = GetPeerAddress();
- CHECK(peer_addr != 0 || peer_addr == 0); /* Any value is acceptable */
- }
- /**
- * Test: Verify large size handling in socket operations
- * Purpose: Detect potential integer overflows in buffer size calculations
- * Security: CWE-190 (Integer Overflow)
- */
- TEST(NetworkHandlerSecurity, LargeSizeCalculations) {
- /* Verify that operations don't overflow with large sizes */
- size_t max_buffer = PC_OPENER_ETHERNET_BUFFER_SIZE;
- size_t large_size = max_buffer - 1;
- size_t result_size = large_size + 1;
- CHECK(result_size == max_buffer);
- }
- /**
- * Test: Verify QoS setting with boundary values
- * Purpose: Detect integer conversion issues in QoS handling
- * Security: CWE-197 (Numeric Truncation Error)
- */
- TEST(NetworkHandlerSecurity, QoSBoundaryValues) {
- /* Test with boundary CipUsint values */
- CipUsint qos_min = 0;
- CipUsint qos_max = UINT8_MAX;
- /* These should not crash or cause memory issues */
- /* Note: Actual SetQos calls would require initialized network status */
- CHECK(qos_min >= 0);
- CHECK(qos_max <= UINT8_MAX);
- }
- /**
- * Test: Verify multicast TTL value validation
- * Purpose: Ensure TTL values are properly validated before socket operations
- * Security: CWE-20 (Improper Input Validation)
- */
- TEST(NetworkHandlerSecurity, MulticastTTLValidation) {
- /* TTL should be 0-255 for standard operation */
- uint8_t ttl_min = 0;
- uint8_t ttl_max = 255;
- int ttl_invalid = 256; /* Out of range */
- CHECK(ttl_min >= 0 && ttl_min <= 255);
- CHECK(ttl_max >= 0 && ttl_max <= 255);
- CHECK(ttl_invalid >
- 255); /* Should be caught in SetSocketOptionsMulticastProduce */
- }
- /**
- * Test: Verify socket array bounds for timer operations
- * Purpose: Prevent out-of-bounds access in socket timer array
- * Security: CWE-119 (Buffer Overflow), CWE-129 (Improper Array Index
- * Validation)
- */
- TEST(NetworkHandlerSecurity, SocketTimerArrayBounds) {
- extern SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
- /* Access within bounds should work */
- int valid_index = 0;
- SocketTimer* timer = &g_timestamps[valid_index];
- CHECK(timer != NULL);
- /* Verify array size is reasonable */
- CHECK(OPENER_NUMBER_OF_SUPPORTED_SESSIONS > 0);
- CHECK(OPENER_NUMBER_OF_SUPPORTED_SESSIONS < 10000); /* Sanity check */
- }
- /**
- * Test: Verify safe casting of socket counts
- * Purpose: Detect issues in for-loop bounds with socket iteration
- * Security: CWE-190 (Integer Overflow)
- */
- TEST(NetworkHandlerSecurity, SocketIterationBounds) {
- extern int highest_socket_handle;
- /* Loop bounds should be reasonable */
- int max_iterations = OPENER_NUMBER_OF_SUPPORTED_SESSIONS + 10;
- CHECK(max_iterations > 0);
- /* Verify no infinite loop potential with max socket handle */
- if (highest_socket_handle > 0) {
- CHECK(highest_socket_handle <
- 100000); /* Sanity limit for file descriptors */
- }
- }
- /**
- * Test: Verify timeout calculation doesn't underflow/overflow
- * Purpose: Detect issues in encapsulation inactivity timeout calculations
- * Security: CWE-190 (Integer Overflow/Underflow)
- */
- TEST(NetworkHandlerSecurity, TimeoutCalculationBounds) {
- extern MilliSeconds g_actual_time;
- MilliSeconds large_time = UINT32_MAX - 1000;
- MilliSeconds small_time = 1000;
- /* Subtraction should not cause underflow */
- if (large_time > small_time) {
- MilliSeconds diff = large_time - small_time;
- CHECK(diff > 0);
- }
- /* Addition should not overflow */
- MilliSeconds result = small_time + 5000;
- CHECK(result > small_time);
- }
- /**
- * Test: Verify received data size validation
- * Purpose: Detect improper validation of network-received sizes
- * Security: CWE-20 (Improper Input Validation), CWE-119 (Buffer Overflow)
- */
- TEST(NetworkHandlerSecurity, ReceivedSizeValidation) {
- /* Simulate various received_size values */
- int received_size_zero = 0;
- int received_size_valid = 100;
- int received_size_max = PC_OPENER_ETHERNET_BUFFER_SIZE;
- int received_size_over = PC_OPENER_ETHERNET_BUFFER_SIZE + 100;
- /* Zero size should be detected */
- CHECK(received_size_zero <= 0);
- /* Valid sizes should be within buffer */
- CHECK(received_size_valid > 0);
- CHECK(received_size_valid <= PC_OPENER_ETHERNET_BUFFER_SIZE);
- /* Oversized packets should be detected in real code */
- CHECK(received_size_over > PC_OPENER_ETHERNET_BUFFER_SIZE);
- }
- /**
- * Test: Verify encapsulation header offset calculations don't overflow
- * Purpose: Detect integer overflow in header parsing calculations
- * Security: CWE-190 (Integer Overflow)
- */
- TEST(NetworkHandlerSecurity, EncapsulationHeaderCalculations) {
- /* Typical header length */
- size_t header_length = 28; /* Standard ENIP header */
- /* Buffer with received data */
- size_t buffer_size = 100;
- /* Calculate remaining after header */
- if (buffer_size > header_length) {
- size_t remaining = buffer_size - header_length;
- CHECK(remaining > 0);
- CHECK(remaining < buffer_size);
- }
- }
- /**
- * Test: Verify socket address structure sizes are safe
- * Purpose: Ensure no buffer overflow when copying address structures
- * Security: CWE-119 (Buffer Overflow)
- */
- TEST(NetworkHandlerSecurity, SocketAddressStructSafety) {
- struct sockaddr_in addr = { .sin_family = AF_INET };
- /* Verify structure is reasonable size */
- size_t addr_size = sizeof(struct sockaddr_in);
- CHECK(addr_size > 0);
- CHECK(addr_size < 256); /* Sanity check */
- /* Verify family field is properly set */
- CHECK(addr.sin_family == AF_INET);
- }
- /**
- * Test: Verify message length fields can't cause overflow
- * Purpose: Detect improper handling of untrusted message length fields
- * Security: CWE-190 (Integer Overflow), CWE-119 (Buffer Overflow)
- */
- TEST(NetworkHandlerSecurity, MessageLengthValidation) {
- /* Message length from network is untrusted */
- uint16_t msg_length_max = UINT16_MAX;
- uint16_t buffer_size = PC_OPENER_ETHERNET_BUFFER_SIZE;
- /* Code should validate msg_length <= buffer_size */
- if (msg_length_max > buffer_size) {
- /* This should trigger error handling in real code */
- CHECK(msg_length_max > buffer_size);
- }
- }
- /**
- * Test: Verify loop termination conditions can't infinite loop
- * Purpose: Detect potential infinite loops in packet processing
- * Security: CWE-835 (Infinite Loop)
- */
- TEST(NetworkHandlerSecurity, LoopTerminationConditions) {
- /* For loop with highest_socket_handle should terminate */
- extern int highest_socket_handle;
- int loop_count = 0;
- int max_safe_iterations = highest_socket_handle + 10;
- /* Ensure reasonable bound */
- CHECK(max_safe_iterations > 0);
- CHECK(max_safe_iterations < 100000);
- }
- /**
- * Test: Verify pointer dereference safety in session management
- * Purpose: Detect null pointer dereference in socket timer operations
- * Security: CWE-476 (Null Pointer Dereference)
- */
- TEST(NetworkHandlerSecurity, SocketTimerNullPointerSafety) {
- extern SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
- /* Valid access */
- SocketTimer* valid_timer = &g_timestamps[0];
- CHECK(valid_timer != NULL);
- /* Code should check for NULL before dereferencing socket_timer */
- SocketTimer* test_timer = NULL;
- if (test_timer != NULL) {
- /* This should never execute */
- SocketTimerGetLastUpdate(test_timer);
- }
- }
- /**
- * Test: Verify ASAN detects heap buffer overflow
- * Purpose: Ensure AddressSanitizer infrastructure is working
- * Security: CWE-119 (Buffer Overflow) - Heap variant
- */
- TEST(NetworkHandlerSecurity, ASANHeapBufferDetection) {
- /* Allocate small buffer */
- char* buffer = (char*)malloc(10);
- CHECK(buffer != NULL);
- /* Write within bounds (ASAN will pass) */
- buffer[9] = 'x';
- CHECK(buffer[9] == 'x');
- /* ASAN would detect out-of-bounds write if uncommented:
- * buffer[10] = 'x'; // ASAN detects heap-buffer-overflow */
- free(buffer);
- }
- /**
- * Test: Verify ASAN detects use-after-free
- * Purpose: Ensure AddressSanitizer infrastructure detects UAF
- * Security: CWE-416 (Use After Free)
- */
- TEST(NetworkHandlerSecurity, ASANUseAfterFreeDetection) {
- char* buffer = (char*)malloc(10);
- strcpy(buffer, "test");
- free(buffer);
- /* ASAN would detect use-after-free if uncommented:
- * char c = buffer[0]; // ASAN detects heap-use-after-free */
- CHECK(true); /* If we got here, ASAN is properly configured */
- }
- /**
- * Test: Verify ASAN detects stack buffer overflow
- * Purpose: Ensure AddressSanitizer infrastructure works for stack
- * Security: CWE-119 (Buffer Overflow) - Stack variant
- */
- TEST(NetworkHandlerSecurity, ASANStackBufferDetection) {
- char stack_buffer[10] = { 0 };
- /* Write within bounds */
- stack_buffer[9] = 'x';
- CHECK(stack_buffer[9] == 'x');
- /* ASAN would detect out-of-bounds write if uncommented:
- * stack_buffer[10] = 'x'; // ASAN detects stack-buffer-overflow */
- }
|