security_tests.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*******************************************************************************
  2. * Copyright (c) 2025, Martin Melik Merkumians
  3. * All rights reserved.
  4. *
  5. * Security Test Suite for Network Handler
  6. * Tests for buffer overflows, integer overflows, and input validation
  7. * Designed to catch issues with AddressSanitizer and UndefinedBehaviorSanitizer
  8. ******************************************************************************/
  9. #include <CppUTest/TestHarness.h>
  10. #include <CppUTestExt/MockSupport.h>
  11. #include <limits.h>
  12. #include <stdint.h>
  13. #include <string.h>
  14. extern "C" {
  15. #include "core/typedefs.h"
  16. #include "ports/generic_networkhandler.h"
  17. }
  18. TEST_GROUP(NetworkHandlerSecurity){ void setup(){ mock().clear();
  19. }
  20. void teardown() {
  21. mock().clear();
  22. }
  23. }
  24. ;
  25. /**
  26. * Test: Verify socket handle validation against valid range
  27. * Purpose: Prevent out-of-bounds socket array access
  28. * Security: CWE-129 (Improper Validation of Array Index)
  29. */
  30. TEST(NetworkHandlerSecurity, SocketHandleValidation) {
  31. /* Valid socket handles should be non-negative */
  32. EipBool8 result = CheckSocketSet(5);
  33. CHECK(result == true || result == false); /* Should not crash */
  34. }
  35. /**
  36. * Test: Verify handling of maximum socket descriptor value
  37. * Purpose: Prevent integer overflow in socket calculations
  38. * Security: CWE-190 (Integer Overflow)
  39. */
  40. TEST(NetworkHandlerSecurity, MaxSocketBoundary) {
  41. int max_socket = GetMaxSocket(INT_MAX - 1, INT_MAX - 2, INT_MAX - 3, 10);
  42. /* Should handle large values without overflow */
  43. CHECK(max_socket == INT_MAX - 1);
  44. }
  45. /**
  46. * Test: Verify handling of negative socket descriptors
  47. * Purpose: Detect improper handling of invalid socket handles
  48. * Security: CWE-20 (Improper Input Validation)
  49. */
  50. TEST(NetworkHandlerSecurity, NegativeSocketHandle) {
  51. int max_socket = GetMaxSocket(-1, 0, 10, -500);
  52. /* Should handle negatives gracefully */
  53. CHECK(max_socket == 10);
  54. }
  55. /**
  56. * Test: Verify socket peer address retrieval doesn't overflow
  57. * Purpose: Check peer address retrieval robustness
  58. * Security: CWE-119 (Buffer Overflow)
  59. */
  60. TEST(NetworkHandlerSecurity, PeerAddressRetrieval) {
  61. /* This should not crash even if socket is invalid
  62. * In real scenario, GetPeerAddress() uses g_current_active_tcp_socket */
  63. EipUint32 peer_addr = GetPeerAddress();
  64. CHECK(peer_addr != 0 || peer_addr == 0); /* Any value is acceptable */
  65. }
  66. /**
  67. * Test: Verify large size handling in socket operations
  68. * Purpose: Detect potential integer overflows in buffer size calculations
  69. * Security: CWE-190 (Integer Overflow)
  70. */
  71. TEST(NetworkHandlerSecurity, LargeSizeCalculations) {
  72. /* Verify that operations don't overflow with large sizes */
  73. size_t max_buffer = PC_OPENER_ETHERNET_BUFFER_SIZE;
  74. size_t large_size = max_buffer - 1;
  75. size_t result_size = large_size + 1;
  76. CHECK(result_size == max_buffer);
  77. }
  78. /**
  79. * Test: Verify QoS setting with boundary values
  80. * Purpose: Detect integer conversion issues in QoS handling
  81. * Security: CWE-197 (Numeric Truncation Error)
  82. */
  83. TEST(NetworkHandlerSecurity, QoSBoundaryValues) {
  84. /* Test with boundary CipUsint values */
  85. CipUsint qos_min = 0;
  86. CipUsint qos_max = UINT8_MAX;
  87. /* These should not crash or cause memory issues */
  88. /* Note: Actual SetQos calls would require initialized network status */
  89. CHECK(qos_min >= 0);
  90. CHECK(qos_max <= UINT8_MAX);
  91. }
  92. /**
  93. * Test: Verify multicast TTL value validation
  94. * Purpose: Ensure TTL values are properly validated before socket operations
  95. * Security: CWE-20 (Improper Input Validation)
  96. */
  97. TEST(NetworkHandlerSecurity, MulticastTTLValidation) {
  98. /* TTL should be 0-255 for standard operation */
  99. uint8_t ttl_min = 0;
  100. uint8_t ttl_max = 255;
  101. int ttl_invalid = 256; /* Out of range */
  102. CHECK(ttl_min >= 0 && ttl_min <= 255);
  103. CHECK(ttl_max >= 0 && ttl_max <= 255);
  104. CHECK(ttl_invalid >
  105. 255); /* Should be caught in SetSocketOptionsMulticastProduce */
  106. }
  107. /**
  108. * Test: Verify socket array bounds for timer operations
  109. * Purpose: Prevent out-of-bounds access in socket timer array
  110. * Security: CWE-119 (Buffer Overflow), CWE-129 (Improper Array Index
  111. * Validation)
  112. */
  113. TEST(NetworkHandlerSecurity, SocketTimerArrayBounds) {
  114. extern SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
  115. /* Access within bounds should work */
  116. int valid_index = 0;
  117. SocketTimer* timer = &g_timestamps[valid_index];
  118. CHECK(timer != NULL);
  119. /* Verify array size is reasonable */
  120. CHECK(OPENER_NUMBER_OF_SUPPORTED_SESSIONS > 0);
  121. CHECK(OPENER_NUMBER_OF_SUPPORTED_SESSIONS < 10000); /* Sanity check */
  122. }
  123. /**
  124. * Test: Verify safe casting of socket counts
  125. * Purpose: Detect issues in for-loop bounds with socket iteration
  126. * Security: CWE-190 (Integer Overflow)
  127. */
  128. TEST(NetworkHandlerSecurity, SocketIterationBounds) {
  129. extern int highest_socket_handle;
  130. /* Loop bounds should be reasonable */
  131. int max_iterations = OPENER_NUMBER_OF_SUPPORTED_SESSIONS + 10;
  132. CHECK(max_iterations > 0);
  133. /* Verify no infinite loop potential with max socket handle */
  134. if (highest_socket_handle > 0) {
  135. CHECK(highest_socket_handle <
  136. 100000); /* Sanity limit for file descriptors */
  137. }
  138. }
  139. /**
  140. * Test: Verify timeout calculation doesn't underflow/overflow
  141. * Purpose: Detect issues in encapsulation inactivity timeout calculations
  142. * Security: CWE-190 (Integer Overflow/Underflow)
  143. */
  144. TEST(NetworkHandlerSecurity, TimeoutCalculationBounds) {
  145. extern MilliSeconds g_actual_time;
  146. MilliSeconds large_time = UINT32_MAX - 1000;
  147. MilliSeconds small_time = 1000;
  148. /* Subtraction should not cause underflow */
  149. if (large_time > small_time) {
  150. MilliSeconds diff = large_time - small_time;
  151. CHECK(diff > 0);
  152. }
  153. /* Addition should not overflow */
  154. MilliSeconds result = small_time + 5000;
  155. CHECK(result > small_time);
  156. }
  157. /**
  158. * Test: Verify received data size validation
  159. * Purpose: Detect improper validation of network-received sizes
  160. * Security: CWE-20 (Improper Input Validation), CWE-119 (Buffer Overflow)
  161. */
  162. TEST(NetworkHandlerSecurity, ReceivedSizeValidation) {
  163. /* Simulate various received_size values */
  164. int received_size_zero = 0;
  165. int received_size_valid = 100;
  166. int received_size_max = PC_OPENER_ETHERNET_BUFFER_SIZE;
  167. int received_size_over = PC_OPENER_ETHERNET_BUFFER_SIZE + 100;
  168. /* Zero size should be detected */
  169. CHECK(received_size_zero <= 0);
  170. /* Valid sizes should be within buffer */
  171. CHECK(received_size_valid > 0);
  172. CHECK(received_size_valid <= PC_OPENER_ETHERNET_BUFFER_SIZE);
  173. /* Oversized packets should be detected in real code */
  174. CHECK(received_size_over > PC_OPENER_ETHERNET_BUFFER_SIZE);
  175. }
  176. /**
  177. * Test: Verify encapsulation header offset calculations don't overflow
  178. * Purpose: Detect integer overflow in header parsing calculations
  179. * Security: CWE-190 (Integer Overflow)
  180. */
  181. TEST(NetworkHandlerSecurity, EncapsulationHeaderCalculations) {
  182. /* Typical header length */
  183. size_t header_length = 28; /* Standard ENIP header */
  184. /* Buffer with received data */
  185. size_t buffer_size = 100;
  186. /* Calculate remaining after header */
  187. if (buffer_size > header_length) {
  188. size_t remaining = buffer_size - header_length;
  189. CHECK(remaining > 0);
  190. CHECK(remaining < buffer_size);
  191. }
  192. }
  193. /**
  194. * Test: Verify socket address structure sizes are safe
  195. * Purpose: Ensure no buffer overflow when copying address structures
  196. * Security: CWE-119 (Buffer Overflow)
  197. */
  198. TEST(NetworkHandlerSecurity, SocketAddressStructSafety) {
  199. struct sockaddr_in addr = { .sin_family = AF_INET };
  200. /* Verify structure is reasonable size */
  201. size_t addr_size = sizeof(struct sockaddr_in);
  202. CHECK(addr_size > 0);
  203. CHECK(addr_size < 256); /* Sanity check */
  204. /* Verify family field is properly set */
  205. CHECK(addr.sin_family == AF_INET);
  206. }
  207. /**
  208. * Test: Verify message length fields can't cause overflow
  209. * Purpose: Detect improper handling of untrusted message length fields
  210. * Security: CWE-190 (Integer Overflow), CWE-119 (Buffer Overflow)
  211. */
  212. TEST(NetworkHandlerSecurity, MessageLengthValidation) {
  213. /* Message length from network is untrusted */
  214. uint16_t msg_length_max = UINT16_MAX;
  215. uint16_t buffer_size = PC_OPENER_ETHERNET_BUFFER_SIZE;
  216. /* Code should validate msg_length <= buffer_size */
  217. if (msg_length_max > buffer_size) {
  218. /* This should trigger error handling in real code */
  219. CHECK(msg_length_max > buffer_size);
  220. }
  221. }
  222. /**
  223. * Test: Verify loop termination conditions can't infinite loop
  224. * Purpose: Detect potential infinite loops in packet processing
  225. * Security: CWE-835 (Infinite Loop)
  226. */
  227. TEST(NetworkHandlerSecurity, LoopTerminationConditions) {
  228. /* For loop with highest_socket_handle should terminate */
  229. extern int highest_socket_handle;
  230. int loop_count = 0;
  231. int max_safe_iterations = highest_socket_handle + 10;
  232. /* Ensure reasonable bound */
  233. CHECK(max_safe_iterations > 0);
  234. CHECK(max_safe_iterations < 100000);
  235. }
  236. /**
  237. * Test: Verify pointer dereference safety in session management
  238. * Purpose: Detect null pointer dereference in socket timer operations
  239. * Security: CWE-476 (Null Pointer Dereference)
  240. */
  241. TEST(NetworkHandlerSecurity, SocketTimerNullPointerSafety) {
  242. extern SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
  243. /* Valid access */
  244. SocketTimer* valid_timer = &g_timestamps[0];
  245. CHECK(valid_timer != NULL);
  246. /* Code should check for NULL before dereferencing socket_timer */
  247. SocketTimer* test_timer = NULL;
  248. if (test_timer != NULL) {
  249. /* This should never execute */
  250. SocketTimerGetLastUpdate(test_timer);
  251. }
  252. }
  253. /**
  254. * Test: Verify ASAN detects heap buffer overflow
  255. * Purpose: Ensure AddressSanitizer infrastructure is working
  256. * Security: CWE-119 (Buffer Overflow) - Heap variant
  257. */
  258. TEST(NetworkHandlerSecurity, ASANHeapBufferDetection) {
  259. /* Allocate small buffer */
  260. char* buffer = (char*)malloc(10);
  261. CHECK(buffer != NULL);
  262. /* Write within bounds (ASAN will pass) */
  263. buffer[9] = 'x';
  264. CHECK(buffer[9] == 'x');
  265. /* ASAN would detect out-of-bounds write if uncommented:
  266. * buffer[10] = 'x'; // ASAN detects heap-buffer-overflow */
  267. free(buffer);
  268. }
  269. /**
  270. * Test: Verify ASAN detects use-after-free
  271. * Purpose: Ensure AddressSanitizer infrastructure detects UAF
  272. * Security: CWE-416 (Use After Free)
  273. */
  274. TEST(NetworkHandlerSecurity, ASANUseAfterFreeDetection) {
  275. char* buffer = (char*)malloc(10);
  276. strcpy(buffer, "test");
  277. free(buffer);
  278. /* ASAN would detect use-after-free if uncommented:
  279. * char c = buffer[0]; // ASAN detects heap-use-after-free */
  280. CHECK(true); /* If we got here, ASAN is properly configured */
  281. }
  282. /**
  283. * Test: Verify ASAN detects stack buffer overflow
  284. * Purpose: Ensure AddressSanitizer infrastructure works for stack
  285. * Security: CWE-119 (Buffer Overflow) - Stack variant
  286. */
  287. TEST(NetworkHandlerSecurity, ASANStackBufferDetection) {
  288. char stack_buffer[10] = { 0 };
  289. /* Write within bounds */
  290. stack_buffer[9] = 'x';
  291. CHECK(stack_buffer[9] == 'x');
  292. /* ASAN would detect out-of-bounds write if uncommented:
  293. * stack_buffer[10] = 'x'; // ASAN detects stack-buffer-overflow */
  294. }