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