1 /*
2  * Copyright (C) 2013-2021 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * This code is a complete clean re-write of the stress tool by
19  * Colin Ian King <colin.king@canonical.com> and attempts to be
20  * backwardly compatible with the stress tool by Amos Waterland
21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
22  * functionality.
23  *
24  */
25 #include "stress-ng.h"
26 
27 static const stress_help_t help[] = {
28 	{ NULL,	"close N",	"start N workers that exercise races on close" },
29 	{ NULL,	"close-ops N",	"stop after N bogo close operations" },
30 	{ NULL,	NULL,		NULL }
31 };
32 
33 #if defined(HAVE_LIB_PTHREAD)
34 
35 #define MAX_PTHREADS	(3)
36 #define SHM_NAME_LEN	(128)
37 #define FDS_START	(1024)
38 #define FDS_TO_DUP	(8)
39 
40 static volatile int fd, dupfd;
41 static volatile uint64_t max_delay_us = 1;
42 static sigset_t set;
43 
44 static const int domains[] = {
45 #if defined(AF_UNIX)
46 	AF_UNIX,
47 #endif
48 #if defined(AF_LOCAL)
49 	AF_LOCAL,
50 #endif
51 #if defined(AF_INET)
52 	AF_INET,
53 #endif
54 #if defined(AF_INET6)
55 	AF_INET6,
56 #endif
57 #if defined(AF_IPX)
58 	AF_IPX,
59 #endif
60 #if defined(AF_NETLINK)
61 	AF_NETLINK,
62 #endif
63 #if defined(AF_X25)
64 	AF_X25,
65 #endif
66 #if defined(AF_AX25)
67 	AF_AX25,
68 #endif
69 #if defined(AF_ATMPVC)
70 	AF_ATMPVC,
71 #endif
72 /*
73 #if defined(AF_APPLETALK)
74 	AF_APPLETALK,
75 #endif
76 */
77 #if defined(AF_PACKET)
78 	AF_PACKET,
79 #endif
80 #if defined(AF_ALG)
81 	AF_ALG,
82 #endif
83 	0,
84 };
85 
86 static const int types[] = {
87 #if defined(SOCK_STREAM)
88 	SOCK_STREAM,
89 #endif
90 #if defined(SOCK_DGRAM)
91 	SOCK_DGRAM,
92 #endif
93 #if defined(SOCK_SEQPACKET)
94 	SOCK_SEQPACKET,
95 #endif
96 #if defined(SOCK_RAW)
97 	SOCK_RAW,
98 #endif
99 #if defined(SOCK_RDM)
100 	SOCK_RDM,
101 #endif
102 	0,
103 };
104 
105 /*
106  *  stress_close_func()
107  *	pthread that exits immediately
108  */
stress_close_func(void * arg)109 static void *stress_close_func(void *arg)
110 {
111 	static void *nowt = NULL;
112 	stress_pthread_args_t *pargs = (stress_pthread_args_t *)arg;
113 	const stress_args_t *args = pargs->args;
114 
115 	/*
116 	 *  Block all signals, let controlling thread
117 	 *  handle these
118 	 */
119 #if !defined(__APPLE__) &&	\
120     !defined(__DragonFly__)
121 	(void)sigprocmask(SIG_BLOCK, &set, NULL);
122 #endif
123 
124 	while (keep_stressing(args)) {
125 		int fd_rnd = (int)stress_mwc32() + 64;
126 		const uint64_t delay =
127 			max_delay_us ? stress_mwc32() % max_delay_us : 0;
128 		int fds[FDS_TO_DUP], i, ret;
129 
130 		for (i = 0; i < FDS_TO_DUP; i++) {
131 			fds[i] = dup2(fileno(stderr), i + FDS_START);
132 		}
133 
134 		shim_usleep_interruptible(delay);
135 		if (fd != -1)
136 			(void)close(fd);
137 		if (dupfd != -1)
138 			(void)close(dupfd);
139 
140 #if defined(F_GETFL)
141 		/*
142 		 *  close random unused fd to force EBADF
143 		 */
144 		if (fcntl((int)fd_rnd, F_GETFL) == -1)
145 			(void)close(fd_rnd);
146 #endif
147 		/*
148 		 *  close a range of fds
149 		 */
150 		ret = shim_close_range(FDS_START, FDS_START + FDS_TO_DUP, 0);
151 		if ((ret < 1) && (errno == ENOSYS)) {
152 			for (i = 0; i < FDS_TO_DUP; i++)
153 				(void)close(fds[i]);
154 		}
155 		/*
156 		 *  close an invalid range of fds
157 		 */
158 		ret = shim_close_range(FDS_START + FDS_TO_DUP, FDS_START, 0);
159 		(void)ret;
160 
161 		/*
162 		 *  close with invalid fds and flags
163 		 */
164 		ret = shim_close_range(FDS_START + FDS_TO_DUP, FDS_START, ~0U);
165 		(void)ret;
166 	}
167 
168 	return &nowt;
169 }
170 
171 /*
172  *  stress_close()
173  *	stress by creating pthreads
174  */
stress_close(const stress_args_t * args)175 static int stress_close(const stress_args_t *args)
176 {
177 	stress_pthread_args_t pargs;
178 	pthread_t pthread[MAX_PTHREADS];
179 	int rc = EXIT_NO_RESOURCE;
180 	int ret, rets[MAX_PTHREADS];
181 	const int bad_fd = stress_get_bad_fd();
182 	size_t i;
183 	const uid_t uid = getuid();
184 	const gid_t gid = getgid();
185 	const bool not_root = !stress_check_capability(SHIM_CAP_IS_ROOT);
186 	double max_duration = 0.0;
187 #if defined(HAVE_FACCESSAT)
188 	int file_fd = -1;
189 	char filename[PATH_MAX];
190 #endif
191 #if defined(HAVE_LIB_RT)
192 	char shm_name[SHM_NAME_LEN];
193 #endif
194 
195 #if defined(HAVE_LIB_RT)
196 	(void)snprintf(shm_name, SHM_NAME_LEN,
197 		"stress-ng-%d-%" PRIx32, (int)getpid(), stress_mwc32());
198 #endif
199 
200 	(void)sigfillset(&set);
201 
202 	fd = -1;
203 	dupfd = -1;
204 
205 	pargs.args = args;
206 	pargs.data = NULL;
207 
208 	for (i = 0; i < MAX_PTHREADS; i++)
209 		rets[i] = -1;
210 
211 	for (i = 0; i < MAX_PTHREADS; i++) {
212 		rets[i] = pthread_create(&pthread[i], NULL, stress_close_func, (void *)&pargs);
213 		if (rets[i]) {
214 			pr_inf("%s: failed to create a pthread, error=%d (%s)\n",
215 				args->name, rets[i], strerror(rets[i]));
216 			goto tidy;
217 		}
218 	}
219 
220 #if defined(HAVE_FACCESSAT)
221 	{
222 		ret = stress_temp_dir_mk_args(args);
223 		if (ret < 0)
224 			return exit_status(-ret);
225 		(void)stress_temp_filename_args(args, filename, sizeof(filename), stress_mwc32());
226 		file_fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
227 		if (file_fd < 0) {
228 			pr_err("%s: cannot create %s\n", args->name, filename);
229 			return exit_status(errno);
230 		}
231 		(void)unlink(filename);
232 	}
233 #endif
234 	stress_set_proc_state(args->name, STRESS_STATE_RUN);
235 
236 	do {
237 		size_t domain, type;
238 		int pipefds[2];
239 		struct stat statbuf;
240 		fd = -1;
241 		double t1, t2, duration;
242 
243 		t1 = stress_time_now();
244 
245 		switch (stress_mwc8() % 14) {
246 		case 0:
247 			domain = stress_mwc8() % SIZEOF_ARRAY(domains);	/* cppcheck-suppress moduloofone */
248 			type = stress_mwc8() % SIZEOF_ARRAY(types);	/* cppcheck-suppress moduloofone */
249 			fd = socket(domains[domain], types[type], 0);
250 			break;
251 		case 1:
252 			fd = open("/dev/zero", O_RDONLY);
253 			break;
254 #if defined(O_TMPFILE)
255 		case 2:
256 			fd = open("/tmp", O_TMPFILE | O_RDWR,
257 					S_IRUSR | S_IWUSR);
258 			break;
259 #endif
260 #if defined(HAVE_SYS_EPOLL_H)
261 		case 3:
262 			fd = epoll_create(1);
263 			break;
264 #endif
265 #if defined(HAVE_SYS_EVENTFD_H) &&	\
266     defined(HAVE_EVENTFD) &&		\
267     NEED_GLIBC(2,8,0)
268 		case 4:
269 			fd = eventfd(0, 0);
270 			break;
271 #endif
272 #if defined(HAVE_SYS_FANOTIFY_H) &&	\
273     defined(HAVE_FANOTIFY)
274 		case 5:
275 			fd = fanotify_init(0, 0);
276 			break;
277 #endif
278 #if defined(HAVE_INOTIFY) &&		\
279     defined(HAVE_SYS_INOTIFY_H)
280 		case 6:
281 			fd = inotify_init();
282 			break;
283 #endif
284 		case 7:
285 			if (pipe(pipefds) == 0) {
286 				fd = pipefds[0];
287 				(void)close(pipefds[1]);
288 			}
289 			break;
290 #if defined(HAVE_SYS_SIGNALFD_H) &&     \
291     NEED_GLIBC(2,8,0) &&                \
292     defined(HAVE_SIGQUEUE) &&		\
293     defined(SIGRTMIN)
294 		case 8:
295 			{
296 				sigset_t mask;
297 
298 				(void)sigemptyset(&mask);
299 				(void)sigaddset(&mask, SIGRTMIN);
300 				fd = signalfd(-1, &mask, 0);
301 			}
302 			break;
303 #endif
304 #if defined(HAVE_USERFAULTFD) &&	\
305     defined(HAVE_LINUX_USERFAULTFD_H)
306 		case 9:
307 			fd = shim_userfaultfd(0);
308 			break;
309 #endif
310 #if defined(O_PATH)
311 		case 10:
312 			fd = open("/tmp", O_PATH | O_RDWR);
313 			break;
314 #endif
315 #if defined(O_DIRECTORY) &&	\
316     defined(O_CLOEXEC)
317 		case 11:
318 			fd = open("/tmp/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
319 			break;
320 #endif
321 #if defined(HAVE_LIB_RT)
322 		case 12:
323 			fd = shm_open(shm_name, O_CREAT | O_RDWR | O_TRUNC,
324 				S_IRUSR | S_IWUSR);
325 			(void)shm_unlink(shm_name);
326 			break;
327 #endif
328 		case 13:
329 			fd = bad_fd;
330 			break;
331 		default:
332 			break;
333 		}
334 		if (fd == -1)
335 			fd = open("/dev/null", O_RDWR);
336 
337 		if (fd != -1) {
338 			dupfd = dup(fd);
339 			if (not_root) {
340 #if defined(HAVE_FCHOWNAT)
341 				ret = fchownat(fd, "", uid, gid, 0);
342 				(void)ret;
343 
344 				ret = fchownat(fd, "", uid, gid, ~0);
345 				(void)ret;
346 #endif
347 				ret = fchown(fd, uid, gid);
348 				(void)ret;
349 			}
350 #if defined(HAVE_FACCESSAT)
351 			ret = faccessat(fd, "", F_OK, 0);
352 			(void)ret;
353 
354 			/*
355 			 * Exercise bad dirfd resulting in Error EBADF
356 			 */
357 			ret = faccessat(bad_fd, "", F_OK, 0);
358 			(void)ret;
359 
360 			/*
361 			 * Exercise invalid flags syscall
362 			 */
363 			ret = faccessat(fd, "", ~0, 0);
364 			(void)ret;
365 
366 			/*
367 			 * Invalid faccessat syscall with pathname is relative and dirfd
368 			 * is a file descriptor referring to a file other than a directory
369 			 */
370 			ret = faccessat(file_fd, "./", F_OK, 0);
371 			if (ret >= 0) {
372 				pr_fail("%s: faccessat opened file descriptor succeeded unexpectedly, "
373 					"errno=%d (%s)\n", args->name, errno, strerror(errno));
374 				(void)close(ret);
375 				goto tidy;
376 			}
377 #endif
378 			ret = fstat(fd, &statbuf);
379 			(void)ret;
380 
381 			(void)close(fd);
382 			if (dupfd != -1)
383 				(void)close(dupfd);
384 		}
385 		t2 = stress_time_now();
386 		duration = t2 - t1;
387 		if (duration > max_duration) {
388 			max_duration = duration;
389 			/* max delay is 75% of the duration in microseconds */
390 			max_delay_us = (uint64_t)(duration * 750000);
391 		}
392 
393 		max_duration *= 0.995;
394 		if (max_duration < 1.0)
395 			max_duration = 1.0;
396 		inc_counter(args);
397 	} while (keep_stressing(args));
398 
399 	rc = EXIT_SUCCESS;
400 tidy:
401 	stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
402 
403 	for (i = 0; i < MAX_PTHREADS; i++) {
404 		if (rets[i] == -1)
405 			continue;
406 		ret = pthread_join(pthread[i], NULL);
407 		if ((ret) && (ret != ESRCH)) {
408 			pr_fail("%s: pthread_join failed (parent), errno=%d (%s)\n",
409 				args->name, ret, strerror(ret));
410 		}
411 	}
412 
413 #if defined(HAVE_FACCESSAT)
414 	if (file_fd >= 0)
415 		(void)close(file_fd);
416 	(void)stress_temp_dir_rm_args(args);
417 #endif
418 
419 	return rc;
420 }
421 
422 stressor_info_t stress_close_info = {
423 	.stressor = stress_close,
424 	.class = CLASS_SCHEDULER | CLASS_OS,
425 	.help = help
426 };
427 #else
428 stressor_info_t stress_close_info = {
429 	.stressor = stress_not_implemented,
430 	.class = CLASS_SCHEDULER | CLASS_OS,
431 	.help = help
432 };
433 #endif
434