1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 Linaro Ltd.
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci * Failure tests.
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci#include <unistd.h>
9f08c3bdfSopenharmony_ci#include <errno.h>
10f08c3bdfSopenharmony_ci#include <stdlib.h>
11f08c3bdfSopenharmony_ci#include <sys/time.h>
12f08c3bdfSopenharmony_ci#include <sys/types.h>
13f08c3bdfSopenharmony_ci#include <sys/wait.h>
14f08c3bdfSopenharmony_ci#include <fcntl.h>
15f08c3bdfSopenharmony_ci#include "select_var.h"
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_cistatic fd_set readfds_reg, writefds_reg, fds_closed;
18f08c3bdfSopenharmony_cistatic fd_set *preadfds_reg = &readfds_reg, *pwritefds_reg = &writefds_reg;
19f08c3bdfSopenharmony_cistatic fd_set *pfds_closed = &fds_closed, *nullfds = NULL, *faulty_fds;
20f08c3bdfSopenharmony_cistatic int fd_closed, fd[2];
21f08c3bdfSopenharmony_cistatic int negative_nfds = -1, maxfds;
22f08c3bdfSopenharmony_cistatic struct timeval timeout = {.tv_sec = 0, .tv_usec = 100000};
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_cistatic struct timeval *valid_to = &timeout, *invalid_to;
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_cistatic struct tcases {
27f08c3bdfSopenharmony_ci	char *name;
28f08c3bdfSopenharmony_ci	int *nfds;
29f08c3bdfSopenharmony_ci	fd_set **readfds;
30f08c3bdfSopenharmony_ci	fd_set **writefds;
31f08c3bdfSopenharmony_ci	fd_set **exceptfds;
32f08c3bdfSopenharmony_ci	struct timeval **timeout;
33f08c3bdfSopenharmony_ci	int exp_errno;
34f08c3bdfSopenharmony_ci} tests[] = {
35f08c3bdfSopenharmony_ci	{ "Negative nfds", &negative_nfds, &preadfds_reg, &pwritefds_reg, &nullfds, &valid_to, EINVAL },
36f08c3bdfSopenharmony_ci	{ "Invalid readfds", &maxfds, &pfds_closed, &pwritefds_reg, &nullfds, &valid_to, EBADF },
37f08c3bdfSopenharmony_ci	{ "Invalid writefds", &maxfds, &preadfds_reg, &pfds_closed, &nullfds, &valid_to, EBADF },
38f08c3bdfSopenharmony_ci	{ "Invalid exceptfds", &maxfds, &preadfds_reg, &pwritefds_reg, &pfds_closed, &valid_to, EBADF },
39f08c3bdfSopenharmony_ci	{ "Faulty readfds", &maxfds, &faulty_fds, &pwritefds_reg, &nullfds, &valid_to, EFAULT },
40f08c3bdfSopenharmony_ci	{ "Faulty writefds", &maxfds, &preadfds_reg, &faulty_fds, &nullfds, &valid_to, EFAULT },
41f08c3bdfSopenharmony_ci	{ "Faulty exceptfds", &maxfds, &preadfds_reg, &pwritefds_reg, &faulty_fds, &valid_to, EFAULT },
42f08c3bdfSopenharmony_ci	{ "Faulty timeout", &maxfds, &preadfds_reg, &pwritefds_reg, &nullfds, &invalid_to, EFAULT },
43f08c3bdfSopenharmony_ci};
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_cistatic void verify_select(unsigned int n)
46f08c3bdfSopenharmony_ci{
47f08c3bdfSopenharmony_ci	struct tcases *tc = &tests[n];
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_ci	TEST(do_select_faulty_to(*tc->nfds, *tc->readfds, *tc->writefds,
50f08c3bdfSopenharmony_ci				 *tc->exceptfds, *tc->timeout,
51f08c3bdfSopenharmony_ci				 tc->timeout == &invalid_to));
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	if (TST_RET != -1) {
54f08c3bdfSopenharmony_ci		tst_res(TFAIL, "%s: select() passed unexpectedly with %ld",
55f08c3bdfSopenharmony_ci		        tc->name, TST_RET);
56f08c3bdfSopenharmony_ci		return;
57f08c3bdfSopenharmony_ci	}
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	if (tc->exp_errno != TST_ERR) {
60f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "%s: select()() should fail with %s",
61f08c3bdfSopenharmony_ci			tc->name, tst_strerrno(tc->exp_errno));
62f08c3bdfSopenharmony_ci		return;
63f08c3bdfSopenharmony_ci	}
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	tst_res(TPASS | TTERRNO, "%s: select() failed as expected", tc->name);
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci	exit(0);
68f08c3bdfSopenharmony_ci}
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_cistatic void run(unsigned int n)
71f08c3bdfSopenharmony_ci{
72f08c3bdfSopenharmony_ci	int pid, status;
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
75f08c3bdfSopenharmony_ci	if (!pid)
76f08c3bdfSopenharmony_ci		verify_select(n);
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci	SAFE_WAITPID(pid, &status, 0);
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci	if (WIFEXITED(status))
81f08c3bdfSopenharmony_ci		return;
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci	if (tst_variant == GLIBC_SELECT_VARIANT &&
84f08c3bdfSopenharmony_ci	    tests[n].timeout == &invalid_to &&
85f08c3bdfSopenharmony_ci	    WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
86f08c3bdfSopenharmony_ci		tst_res(TPASS, "%s: select() killed by signal", tests[n].name);
87f08c3bdfSopenharmony_ci		return;
88f08c3bdfSopenharmony_ci	}
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_ci	tst_res(TFAIL, "Child %s", tst_strstatus(status));
91f08c3bdfSopenharmony_ci}
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_cistatic void setup(void)
94f08c3bdfSopenharmony_ci{
95f08c3bdfSopenharmony_ci	void *faulty_address;
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ci	select_info();
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci	/* Regular file */
100f08c3bdfSopenharmony_ci	fd_closed = SAFE_OPEN("tmpfile1", O_CREAT | O_RDWR, 0777);
101f08c3bdfSopenharmony_ci	FD_ZERO(&fds_closed);
102f08c3bdfSopenharmony_ci	FD_SET(fd_closed, &fds_closed);
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	SAFE_PIPE(fd);
105f08c3bdfSopenharmony_ci	FD_ZERO(&readfds_reg);
106f08c3bdfSopenharmony_ci	FD_ZERO(&writefds_reg);
107f08c3bdfSopenharmony_ci	FD_SET(fd[0], &readfds_reg);
108f08c3bdfSopenharmony_ci	FD_SET(fd[1], &writefds_reg);
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci	SAFE_CLOSE(fd_closed);
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	maxfds = fd[1] + 1;
113f08c3bdfSopenharmony_ci	faulty_address = tst_get_bad_addr(NULL);
114f08c3bdfSopenharmony_ci	invalid_to = faulty_address;
115f08c3bdfSopenharmony_ci	faulty_fds = faulty_address;
116f08c3bdfSopenharmony_ci}
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_cistatic struct tst_test test = {
119f08c3bdfSopenharmony_ci	.test = run,
120f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tests),
121f08c3bdfSopenharmony_ci	.test_variants = TEST_VARIANTS,
122f08c3bdfSopenharmony_ci	.setup = setup,
123f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
124f08c3bdfSopenharmony_ci	.forks_child = 1,
125f08c3bdfSopenharmony_ci};
126