1/* BEGIN_HEADER */ 2 3#include "mbedtls/net_sockets.h" 4 5#if defined(unix) || defined(__unix__) || defined(__unix) || \ 6 defined(__APPLE__) || defined(__QNXNTO__) || \ 7 defined(__HAIKU__) || defined(__midipix__) 8#define MBEDTLS_PLATFORM_IS_UNIXLIKE 9#endif 10 11#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) 12#include <sys/resource.h> 13#include <sys/stat.h> 14#include <sys/time.h> 15#include <sys/types.h> 16#include <fcntl.h> 17#include <unistd.h> 18#endif 19 20 21#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) 22/** Open a file on the given file descriptor. 23 * 24 * This is disruptive if there is already something open on that descriptor. 25 * Caller beware. 26 * 27 * \param ctx An initialized, but unopened socket context. 28 * On success, it refers to the opened file (\p wanted_fd). 29 * \param wanted_fd The desired file descriptor. 30 * 31 * \return \c 0 on success, a negative error code on error. 32 */ 33static int open_file_on_fd(mbedtls_net_context *ctx, int wanted_fd) 34{ 35 int got_fd = open("/dev/null", O_RDONLY); 36 TEST_ASSERT(got_fd >= 0); 37 if (got_fd != wanted_fd) { 38 TEST_ASSERT(dup2(got_fd, wanted_fd) >= 0); 39 TEST_ASSERT(close(got_fd) >= 0); 40 } 41 ctx->fd = wanted_fd; 42 return 0; 43exit: 44 return -1; 45} 46#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */ 47 48/* END_HEADER */ 49 50/* BEGIN_DEPENDENCIES 51 * depends_on:MBEDTLS_NET_C 52 * END_DEPENDENCIES 53 */ 54 55/* BEGIN_CASE */ 56void context_init_free(int reinit) 57{ 58 mbedtls_net_context ctx; 59 60 mbedtls_net_init(&ctx); 61 mbedtls_net_free(&ctx); 62 63 if (reinit) { 64 mbedtls_net_init(&ctx); 65 } 66 mbedtls_net_free(&ctx); 67 68 /* This test case always succeeds, functionally speaking. A plausible 69 * bug might trigger an invalid pointer dereference or a memory leak. */ 70 goto exit; 71} 72/* END_CASE */ 73 74/* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */ 75void poll_beyond_fd_setsize() 76{ 77 /* Test that mbedtls_net_poll does not misbehave when given a file 78 * descriptor greater or equal to FD_SETSIZE. This code is specific to 79 * platforms with a Unix-like select() function, which is where 80 * FD_SETSIZE is a concern. */ 81 82 struct rlimit rlim_nofile; 83 int restore_rlim_nofile = 0; 84 int ret; 85 mbedtls_net_context ctx; 86 uint8_t buf[1]; 87 88 mbedtls_net_init(&ctx); 89 90 /* On many systems, by default, the maximum permitted file descriptor 91 * number is less than FD_SETSIZE. If so, raise the limit if 92 * possible. 93 * 94 * If the limit can't be raised, a file descriptor opened by the 95 * net_sockets module will be less than FD_SETSIZE, so the test 96 * is not necessary and we mark it as skipped. 97 * A file descriptor could still be higher than FD_SETSIZE if it was 98 * opened before the limit was lowered (which is something an application 99 * might do); but we don't do such things in our test code, so the unit 100 * test will run if it can. 101 */ 102 TEST_ASSERT(getrlimit(RLIMIT_NOFILE, &rlim_nofile) == 0); 103 if (rlim_nofile.rlim_cur < FD_SETSIZE + 1) { 104 rlim_t old_rlim_cur = rlim_nofile.rlim_cur; 105 rlim_nofile.rlim_cur = FD_SETSIZE + 1; 106 TEST_ASSUME(setrlimit(RLIMIT_NOFILE, &rlim_nofile) == 0); 107 rlim_nofile.rlim_cur = old_rlim_cur; 108 restore_rlim_nofile = 1; 109 } 110 111 TEST_ASSERT(open_file_on_fd(&ctx, FD_SETSIZE) == 0); 112 113 /* In principle, mbedtls_net_poll() with valid arguments should succeed. 114 * However, we know that on Unix-like platforms (and others), this function 115 * is implemented on top of select() and fd_set, which do not support 116 * file descriptors greater or equal to FD_SETSIZE. So we expect to hit 117 * this platform limitation. 118 * 119 * If mbedtls_net_poll() does not proprely check that ctx.fd is in range, 120 * it may still happen to return the expected failure code, but if this 121 * is problematic on the particular platform where the code is running, 122 * a memory sanitizer such as UBSan should catch it. 123 */ 124 ret = mbedtls_net_poll(&ctx, MBEDTLS_NET_POLL_READ, 0); 125 TEST_EQUAL(ret, MBEDTLS_ERR_NET_POLL_FAILED); 126 127 /* mbedtls_net_recv_timeout() uses select() and fd_set in the same way. */ 128 ret = mbedtls_net_recv_timeout(&ctx, buf, sizeof(buf), 0); 129 TEST_EQUAL(ret, MBEDTLS_ERR_NET_POLL_FAILED); 130 131exit: 132 mbedtls_net_free(&ctx); 133 if (restore_rlim_nofile) { 134 setrlimit(RLIMIT_NOFILE, &rlim_nofile); 135 } 136} 137/* END_CASE */ 138