|  | /* BEGIN_HEADER */ | 
|  |  | 
|  | #include "mbedtls/net_sockets.h" | 
|  |  | 
|  | #if defined(unix) || defined(__unix__) || defined(__unix) || \ | 
|  | defined(__APPLE__) || defined(__QNXNTO__) || \ | 
|  | defined(__HAIKU__) || defined(__midipix__) | 
|  | #define MBEDTLS_PLATFORM_IS_UNIXLIKE | 
|  | #endif | 
|  |  | 
|  | #if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) | 
|  | #include <sys/resource.h> | 
|  | #include <sys/stat.h> | 
|  | #include <sys/time.h> | 
|  | #include <sys/types.h> | 
|  | #include <fcntl.h> | 
|  | #include <unistd.h> | 
|  | #endif | 
|  |  | 
|  |  | 
|  | #if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) | 
|  | /** Open a file on the given file descriptor. | 
|  | * | 
|  | * This is disruptive if there is already something open on that descriptor. | 
|  | * Caller beware. | 
|  | * | 
|  | * \param ctx           An initialized, but unopened socket context. | 
|  | *                      On success, it refers to the opened file (\p wanted_fd). | 
|  | * \param wanted_fd     The desired file descriptor. | 
|  | * | 
|  | * \return              \c 0 on success, a negative error code on error. | 
|  | */ | 
|  | static int open_file_on_fd(mbedtls_net_context *ctx, int wanted_fd) | 
|  | { | 
|  | int got_fd = open("/dev/null", O_RDONLY); | 
|  | TEST_ASSERT(got_fd >= 0); | 
|  | if (got_fd != wanted_fd) { | 
|  | TEST_ASSERT(dup2(got_fd, wanted_fd) >= 0); | 
|  | TEST_ASSERT(close(got_fd) >= 0); | 
|  | } | 
|  | ctx->fd = wanted_fd; | 
|  | return 0; | 
|  | exit: | 
|  | return -1; | 
|  | } | 
|  | #endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */ | 
|  |  | 
|  | /* END_HEADER */ | 
|  |  | 
|  | /* BEGIN_DEPENDENCIES | 
|  | * depends_on:MBEDTLS_NET_C | 
|  | * END_DEPENDENCIES | 
|  | */ | 
|  |  | 
|  | /* BEGIN_CASE */ | 
|  | void context_init_free(int reinit) | 
|  | { | 
|  | mbedtls_net_context ctx; | 
|  |  | 
|  | mbedtls_net_init(&ctx); | 
|  | mbedtls_net_free(&ctx); | 
|  |  | 
|  | if (reinit) { | 
|  | mbedtls_net_init(&ctx); | 
|  | } | 
|  | mbedtls_net_free(&ctx); | 
|  |  | 
|  | /* This test case always succeeds, functionally speaking. A plausible | 
|  | * bug might trigger an invalid pointer dereference or a memory leak. */ | 
|  | goto exit; | 
|  | } | 
|  | /* END_CASE */ | 
|  |  | 
|  | /* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */ | 
|  | void poll_beyond_fd_setsize() | 
|  | { | 
|  | /* Test that mbedtls_net_poll does not misbehave when given a file | 
|  | * descriptor greater or equal to FD_SETSIZE. This code is specific to | 
|  | * platforms with a Unix-like select() function, which is where | 
|  | * FD_SETSIZE is a concern. */ | 
|  |  | 
|  | struct rlimit rlim_nofile; | 
|  | int restore_rlim_nofile = 0; | 
|  | int ret; | 
|  | mbedtls_net_context ctx; | 
|  | uint8_t buf[1]; | 
|  |  | 
|  | mbedtls_net_init(&ctx); | 
|  |  | 
|  | /* On many systems, by default, the maximum permitted file descriptor | 
|  | * number is less than FD_SETSIZE. If so, raise the limit if | 
|  | * possible. | 
|  | * | 
|  | * If the limit can't be raised, a file descriptor opened by the | 
|  | * net_sockets module will be less than FD_SETSIZE, so the test | 
|  | * is not necessary and we mark it as skipped. | 
|  | * A file descriptor could still be higher than FD_SETSIZE if it was | 
|  | * opened before the limit was lowered (which is something an application | 
|  | * might do); but we don't do such things in our test code, so the unit | 
|  | * test will run if it can. | 
|  | */ | 
|  | TEST_ASSERT(getrlimit(RLIMIT_NOFILE, &rlim_nofile) == 0); | 
|  | if (rlim_nofile.rlim_cur < FD_SETSIZE + 1) { | 
|  | rlim_t old_rlim_cur = rlim_nofile.rlim_cur; | 
|  | rlim_nofile.rlim_cur = FD_SETSIZE + 1; | 
|  | TEST_ASSUME(setrlimit(RLIMIT_NOFILE, &rlim_nofile) == 0); | 
|  | rlim_nofile.rlim_cur = old_rlim_cur; | 
|  | restore_rlim_nofile = 1; | 
|  | } | 
|  |  | 
|  | TEST_ASSERT(open_file_on_fd(&ctx, FD_SETSIZE) == 0); | 
|  |  | 
|  | /* In principle, mbedtls_net_poll() with valid arguments should succeed. | 
|  | * However, we know that on Unix-like platforms (and others), this function | 
|  | * is implemented on top of select() and fd_set, which do not support | 
|  | * file descriptors greater or equal to FD_SETSIZE. So we expect to hit | 
|  | * this platform limitation. | 
|  | * | 
|  | * If mbedtls_net_poll() does not proprely check that ctx.fd is in range, | 
|  | * it may still happen to return the expected failure code, but if this | 
|  | * is problematic on the particular platform where the code is running, | 
|  | * a memory sanitizer such as UBSan should catch it. | 
|  | */ | 
|  | ret = mbedtls_net_poll(&ctx, MBEDTLS_NET_POLL_READ, 0); | 
|  | TEST_EQUAL(ret, MBEDTLS_ERR_NET_POLL_FAILED); | 
|  |  | 
|  | /* mbedtls_net_recv_timeout() uses select() and fd_set in the same way. */ | 
|  | ret = mbedtls_net_recv_timeout(&ctx, buf, sizeof(buf), 0); | 
|  | TEST_EQUAL(ret, MBEDTLS_ERR_NET_POLL_FAILED); | 
|  |  | 
|  | exit: | 
|  | mbedtls_net_free(&ctx); | 
|  | if (restore_rlim_nofile) { | 
|  | setrlimit(RLIMIT_NOFILE, &rlim_nofile); | 
|  | } | 
|  | } | 
|  | /* END_CASE */ |