1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
4 */
5
6 #define _GNU_SOURCE
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <sched.h>
11 #include <sys/ptrace.h>
12 #include "config.h"
13 #ifdef HAVE_SYS_FANOTIFY_H
14 # include <sys/fanotify.h>
15 #endif
16 #define TST_NO_DEFAULT_MAIN
17 #include "tst_test.h"
18 #include "lapi/setns.h"
19 #include "tst_safe_macros.h"
20 #include "lapi/personality.h"
21 #include "lapi/pidfd.h"
22
safe_access(const char * file,const int lineno,const char * pathname,int mode)23 int safe_access(const char *file, const int lineno,
24 const char *pathname, int mode)
25 {
26 int rval;
27
28 rval = access(pathname, mode);
29
30 if (rval == -1) {
31 tst_brk_(file, lineno, TBROK | TERRNO,
32 "access(%s,%d) failed", pathname, mode);
33 } else if (rval) {
34 tst_brk_(file, lineno, TBROK | TERRNO,
35 "Invalid access(%s,%d) return value %d", pathname,
36 mode, rval);
37 }
38
39 return rval;
40 }
41
safe_setpgid(const char * file,const int lineno,pid_t pid,pid_t pgid)42 int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid)
43 {
44 int rval;
45
46 rval = setpgid(pid, pgid);
47
48 if (rval == -1) {
49 tst_brk_(file, lineno, TBROK | TERRNO,
50 "setpgid(%i, %i) failed", pid, pgid);
51 } else if (rval) {
52 tst_brk_(file, lineno, TBROK | TERRNO,
53 "Invalid setpgid(%i, %i) return value %d", pid, pgid,
54 rval);
55 }
56
57 return rval;
58 }
59
safe_getpgid(const char * file,const int lineno,pid_t pid)60 pid_t safe_getpgid(const char *file, const int lineno, pid_t pid)
61 {
62 pid_t pgid;
63
64 pgid = getpgid(pid);
65
66 if (pgid == -1) {
67 tst_brk_(file, lineno, TBROK | TERRNO, "getpgid(%i) failed",
68 pid);
69 } else if (pgid < 0) {
70 tst_brk_(file, lineno, TBROK | TERRNO,
71 "Invalid getpgid(%i) return value %d", pid, pgid);
72 }
73
74 return pgid;
75 }
76
safe_setgroups(const char * file,const int lineno,size_t size,const gid_t * list)77 int safe_setgroups(const char *file, const int lineno, size_t size, const gid_t *list)
78 {
79 int rval;
80
81 rval = setgroups(size, list);
82
83 if (rval == -1) {
84 tst_brk_(file, lineno, TBROK | TERRNO,
85 "setgroups(%zu, %p) failed", size, list);
86 } else if (rval) {
87 tst_brk_(file, lineno, TBROK | TERRNO,
88 "Invalid setgroups(%zu, %p) return value %d", size,
89 list, rval);
90 }
91
92 return rval;
93 }
94
safe_getgroups(const char * file,const int lineno,int size,gid_t list[])95 int safe_getgroups(const char *file, const int lineno, int size, gid_t list[])
96 {
97 int rval;
98
99 rval = getgroups(size, list);
100
101 if (rval == -1) {
102 tst_brk_(file, lineno, TBROK | TERRNO,
103 "getgroups(%i, %p)", size, list);
104 } else if (rval < 0) {
105 tst_brk_(file, lineno, TBROK | TERRNO,
106 "Invalid getgroups(%i, %p) return value %d", size,
107 list, rval);
108 }
109
110 return rval;
111 }
112
safe_personality(const char * filename,unsigned int lineno,unsigned long persona)113 int safe_personality(const char *filename, unsigned int lineno,
114 unsigned long persona)
115 {
116 int prev_persona = personality(persona);
117
118 if (prev_persona == -1) {
119 tst_brk_(filename, lineno, TBROK | TERRNO,
120 "persona(%ld) failed", persona);
121 } else if (prev_persona < 0) {
122 tst_brk_(filename, lineno, TBROK | TERRNO,
123 "Invalid persona(%ld) return value %d", persona,
124 prev_persona);
125 }
126
127 return prev_persona;
128 }
129
safe_pidfd_open(const char * file,const int lineno,pid_t pid,unsigned int flags)130 int safe_pidfd_open(const char *file, const int lineno, pid_t pid,
131 unsigned int flags)
132 {
133 int rval;
134
135 rval = pidfd_open(pid, flags);
136
137 if (rval == -1) {
138 tst_brk_(file, lineno, TBROK | TERRNO,
139 "pidfd_open(%i, %i) failed", pid, flags);
140 } else if (rval < 0) {
141 tst_brk_(file, lineno, TBROK | TERRNO,
142 "Invalid pidfd_open(%i, %i) return value %d",
143 pid, flags, rval);
144 }
145
146 return rval;
147 }
148
safe_setregid(const char * file,const int lineno,gid_t rgid,gid_t egid)149 int safe_setregid(const char *file, const int lineno,
150 gid_t rgid, gid_t egid)
151 {
152 int rval;
153
154 rval = setregid(rgid, egid);
155
156 if (rval == -1) {
157 tst_brk_(file, lineno, TBROK | TERRNO,
158 "setregid(%li, %li) failed", (long)rgid, (long)egid);
159 } else if (rval) {
160 tst_brk_(file, lineno, TBROK | TERRNO,
161 "Invalid setregid(%li, %li) return value %d",
162 (long)rgid, (long)egid, rval);
163 }
164
165 return rval;
166 }
167
safe_setreuid(const char * file,const int lineno,uid_t ruid,uid_t euid)168 int safe_setreuid(const char *file, const int lineno,
169 uid_t ruid, uid_t euid)
170 {
171 int rval;
172
173 rval = setreuid(ruid, euid);
174
175 if (rval == -1) {
176 tst_brk_(file, lineno, TBROK | TERRNO,
177 "setreuid(%li, %li) failed", (long)ruid, (long)euid);
178 } else if (rval) {
179 tst_brk_(file, lineno, TBROK | TERRNO,
180 "Invalid setreuid(%li, %li) return value %d",
181 (long)ruid, (long)euid, rval);
182 }
183
184 return rval;
185 }
186
safe_setresgid(const char * file,const int lineno,gid_t rgid,gid_t egid,gid_t sgid)187 int safe_setresgid(const char *file, const int lineno,
188 gid_t rgid, gid_t egid, gid_t sgid)
189 {
190 int ret;
191
192 ret = setresgid(rgid, egid, sgid);
193
194 if (ret == -1) {
195 tst_brk_(file, lineno, TBROK | TERRNO,
196 "setregid(%li, %li, %li) failed", (long)rgid,
197 (long)egid, (long)sgid);
198 } else if (ret) {
199 tst_brk_(file, lineno, TBROK | TERRNO,
200 "Invalid setregid(%li, %li, %li) return value %d",
201 (long)rgid, (long)egid, (long)sgid, ret);
202 }
203
204 return ret;
205 }
206
safe_setresuid(const char * file,const int lineno,uid_t ruid,uid_t euid,uid_t suid)207 int safe_setresuid(const char *file, const int lineno,
208 uid_t ruid, uid_t euid, uid_t suid)
209 {
210 int ret;
211
212 ret = setresuid(ruid, euid, suid);
213
214 if (ret == -1) {
215 tst_brk_(file, lineno, TBROK | TERRNO,
216 "setreuid(%li, %li, %li) failed", (long)ruid,
217 (long)euid, (long)suid);
218 } else if (ret) {
219 tst_brk_(file, lineno, TBROK | TERRNO,
220 "Invalid setreuid(%li, %li, %li) return value %d",
221 (long)ruid, (long)euid, (long)suid, ret);
222 }
223
224 return ret;
225 }
226
safe_sigaction(const char * file,const int lineno,int signum,const struct sigaction * act,struct sigaction * oldact)227 int safe_sigaction(const char *file, const int lineno,
228 int signum, const struct sigaction *act,
229 struct sigaction *oldact)
230 {
231 int rval;
232
233 rval = sigaction(signum, act, oldact);
234
235 if (rval == -1) {
236 tst_brk_(file, lineno, TBROK | TERRNO,
237 "sigaction(%s (%d), %p, %p) failed",
238 tst_strsig(signum), signum, act, oldact);
239 } else if (rval) {
240 tst_brk_(file, lineno, TBROK | TERRNO,
241 "Invalid sigaction(%s (%d), %p, %p) return value %d",
242 tst_strsig(signum), signum, act, oldact, rval);
243 }
244
245 return rval;
246 }
247
safe_sigaddset(const char * file,const int lineno,sigset_t * sigs,int signo)248 int safe_sigaddset(const char *file, const int lineno,
249 sigset_t *sigs, int signo)
250 {
251 int rval;
252
253 rval = sigaddset(sigs, signo);
254
255 if (rval == -1) {
256 tst_brk_(file, lineno, TBROK | TERRNO,
257 "sigaddset() %s (%i) failed", tst_strsig(signo),
258 signo);
259 } else if (rval) {
260 tst_brk_(file, lineno, TBROK | TERRNO,
261 "Invalid sigaddset() %s (%i) return value %d",
262 tst_strsig(signo), signo, rval);
263 }
264
265 return rval;
266 }
267
safe_sigdelset(const char * file,const int lineno,sigset_t * sigs,int signo)268 int safe_sigdelset(const char *file, const int lineno,
269 sigset_t *sigs, int signo)
270 {
271 int rval;
272
273 rval = sigdelset(sigs, signo);
274
275 if (rval == -1) {
276 tst_brk_(file, lineno, TBROK | TERRNO,
277 "sigdelset() %s (%i) failed", tst_strsig(signo),
278 signo);
279 } else if (rval) {
280 tst_brk_(file, lineno, TBROK | TERRNO,
281 "Invalid sigdelset() %s (%i) return value %d",
282 tst_strsig(signo), signo, rval);
283 }
284
285 return rval;
286 }
287
safe_sigemptyset(const char * file,const int lineno,sigset_t * sigs)288 int safe_sigemptyset(const char *file, const int lineno,
289 sigset_t *sigs)
290 {
291 int rval;
292
293 rval = sigemptyset(sigs);
294
295 if (rval == -1) {
296 tst_brk_(file, lineno, TBROK | TERRNO, "sigemptyset() failed");
297 } else if (rval) {
298 tst_brk_(file, lineno, TBROK | TERRNO,
299 "Invalid sigemptyset() return value %d", rval);
300 }
301
302 return rval;
303 }
304
safe_sigfillset(const char * file,const int lineno,sigset_t * sigs)305 int safe_sigfillset(const char *file, const int lineno,
306 sigset_t *sigs)
307 {
308 int rval;
309
310 rval = sigfillset(sigs);
311
312 if (rval == -1) {
313 tst_brk_(file, lineno, TBROK | TERRNO, "sigfillset() failed");
314 } else if (rval) {
315 tst_brk_(file, lineno, TBROK | TERRNO,
316 "Invalid sigfillset() return value %d", rval);
317 }
318
319 return rval;
320 }
321
strhow(int how)322 static const char *strhow(int how)
323 {
324 switch (how) {
325 case SIG_BLOCK:
326 return "SIG_BLOCK";
327 case SIG_UNBLOCK:
328 return "SIG_UNBLOCK";
329 case SIG_SETMASK:
330 return "SIG_SETMASK";
331 default:
332 return "???";
333 }
334 }
335
safe_sigprocmask(const char * file,const int lineno,int how,sigset_t * set,sigset_t * oldset)336 int safe_sigprocmask(const char *file, const int lineno,
337 int how, sigset_t *set, sigset_t *oldset)
338 {
339 int rval;
340
341 rval = sigprocmask(how, set, oldset);
342
343 if (rval == -1) {
344 tst_brk_(file, lineno, TBROK | TERRNO,
345 "sigprocmask(%s, %p, %p) failed", strhow(how), set,
346 oldset);
347 } else if (rval) {
348 tst_brk_(file, lineno, TBROK | TERRNO,
349 "Invalid sigprocmask(%s, %p, %p) return value %d",
350 strhow(how), set, oldset, rval);
351 }
352
353 return rval;
354 }
355
safe_sigwait(const char * file,const int lineno,sigset_t * set,int * sig)356 int safe_sigwait(const char *file, const int lineno,
357 sigset_t *set, int *sig)
358 {
359 int rval;
360
361 rval = sigwait(set, sig);
362
363 if (rval > 0) {
364 errno = rval;
365 tst_brk_(file, lineno, TBROK | TERRNO,
366 "sigwait(%p, %p) failed", set, sig);
367 } else if (rval) {
368 tst_brk_(file, lineno, TBROK,
369 "Invalid sigwait(%p, %p) return value %d", set, sig,
370 rval);
371 }
372
373 return rval;
374 }
375
safe_getgrnam(const char * file,const int lineno,const char * name)376 struct group *safe_getgrnam(const char *file, const int lineno,
377 const char *name)
378 {
379 struct group *rval;
380
381 errno = 0;
382 rval = getgrnam(name);
383 if (rval == NULL) {
384 tst_brk_(file, lineno, TBROK | TERRNO,
385 "getgrnam(%s) failed", name);
386 }
387
388 return rval;
389 }
390
safe_getgrnam_fallback(const char * file,const int lineno,const char * name,const char * fallback)391 struct group *safe_getgrnam_fallback(const char *file, const int lineno,
392 const char *name, const char *fallback)
393 {
394 struct group *rval;
395
396 errno = 0;
397 rval = getgrnam(name);
398 if (rval == NULL) {
399 tst_res_(file, lineno, TINFO,
400 "getgrnam(%s) failed - try fallback %s",
401 name, fallback);
402 rval = safe_getgrnam(file, lineno, fallback);
403 }
404
405 return rval;
406 }
407
safe_getgrgid(const char * file,const int lineno,gid_t gid)408 struct group *safe_getgrgid(const char *file, const int lineno, gid_t gid)
409 {
410 struct group *rval;
411
412 errno = 0;
413 rval = getgrgid(gid);
414 if (rval == NULL) {
415 tst_brk_(file, lineno, TBROK | TERRNO,
416 "getgrgid(%li) failed", (long)gid);
417 }
418
419 return rval;
420 }
421
safe_chroot(const char * file,const int lineno,const char * path)422 int safe_chroot(const char *file, const int lineno, const char *path)
423 {
424 int rval;
425
426 rval = chroot(path);
427
428 if (rval == -1) {
429 tst_brk_(file, lineno, TBROK | TERRNO, "chroot(%s) failed",
430 path);
431 } else if (rval) {
432 tst_brk_(file, lineno, TBROK | TERRNO,
433 "Invalid chroot(%s) return value %d", path, rval);
434 }
435
436 return rval;
437 }
438
safe_unshare(const char * file,const int lineno,int flags)439 int safe_unshare(const char *file, const int lineno, int flags)
440 {
441 int res;
442
443 res = unshare(flags);
444
445 if (res == -1) {
446 if (errno == EINVAL) {
447 tst_brk_(file, lineno, TCONF | TERRNO,
448 "unshare(%d) unsupported", flags);
449 } else {
450 tst_brk_(file, lineno, TBROK | TERRNO,
451 "unshare(%d) failed", flags);
452 }
453 } else if (res) {
454 tst_brk_(file, lineno, TBROK | TERRNO,
455 "Invalid unshare(%d) return value %d", flags, res);
456 }
457
458 return res;
459 }
460
safe_setns(const char * file,const int lineno,int fd,int nstype)461 int safe_setns(const char *file, const int lineno, int fd, int nstype)
462 {
463 int ret;
464
465 ret = setns(fd, nstype);
466
467 if (ret == -1) {
468 tst_brk_(file, lineno, TBROK | TERRNO, "setns(%i, %i) failed",
469 fd, nstype);
470 } else if (ret) {
471 tst_brk_(file, lineno, TBROK | TERRNO,
472 "Invalid setns(%i, %i) return value %d", fd, nstype,
473 ret);
474 }
475
476 return ret;
477 }
478
tst_safe_ptrace(const char * file,const int lineno,int req,pid_t pid,void * addr,void * data)479 long tst_safe_ptrace(const char *file, const int lineno, int req, pid_t pid,
480 void *addr, void *data)
481 {
482 long ret;
483
484 errno = 0;
485 ret = ptrace(req, pid, addr, data);
486
487 if (ret == -1) {
488 tst_brk_(file, lineno, TBROK | TERRNO, "ptrace() failed");
489 } else if (ret) {
490 tst_brk_(file, lineno, TBROK | TERRNO,
491 "Invalid ptrace() return value %ld", ret);
492 }
493
494 return ret;
495 }
496
safe_pipe2(const char * file,const int lineno,int fildes[2],int flags)497 int safe_pipe2(const char *file, const int lineno, int fildes[2], int flags)
498 {
499 int ret;
500
501 ret = pipe2(fildes, flags);
502
503 if (ret == -1) {
504 tst_brk_(file, lineno, TBROK | TERRNO,
505 "pipe2({%d,%d}) failed with flag(%d)", fildes[0],
506 fildes[1], flags);
507 } else if (ret) {
508 tst_brk_(file, lineno, TBROK | TERRNO,
509 "Invalid pipe2({%d,%d}, %d) return value %d",
510 fildes[0], fildes[1], flags, ret);
511 }
512
513 return ret;
514 }
515
safe_dup(const char * file,const int lineno,int oldfd)516 int safe_dup(const char *file, const int lineno, int oldfd)
517 {
518 int rval;
519
520 rval = dup(oldfd);
521
522 if (rval == -1) {
523 tst_brk_(file, lineno, TBROK | TERRNO,
524 "dup(%i) failed", oldfd);
525 } else if (rval < 0) {
526 tst_brk_(file, lineno, TBROK | TERRNO,
527 "Invalid dup(%i) return value %d", oldfd, rval);
528 }
529
530 return rval;
531 }
532
safe_dup2(const char * file,const int lineno,int oldfd,int newfd)533 int safe_dup2(const char *file, const int lineno, int oldfd, int newfd)
534 {
535 int rval;
536
537 rval = dup2(oldfd, newfd);
538
539 if (rval == -1) {
540 tst_brk_(file, lineno, TBROK | TERRNO,
541 "dup2(%i, %i) failed", oldfd, newfd);
542 } else if (rval != newfd) {
543 tst_brk_(file, lineno, TBROK | TERRNO,
544 "Invalid dup2(%i, %i) return value %d",
545 oldfd, newfd, rval);
546 }
547
548 return rval;
549 }
550
safe_realloc(const char * file,const int lineno,void * ptr,size_t size)551 void *safe_realloc(const char *file, const int lineno, void *ptr, size_t size)
552 {
553 void *ret;
554
555 ret = realloc(ptr, size);
556
557 if (!ret) {
558 tst_brk_(file, lineno, TBROK | TERRNO,
559 "realloc(%p, %zu) failed", ptr, size);
560 }
561
562 return ret;
563 }
564
safe_signal(const char * file,const int lineno,int signum,sighandler_t handler)565 sighandler_t safe_signal(const char *file, const int lineno,
566 int signum, sighandler_t handler)
567 {
568 sighandler_t rval;
569
570 rval = signal(signum, handler);
571
572 if (rval == SIG_ERR) {
573 tst_brk_(file, lineno, TBROK | TERRNO,
574 "signal(%d,%p) failed",
575 signum, handler);
576 }
577
578 return rval;
579 }
580
safe_cmd(const char * file,const int lineno,const char * const argv[],const char * stdout_path,const char * stderr_path)581 void safe_cmd(const char *file, const int lineno, const char *const argv[],
582 const char *stdout_path, const char *stderr_path)
583 {
584 int rval;
585
586 switch ((rval = tst_cmd(argv, stdout_path, stderr_path,
587 TST_CMD_PASS_RETVAL | TST_CMD_TCONF_ON_MISSING))) {
588 case 0:
589 break;
590 default:
591 tst_brk_(file, lineno, TBROK, "%s failed (%d)", argv[0], rval);
592 }
593 }
594