1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2017 Cyril Hrubis <[email protected]>
4 * Copyright (c) 2017-2024 Linux Test Project
5 */
6
7 #define _GNU_SOURCE
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <errno.h>
11 #include <sched.h>
12 #include <sys/ptrace.h>
13 #include "config.h"
14 #ifdef HAVE_SYS_FANOTIFY_H
15 # include <sys/fanotify.h>
16 #endif
17 #define TST_NO_DEFAULT_MAIN
18 #include "tst_test.h"
19 #include "lapi/setns.h"
20 #include "tst_safe_macros.h"
21 #include "lapi/personality.h"
22 #include "lapi/pidfd.h"
23
safe_access(const char * file,const int lineno,const char * pathname,int mode)24 int safe_access(const char *file, const int lineno,
25 const char *pathname, int mode)
26 {
27 int rval;
28
29 rval = access(pathname, mode);
30
31 if (rval == -1) {
32 tst_brk_(file, lineno, TBROK | TERRNO,
33 "access(%s,%d) failed", pathname, mode);
34 } else if (rval) {
35 tst_brk_(file, lineno, TBROK | TERRNO,
36 "Invalid access(%s,%d) return value %d", pathname,
37 mode, rval);
38 }
39
40 return rval;
41 }
42
safe_setpgid(const char * file,const int lineno,pid_t pid,pid_t pgid)43 int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid)
44 {
45 int rval;
46
47 rval = setpgid(pid, pgid);
48
49 if (rval == -1) {
50 tst_brk_(file, lineno, TBROK | TERRNO,
51 "setpgid(%i, %i) failed", pid, pgid);
52 } else if (rval) {
53 tst_brk_(file, lineno, TBROK | TERRNO,
54 "Invalid setpgid(%i, %i) return value %d", pid, pgid,
55 rval);
56 }
57
58 return rval;
59 }
60
safe_getpgid(const char * file,const int lineno,pid_t pid)61 pid_t safe_getpgid(const char *file, const int lineno, pid_t pid)
62 {
63 pid_t pgid;
64
65 pgid = getpgid(pid);
66
67 if (pgid == -1) {
68 tst_brk_(file, lineno, TBROK | TERRNO, "getpgid(%i) failed",
69 pid);
70 } else if (pgid < 0) {
71 tst_brk_(file, lineno, TBROK | TERRNO,
72 "Invalid getpgid(%i) return value %d", pid, pgid);
73 }
74
75 return pgid;
76 }
77
safe_setgroups(const char * file,const int lineno,size_t size,const gid_t * list)78 int safe_setgroups(const char *file, const int lineno, size_t size, const gid_t *list)
79 {
80 int rval;
81
82 rval = setgroups(size, list);
83
84 if (rval == -1) {
85 tst_brk_(file, lineno, TBROK | TERRNO,
86 "setgroups(%zu, %p) failed", size, list);
87 } else if (rval) {
88 tst_brk_(file, lineno, TBROK | TERRNO,
89 "Invalid setgroups(%zu, %p) return value %d", size,
90 list, rval);
91 }
92
93 return rval;
94 }
95
safe_getgroups(const char * file,const int lineno,int size,gid_t list[])96 int safe_getgroups(const char *file, const int lineno, int size, gid_t list[])
97 {
98 int rval;
99
100 rval = getgroups(size, list);
101
102 if (rval == -1) {
103 tst_brk_(file, lineno, TBROK | TERRNO,
104 "getgroups(%i, %p)", size, list);
105 } else if (rval < 0) {
106 tst_brk_(file, lineno, TBROK | TERRNO,
107 "Invalid getgroups(%i, %p) return value %d", size,
108 list, rval);
109 }
110
111 return rval;
112 }
113
safe_personality(const char * filename,unsigned int lineno,unsigned long persona)114 int safe_personality(const char *filename, unsigned int lineno,
115 unsigned long persona)
116 {
117 int prev_persona = personality(persona);
118
119 if (prev_persona == -1) {
120 tst_brk_(filename, lineno, TBROK | TERRNO,
121 "persona(%ld) failed", persona);
122 } else if (prev_persona < 0) {
123 tst_brk_(filename, lineno, TBROK | TERRNO,
124 "Invalid persona(%ld) return value %d", persona,
125 prev_persona);
126 }
127
128 return prev_persona;
129 }
130
safe_pidfd_open(const char * file,const int lineno,pid_t pid,unsigned int flags)131 int safe_pidfd_open(const char *file, const int lineno, pid_t pid,
132 unsigned int flags)
133 {
134 int rval;
135
136 rval = pidfd_open(pid, flags);
137
138 if (rval == -1) {
139 tst_brk_(file, lineno, TBROK | TERRNO,
140 "pidfd_open(%i, %i) failed", pid, flags);
141 } else if (rval < 0) {
142 tst_brk_(file, lineno, TBROK | TERRNO,
143 "Invalid pidfd_open(%i, %i) return value %d",
144 pid, flags, rval);
145 }
146
147 return rval;
148 }
149
safe_setregid(const char * file,const int lineno,gid_t rgid,gid_t egid)150 int safe_setregid(const char *file, const int lineno,
151 gid_t rgid, gid_t egid)
152 {
153 int rval;
154
155 rval = setregid(rgid, egid);
156
157 if (rval == -1) {
158 tst_brk_(file, lineno, TBROK | TERRNO,
159 "setregid(%li, %li) failed", (long)rgid, (long)egid);
160 } else if (rval) {
161 tst_brk_(file, lineno, TBROK | TERRNO,
162 "Invalid setregid(%li, %li) return value %d",
163 (long)rgid, (long)egid, rval);
164 }
165
166 return rval;
167 }
168
safe_setreuid(const char * file,const int lineno,uid_t ruid,uid_t euid)169 int safe_setreuid(const char *file, const int lineno,
170 uid_t ruid, uid_t euid)
171 {
172 int rval;
173
174 rval = setreuid(ruid, euid);
175
176 if (rval == -1) {
177 tst_brk_(file, lineno, TBROK | TERRNO,
178 "setreuid(%li, %li) failed", (long)ruid, (long)euid);
179 } else if (rval) {
180 tst_brk_(file, lineno, TBROK | TERRNO,
181 "Invalid setreuid(%li, %li) return value %d",
182 (long)ruid, (long)euid, rval);
183 }
184
185 return rval;
186 }
187
safe_setresgid(const char * file,const int lineno,gid_t rgid,gid_t egid,gid_t sgid)188 int safe_setresgid(const char *file, const int lineno,
189 gid_t rgid, gid_t egid, gid_t sgid)
190 {
191 int ret;
192
193 ret = setresgid(rgid, egid, sgid);
194
195 if (ret == -1) {
196 tst_brk_(file, lineno, TBROK | TERRNO,
197 "setregid(%li, %li, %li) failed", (long)rgid,
198 (long)egid, (long)sgid);
199 } else if (ret) {
200 tst_brk_(file, lineno, TBROK | TERRNO,
201 "Invalid setregid(%li, %li, %li) return value %d",
202 (long)rgid, (long)egid, (long)sgid, ret);
203 }
204
205 return ret;
206 }
207
safe_setresuid(const char * file,const int lineno,uid_t ruid,uid_t euid,uid_t suid)208 int safe_setresuid(const char *file, const int lineno,
209 uid_t ruid, uid_t euid, uid_t suid)
210 {
211 int ret;
212
213 ret = setresuid(ruid, euid, suid);
214
215 if (ret == -1) {
216 tst_brk_(file, lineno, TBROK | TERRNO,
217 "setreuid(%li, %li, %li) failed", (long)ruid,
218 (long)euid, (long)suid);
219 } else if (ret) {
220 tst_brk_(file, lineno, TBROK | TERRNO,
221 "Invalid setreuid(%li, %li, %li) return value %d",
222 (long)ruid, (long)euid, (long)suid, ret);
223 }
224
225 return ret;
226 }
227
safe_sigaction(const char * file,const int lineno,int signum,const struct sigaction * act,struct sigaction * oldact)228 int safe_sigaction(const char *file, const int lineno,
229 int signum, const struct sigaction *act,
230 struct sigaction *oldact)
231 {
232 int rval;
233
234 rval = sigaction(signum, act, oldact);
235
236 if (rval == -1) {
237 tst_brk_(file, lineno, TBROK | TERRNO,
238 "sigaction(%s (%d), %p, %p) failed",
239 tst_strsig(signum), signum, act, oldact);
240 } else if (rval) {
241 tst_brk_(file, lineno, TBROK | TERRNO,
242 "Invalid sigaction(%s (%d), %p, %p) return value %d",
243 tst_strsig(signum), signum, act, oldact, rval);
244 }
245
246 return rval;
247 }
248
safe_sigaddset(const char * file,const int lineno,sigset_t * sigs,int signo)249 int safe_sigaddset(const char *file, const int lineno,
250 sigset_t *sigs, int signo)
251 {
252 int rval;
253
254 rval = sigaddset(sigs, signo);
255
256 if (rval == -1) {
257 tst_brk_(file, lineno, TBROK | TERRNO,
258 "sigaddset() %s (%i) failed", tst_strsig(signo),
259 signo);
260 } else if (rval) {
261 tst_brk_(file, lineno, TBROK | TERRNO,
262 "Invalid sigaddset() %s (%i) return value %d",
263 tst_strsig(signo), signo, rval);
264 }
265
266 return rval;
267 }
268
safe_sigdelset(const char * file,const int lineno,sigset_t * sigs,int signo)269 int safe_sigdelset(const char *file, const int lineno, 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, sigset_t *sigs)
289 {
290 int rval;
291
292 rval = sigemptyset(sigs);
293
294 if (rval == -1) {
295 tst_brk_(file, lineno, TBROK | TERRNO, "sigemptyset() failed");
296 } else if (rval) {
297 tst_brk_(file, lineno, TBROK | TERRNO,
298 "Invalid sigemptyset() return value %d", rval);
299 }
300
301 return rval;
302 }
303
safe_sigfillset(const char * file,const int lineno,sigset_t * sigs)304 int safe_sigfillset(const char *file, const int lineno,
305 sigset_t *sigs)
306 {
307 int rval;
308
309 rval = sigfillset(sigs);
310
311 if (rval == -1) {
312 tst_brk_(file, lineno, TBROK | TERRNO, "sigfillset() failed");
313 } else if (rval) {
314 tst_brk_(file, lineno, TBROK | TERRNO,
315 "Invalid sigfillset() return value %d", rval);
316 }
317
318 return rval;
319 }
320
strhow(int how)321 static const char *strhow(int how)
322 {
323 switch (how) {
324 case SIG_BLOCK:
325 return "SIG_BLOCK";
326 case SIG_UNBLOCK:
327 return "SIG_UNBLOCK";
328 case SIG_SETMASK:
329 return "SIG_SETMASK";
330 default:
331 return "???";
332 }
333 }
334
safe_sigprocmask(const char * file,const int lineno,int how,sigset_t * set,sigset_t * oldset)335 int safe_sigprocmask(const char *file, const int lineno,
336 int how, sigset_t *set, sigset_t *oldset)
337 {
338 int rval;
339
340 rval = sigprocmask(how, set, oldset);
341
342 if (rval == -1) {
343 tst_brk_(file, lineno, TBROK | TERRNO,
344 "sigprocmask(%s, %p, %p) failed", strhow(how), set,
345 oldset);
346 } else if (rval) {
347 tst_brk_(file, lineno, TBROK | TERRNO,
348 "Invalid sigprocmask(%s, %p, %p) return value %d",
349 strhow(how), set, oldset, rval);
350 }
351
352 return rval;
353 }
354
safe_sigwait(const char * file,const int lineno,sigset_t * set,int * sig)355 int safe_sigwait(const char *file, const int lineno, sigset_t *set, int *sig)
356 {
357 int rval;
358
359 rval = sigwait(set, sig);
360
361 if (rval > 0) {
362 errno = rval;
363 tst_brk_(file, lineno, TBROK | TERRNO,
364 "sigwait(%p, %p) failed", set, sig);
365 } else if (rval) {
366 tst_brk_(file, lineno, TBROK,
367 "Invalid sigwait(%p, %p) return value %d", set, sig,
368 rval);
369 }
370
371 return rval;
372 }
373
safe_getgrnam(const char * file,const int lineno,const char * name)374 struct group *safe_getgrnam(const char *file, const int lineno,
375 const char *name)
376 {
377 struct group *rval;
378
379 errno = 0;
380 rval = getgrnam(name);
381 if (rval == NULL) {
382 tst_brk_(file, lineno, TBROK | TERRNO,
383 "getgrnam(%s) failed", name);
384 }
385
386 return rval;
387 }
388
safe_getgrnam_fallback(const char * file,const int lineno,const char * name,const char * fallback)389 struct group *safe_getgrnam_fallback(const char *file, const int lineno,
390 const char *name, const char *fallback)
391 {
392 struct group *rval;
393
394 errno = 0;
395 rval = getgrnam(name);
396 if (rval == NULL) {
397 tst_res_(file, lineno, TINFO,
398 "getgrnam(%s) failed - try fallback %s",
399 name, fallback);
400 rval = safe_getgrnam(file, lineno, fallback);
401 }
402
403 return rval;
404 }
405
safe_getgrgid(const char * file,const int lineno,gid_t gid)406 struct group *safe_getgrgid(const char *file, const int lineno, gid_t gid)
407 {
408 struct group *rval;
409
410 errno = 0;
411 rval = getgrgid(gid);
412 if (rval == NULL) {
413 tst_brk_(file, lineno, TBROK | TERRNO,
414 "getgrgid(%li) failed", (long)gid);
415 }
416
417 return rval;
418 }
419
safe_chroot(const char * file,const int lineno,const char * path)420 int safe_chroot(const char *file, const int lineno, const char *path)
421 {
422 int rval;
423
424 rval = chroot(path);
425
426 if (rval == -1) {
427 tst_brk_(file, lineno, TBROK | TERRNO, "chroot(%s) failed",
428 path);
429 } else if (rval) {
430 tst_brk_(file, lineno, TBROK | TERRNO,
431 "Invalid chroot(%s) return value %d", path, rval);
432 }
433
434 return rval;
435 }
436
safe_unshare(const char * file,const int lineno,int flags)437 int safe_unshare(const char *file, const int lineno, int flags)
438 {
439 int res;
440
441 res = unshare(flags);
442
443 if (res == -1) {
444 if (errno == EINVAL) {
445 tst_brk_(file, lineno, TCONF | TERRNO,
446 "unshare(%d) unsupported", flags);
447 } else {
448 tst_brk_(file, lineno, TBROK | TERRNO,
449 "unshare(%d) failed", flags);
450 }
451 } else if (res) {
452 tst_brk_(file, lineno, TBROK | TERRNO,
453 "Invalid unshare(%d) return value %d", flags, res);
454 }
455
456 return res;
457 }
458
safe_setns(const char * file,const int lineno,int fd,int nstype)459 int safe_setns(const char *file, const int lineno, int fd, int nstype)
460 {
461 int ret;
462
463 ret = setns(fd, nstype);
464
465 if (ret == -1) {
466 tst_brk_(file, lineno, TBROK | TERRNO, "setns(%i, %i) failed",
467 fd, nstype);
468 } else if (ret) {
469 tst_brk_(file, lineno, TBROK | TERRNO,
470 "Invalid setns(%i, %i) return value %d", fd, nstype,
471 ret);
472 }
473
474 return ret;
475 }
476
tst_safe_ptrace(const char * file,const int lineno,int req,pid_t pid,void * addr,void * data)477 long tst_safe_ptrace(const char *file, const int lineno, int req, pid_t pid,
478 void *addr, void *data)
479 {
480 long ret;
481
482 errno = 0;
483 ret = ptrace(req, pid, addr, data);
484
485 if (ret == -1) {
486 tst_brk_(file, lineno, TBROK | TERRNO, "ptrace() failed");
487 } else if (ret) {
488 tst_brk_(file, lineno, TBROK | TERRNO,
489 "Invalid ptrace() return value %ld", ret);
490 }
491
492 return ret;
493 }
494
safe_pipe2(const char * file,const int lineno,int fildes[2],int flags)495 int safe_pipe2(const char *file, const int lineno, int fildes[2], int flags)
496 {
497 int ret;
498
499 ret = pipe2(fildes, flags);
500
501 if (ret == -1) {
502 tst_brk_(file, lineno, TBROK | TERRNO,
503 "pipe2({%d,%d}) failed with flag(%d)", fildes[0],
504 fildes[1], flags);
505 } else if (ret) {
506 tst_brk_(file, lineno, TBROK | TERRNO,
507 "Invalid pipe2({%d,%d}, %d) return value %d",
508 fildes[0], fildes[1], flags, ret);
509 }
510
511 return ret;
512 }
513
safe_dup(const char * file,const int lineno,int oldfd)514 int safe_dup(const char *file, const int lineno, int oldfd)
515 {
516 int rval;
517
518 rval = dup(oldfd);
519
520 if (rval == -1) {
521 tst_brk_(file, lineno, TBROK | TERRNO,
522 "dup(%i) failed", oldfd);
523 } else if (rval < 0) {
524 tst_brk_(file, lineno, TBROK | TERRNO,
525 "Invalid dup(%i) return value %d", oldfd, rval);
526 }
527
528 return rval;
529 }
530
safe_dup2(const char * file,const int lineno,int oldfd,int newfd)531 int safe_dup2(const char *file, const int lineno, int oldfd, int newfd)
532 {
533 int rval;
534
535 rval = dup2(oldfd, newfd);
536
537 if (rval == -1) {
538 tst_brk_(file, lineno, TBROK | TERRNO,
539 "dup2(%i, %i) failed", oldfd, newfd);
540 } else if (rval != newfd) {
541 tst_brk_(file, lineno, TBROK | TERRNO,
542 "Invalid dup2(%i, %i) return value %d",
543 oldfd, newfd, rval);
544 }
545
546 return rval;
547 }
548
safe_calloc(const char * file,const int lineno,size_t nmemb,size_t size)549 void *safe_calloc(const char *file, const int lineno, size_t nmemb, size_t size)
550 {
551 void *rval;
552
553 rval = calloc(nmemb, size);
554
555 if (rval == NULL) {
556 tst_brk_(file, lineno, TBROK | TERRNO,
557 "calloc(%zu, %zu) failed", nmemb, size);
558 }
559
560 return rval;
561 }
562
safe_realloc(const char * file,const int lineno,void * ptr,size_t size)563 void *safe_realloc(const char *file, const int lineno, void *ptr, size_t size)
564 {
565 void *ret;
566
567 ret = realloc(ptr, size);
568
569 if (!ret) {
570 tst_brk_(file, lineno, TBROK | TERRNO,
571 "realloc(%p, %zu) failed", ptr, size);
572 }
573
574 return ret;
575 }
576
safe_signal(const char * file,const int lineno,int signum,sighandler_t handler)577 sighandler_t safe_signal(const char *file, const int lineno,
578 int signum, sighandler_t handler)
579 {
580 sighandler_t rval;
581
582 rval = signal(signum, handler);
583
584 if (rval == SIG_ERR) {
585 tst_brk_(file, lineno, TBROK | TERRNO,
586 "signal(%d,%p) failed",
587 signum, handler);
588 }
589
590 return rval;
591 }
592
safe_cmd(const char * file,const int lineno,const char * const argv[],const char * stdout_path,const char * stderr_path)593 void safe_cmd(const char *file, const int lineno, const char *const argv[],
594 const char *stdout_path, const char *stderr_path)
595 {
596 int rval;
597
598 switch ((rval = tst_cmd(argv, stdout_path, stderr_path,
599 TST_CMD_PASS_RETVAL | TST_CMD_TCONF_ON_MISSING))) {
600 case 0:
601 break;
602 default:
603 tst_brk_(file, lineno, TBROK, "%s failed (%d)", argv[0], rval);
604 }
605 }
606
safe_msync(const char * file,const int lineno,void * addr,size_t length,int flags)607 int safe_msync(const char *file, const int lineno, void *addr,
608 size_t length, int flags)
609 {
610 int rval;
611
612 rval = msync(addr, length, flags);
613
614 if (rval == -1) {
615 tst_brk_(file, lineno, TBROK | TERRNO,
616 "msync(%p, %zu, %d) failed", addr, length, flags);
617 } else if (rval) {
618 tst_brk_(file, lineno, TBROK | TERRNO,
619 "Invalid msync(%p, %zu, %d) return value %d",
620 addr, length, flags, rval);
621 }
622
623 return rval;
624 }
625
safe_print_file(const char * file,const int lineno,char * path)626 void safe_print_file(const char *file, const int lineno, char *path)
627 {
628 FILE *pfile;
629 char line[PATH_MAX];
630
631 tst_res(TINFO, "=== %s ===", path);
632
633 pfile = safe_fopen(file, lineno, NULL, path, "r");
634
635 while (fgets(line, sizeof(line), pfile))
636 fprintf(stderr, "%s", line);
637
638 safe_fclose(file, lineno, NULL, pfile);
639 }
640
safe_sscanf(const char * file,const int lineno,const char * restrict buffer,const char * restrict format,...)641 int safe_sscanf(const char *file, const int lineno, const char *restrict buffer, const char *restrict format, ...)
642 {
643 va_list args;
644
645 va_start(args, format);
646 int ret = vsscanf(buffer, format, args);
647
648 va_end(args);
649 int placeholders = tst_count_scanf_conversions(format);
650
651 if (ret == EOF)
652 tst_brk_(file, lineno, TBROK | TERRNO, "got EOF from sscanf()");
653
654 if (ret != placeholders)
655 tst_brk_(file, lineno, TBROK | TERRNO, "wrong number of conversion, expected %d, got %d", placeholders, ret);
656
657 return ret;
658 }
659
660 #define PROT_FLAG_STR(f) #f " | "
tst_prot_to_str(const int prot,char * buf)661 void tst_prot_to_str(const int prot, char *buf)
662 {
663 char *ptr = buf;
664
665 if (prot == PROT_NONE) {
666 strcpy(buf, "PROT_NONE");
667 return;
668 }
669
670 if (prot & PROT_READ) {
671 strcpy(ptr, PROT_FLAG_STR(PROT_READ));
672 ptr += sizeof(PROT_FLAG_STR(PROT_READ)) - 1;
673 }
674
675 if (prot & PROT_WRITE) {
676 strcpy(ptr, PROT_FLAG_STR(PROT_WRITE));
677 ptr += sizeof(PROT_FLAG_STR(PROT_WRITE)) - 1;
678 }
679
680 if (prot & PROT_EXEC) {
681 strcpy(ptr, PROT_FLAG_STR(PROT_EXEC));
682 ptr += sizeof(PROT_FLAG_STR(PROT_EXEC)) - 1;
683 }
684
685 if (buf != ptr)
686 ptr[-3] = 0;
687 }
688
safe_mprotect(const char * file,const int lineno,char * addr,size_t len,int prot)689 int safe_mprotect(const char *file, const int lineno,
690 char *addr, size_t len, int prot)
691 {
692 int rval;
693 char prot_buf[512];
694
695 tst_prot_to_str(prot, prot_buf);
696
697 tst_res_(file, lineno, TDEBUG,
698 "mprotect(%p, %ld, %s(%x))", addr, len, prot_buf, prot);
699
700 rval = mprotect(addr, len, prot);
701
702 if (rval == -1) {
703 tst_brk_(file, lineno, TBROK | TERRNO,
704 "mprotect(%p, %ld, %s(%x))", addr, len, prot_buf, prot);
705 } else if (rval) {
706 tst_brk_(file, lineno, TBROK | TERRNO,
707 "mprotect(%p, %ld, %s(%x)) return value %d",
708 addr, len, prot_buf, prot, rval);
709 }
710
711 return rval;
712 }
713