1 /* Copyright (C) 2004-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library 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 GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <pthread.h>
19 #include <pwd.h>
20 #include <grp.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 
26 
27 static pthread_barrier_t b3, b4;
28 static uid_t prev_ruid, prev_euid, prev_suid, nobody_uid;
29 static gid_t prev_rgid, prev_egid, prev_sgid, nobody_gid;
30 enum ACTION { PREPARE, SET, CHECK_BEFORE, CHECK_AFTER };
31 #define TESTNO(arg) ((long int) (arg) & 0xff)
32 #define THREADNO(arg) ((long int) (arg) >> 8)
33 
34 
35 static void
check_prev_uid(int tno)36 check_prev_uid (int tno)
37 {
38   uid_t ruid, euid, suid;
39   if (getresuid (&ruid, &euid, &suid) < 0)
40     {
41       printf ("getresuid failed: %d %m\n", tno);
42       exit (1);
43     }
44 
45   if (ruid != prev_ruid || euid != prev_euid || suid != prev_suid)
46     {
47       printf ("uids before in %d (%d %d %d) != (%d %d %d)\n", tno,
48 	      ruid, euid, suid, prev_ruid, prev_euid, prev_suid);
49       exit (1);
50     }
51 }
52 
53 
54 static void
check_prev_gid(int tno)55 check_prev_gid (int tno)
56 {
57   gid_t rgid, egid, sgid;
58   if (getresgid (&rgid, &egid, &sgid) < 0)
59     {
60       printf ("getresgid failed: %d %m\n", tno);
61       exit (1);
62     }
63 
64   if (rgid != prev_rgid || egid != prev_egid || sgid != prev_sgid)
65     {
66       printf ("gids before in %d (%d %d %d) != (%d %d %d)\n", tno,
67 	      rgid, egid, sgid, prev_rgid, prev_egid, prev_sgid);
68       exit (1);
69     }
70 }
71 
72 
73 static void
test_setuid1(enum ACTION action,int tno)74 test_setuid1 (enum ACTION action, int tno)
75 {
76   if (action == PREPARE)
77     return;
78 
79   if (action != CHECK_AFTER)
80     check_prev_uid (tno);
81 
82   if (action == SET && setuid (nobody_uid) < 0)
83     {
84        printf ("setuid failed: %m\n");
85        exit (1);
86     }
87 
88   if (action != CHECK_BEFORE)
89     {
90       uid_t ruid, euid, suid;
91       if (getresuid (&ruid, &euid, &suid) < 0)
92 	{
93 	  printf ("getresuid failed: %d %m\n", tno);
94 	  exit (1);
95 	}
96 
97       if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid)
98 	{
99 	  printf ("after setuid %d (%d %d %d) != (%d %d %d)\n", tno,
100 		  ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid);
101 	  exit (1);
102 	}
103     }
104 }
105 
106 
107 static void
test_setuid2(enum ACTION action,int tno)108 test_setuid2 (enum ACTION action, int tno)
109 {
110   if (action == PREPARE)
111     {
112       if (setresuid (nobody_uid, nobody_uid, -1) < 0)
113 	{
114 	  printf ("setresuid failed: %m\n");
115 	  exit (1);
116 	}
117 
118       prev_ruid = nobody_uid;
119       prev_euid = nobody_uid;
120       return;
121     }
122 
123   if (action != CHECK_AFTER)
124     check_prev_uid (tno);
125 
126   if (action == SET && setuid (prev_suid) < 0)
127     {
128       printf ("setuid failed: %m\n");
129       exit (1);
130     }
131 
132   if (action != CHECK_BEFORE)
133     {
134       uid_t ruid, euid, suid;
135       if (getresuid (&ruid, &euid, &suid) < 0)
136 	{
137 	  printf ("getresuid failed: %d %m\n", tno);
138 	  exit (1);
139 	}
140 
141       if (ruid != nobody_uid || euid != prev_suid || suid != prev_suid)
142 	{
143 	  printf ("after setuid %d (%d %d %d) != (%d %d %d)\n", tno,
144 		  ruid, euid, suid, nobody_uid, prev_suid, prev_suid);
145 	  exit (1);
146 	}
147     }
148 }
149 
150 
151 static void
test_seteuid1(enum ACTION action,int tno)152 test_seteuid1 (enum ACTION action, int tno)
153 {
154   if (action == PREPARE)
155     return;
156 
157   if (action != CHECK_AFTER)
158     check_prev_uid (tno);
159 
160   if (action == SET && seteuid (nobody_uid) < 0)
161     {
162        printf ("seteuid failed: %m\n");
163        exit (1);
164     }
165 
166   if (action != CHECK_BEFORE)
167     {
168       uid_t ruid, euid, suid;
169       if (getresuid (&ruid, &euid, &suid) < 0)
170 	{
171 	  printf ("getresuid failed: %d %m\n", tno);
172 	  exit (1);
173 	}
174 
175       if (ruid != prev_ruid || euid != nobody_uid || suid != prev_suid)
176 	{
177 	  printf ("after seteuid %d (%d %d %d) != (%d %d %d)\n", tno,
178 		  ruid, euid, suid, prev_ruid, nobody_uid, prev_suid);
179 	  exit (1);
180 	}
181     }
182 }
183 
184 
185 static void
test_seteuid2(enum ACTION action,int tno)186 test_seteuid2 (enum ACTION action, int tno)
187 {
188   if (action == PREPARE)
189     {
190       if (setresuid (nobody_uid, nobody_uid, -1) < 0)
191 	{
192 	  printf ("setresuid failed: %m\n");
193 	  exit (1);
194 	}
195 
196       prev_ruid = nobody_uid;
197       prev_euid = nobody_uid;
198       nobody_uid = prev_suid;
199       return;
200     }
201 
202   test_seteuid1 (action, tno);
203 }
204 
205 
206 static void
test_setreuid1(enum ACTION action,int tno)207 test_setreuid1 (enum ACTION action, int tno)
208 {
209   if (action == PREPARE)
210     return;
211 
212   if (action != CHECK_AFTER)
213     check_prev_uid (tno);
214 
215   if (action == SET && setreuid (-1, nobody_uid) < 0)
216     {
217        printf ("setreuid failed: %m\n");
218        exit (1);
219     }
220 
221   if (action != CHECK_BEFORE)
222     {
223       uid_t ruid, euid, suid, esuid;
224       if (getresuid (&ruid, &euid, &suid) < 0)
225 	{
226 	  printf ("getresuid failed: %d %m\n", tno);
227 	  exit (1);
228 	}
229 
230       if (prev_ruid != nobody_uid)
231 	esuid = nobody_uid;
232       else
233 	esuid = prev_suid;
234 
235       if (ruid != prev_ruid || euid != nobody_uid || suid != esuid)
236 	{
237 	  printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno,
238 		  ruid, euid, suid, prev_ruid, nobody_uid, esuid);
239 	  exit (1);
240 	}
241     }
242 }
243 
244 
245 static void
test_setreuid2(enum ACTION action,int tno)246 test_setreuid2 (enum ACTION action, int tno)
247 {
248   if (action == PREPARE)
249     return;
250 
251   if (action != CHECK_AFTER)
252     check_prev_uid (tno);
253 
254   if (action == SET && setreuid (nobody_uid, -1) < 0)
255     {
256        printf ("setreuid failed: %m\n");
257        exit (1);
258     }
259 
260   if (action != CHECK_BEFORE)
261     {
262       uid_t ruid, euid, suid;
263       if (getresuid (&ruid, &euid, &suid) < 0)
264 	{
265 	  printf ("getresuid failed: %d %m\n", tno);
266 	  exit (1);
267 	}
268 
269       if (ruid != nobody_uid || euid != prev_euid || suid != prev_euid)
270 	{
271 	  printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno,
272 		  ruid, euid, suid, nobody_uid, prev_euid, prev_euid);
273 	  exit (1);
274 	}
275     }
276 }
277 
278 
279 static void
test_setreuid3(enum ACTION action,int tno)280 test_setreuid3 (enum ACTION action, int tno)
281 {
282   if (action == PREPARE)
283     return;
284 
285   if (action != CHECK_AFTER)
286     check_prev_uid (tno);
287 
288   if (action == SET && setreuid (nobody_uid, nobody_uid) < 0)
289     {
290        printf ("setreuid failed: %m\n");
291        exit (1);
292     }
293 
294   if (action != CHECK_BEFORE)
295     {
296       uid_t ruid, euid, suid;
297       if (getresuid (&ruid, &euid, &suid) < 0)
298 	{
299 	  printf ("getresuid failed: %d %m\n", tno);
300 	  exit (1);
301 	}
302 
303       if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid)
304 	{
305 	  printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno,
306 		  ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid);
307 	  exit (1);
308 	}
309     }
310 }
311 
312 
313 static void
test_setreuid4(enum ACTION action,int tno)314 test_setreuid4 (enum ACTION action, int tno)
315 {
316   if (action == PREPARE)
317     {
318       if (setresuid (nobody_uid, nobody_uid, -1) < 0)
319 	{
320 	  printf ("setresuid failed: %m\n");
321 	  exit (1);
322 	}
323 
324       prev_ruid = nobody_uid;
325       prev_euid = nobody_uid;
326       nobody_uid = prev_suid;
327       return;
328     }
329 
330   test_setreuid1 (action, tno);
331 }
332 
333 
334 static void
test_setresuid1(enum ACTION action,int tno)335 test_setresuid1 (enum ACTION action, int tno)
336 {
337   if (action == PREPARE)
338     return;
339 
340   if (action != CHECK_AFTER)
341     check_prev_uid (tno);
342 
343   if (action == SET && setresuid (-1, nobody_uid, -1) < 0)
344     {
345        printf ("setresuid failed: %m\n");
346        exit (1);
347     }
348 
349   if (action != CHECK_BEFORE)
350     {
351       uid_t ruid, euid, suid;
352       if (getresuid (&ruid, &euid, &suid) < 0)
353 	{
354 	  printf ("getresuid failed: %d %m\n", tno);
355 	  exit (1);
356 	}
357 
358       if (ruid != prev_ruid || euid != nobody_uid || suid != prev_suid)
359 	{
360 	  printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno,
361 		  ruid, euid, suid, prev_ruid, nobody_uid, prev_suid);
362 	  exit (1);
363 	}
364     }
365 }
366 
367 
368 static void
test_setresuid2(enum ACTION action,int tno)369 test_setresuid2 (enum ACTION action, int tno)
370 {
371   if (action == PREPARE)
372     return;
373 
374   if (action != CHECK_AFTER)
375     check_prev_uid (tno);
376 
377   if (action == SET && setresuid (prev_euid, nobody_uid, nobody_uid) < 0)
378     {
379        printf ("setresuid failed: %m\n");
380        exit (1);
381     }
382 
383   if (action != CHECK_BEFORE)
384     {
385       uid_t ruid, euid, suid;
386       if (getresuid (&ruid, &euid, &suid) < 0)
387 	{
388 	  printf ("getresuid failed: %d %m\n", tno);
389 	  exit (1);
390 	}
391 
392       if (ruid != prev_euid || euid != nobody_uid || suid != nobody_uid)
393 	{
394 	  printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno,
395 		  ruid, euid, suid, prev_euid, nobody_uid, nobody_uid);
396 	  exit (1);
397 	}
398     }
399 }
400 
401 
402 static void
test_setresuid3(enum ACTION action,int tno)403 test_setresuid3 (enum ACTION action, int tno)
404 {
405   if (action == PREPARE)
406     return;
407 
408   if (action != CHECK_AFTER)
409     check_prev_uid (tno);
410 
411   if (action == SET && setresuid (nobody_uid, nobody_uid, nobody_uid) < 0)
412     {
413        printf ("setresuid failed: %m\n");
414        exit (1);
415     }
416 
417   if (action != CHECK_BEFORE)
418     {
419       uid_t ruid, euid, suid;
420       if (getresuid (&ruid, &euid, &suid) < 0)
421 	{
422 	  printf ("getresuid failed: %d %m\n", tno);
423 	  exit (1);
424 	}
425 
426       if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid)
427 	{
428 	  printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno,
429 		  ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid);
430 	  exit (1);
431 	}
432     }
433 }
434 
435 
436 static void
test_setresuid4(enum ACTION action,int tno)437 test_setresuid4 (enum ACTION action, int tno)
438 {
439   if (action == PREPARE)
440     {
441       if (setresuid (nobody_uid, nobody_uid, -1) < 0)
442 	{
443 	  printf ("setresuid failed: %m\n");
444 	  exit (1);
445 	}
446 
447       prev_ruid = nobody_uid;
448       prev_euid = nobody_uid;
449       nobody_uid = prev_suid;
450       return;
451     }
452 
453   test_setresuid1 (action, tno);
454 }
455 
456 
457 static void
test_setgid1(enum ACTION action,int tno)458 test_setgid1 (enum ACTION action, int tno)
459 {
460   if (action == PREPARE)
461     return;
462 
463   if (action != CHECK_AFTER)
464     check_prev_gid (tno);
465 
466   if (action == SET && setgid (nobody_gid) < 0)
467     {
468        printf ("setgid failed: %m\n");
469        exit (1);
470     }
471 
472   if (action != CHECK_BEFORE)
473     {
474       gid_t rgid, egid, sgid;
475       if (getresgid (&rgid, &egid, &sgid) < 0)
476 	{
477 	  printf ("getresgid failed: %d %m\n", tno);
478 	  exit (1);
479 	}
480 
481       if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid)
482 	{
483 	  printf ("after setgid %d (%d %d %d) != (%d %d %d)\n", tno,
484 		  rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid);
485 	  exit (1);
486 	}
487     }
488 }
489 
490 
491 static void
test_setgid2(enum ACTION action,int tno)492 test_setgid2 (enum ACTION action, int tno)
493 {
494   if (action == PREPARE)
495     {
496       if (setresgid (nobody_gid, nobody_gid, -1) < 0)
497 	{
498 	  printf ("setresgid failed: %m\n");
499 	  exit (1);
500 	}
501 
502       prev_rgid = nobody_gid;
503       prev_egid = nobody_gid;
504 
505       if (setresuid (nobody_uid, nobody_uid, -1) < 0)
506 	{
507 	  printf ("setresuid failed: %m\n");
508 	  exit (1);
509 	}
510 
511       prev_ruid = nobody_uid;
512       prev_euid = nobody_uid;
513       return;
514     }
515 
516   if (action != CHECK_AFTER)
517     check_prev_gid (tno);
518 
519   if (action == SET && setgid (prev_sgid) < 0)
520     {
521       printf ("setgid failed: %m\n");
522       exit (1);
523     }
524 
525   if (action != CHECK_BEFORE)
526     {
527       gid_t rgid, egid, sgid;
528       if (getresgid (&rgid, &egid, &sgid) < 0)
529 	{
530 	  printf ("getresgid failed: %d %m\n", tno);
531 	  exit (1);
532 	}
533 
534       if (rgid != nobody_gid || egid != prev_sgid || sgid != prev_sgid)
535 	{
536 	  printf ("after setgid %d (%d %d %d) != (%d %d %d)\n", tno,
537 		  rgid, egid, sgid, nobody_gid, prev_sgid, prev_sgid);
538 	  exit (1);
539 	}
540     }
541 }
542 
543 
544 static void
test_setegid1(enum ACTION action,int tno)545 test_setegid1 (enum ACTION action, int tno)
546 {
547   if (action == PREPARE)
548     return;
549 
550   if (action != CHECK_AFTER)
551     check_prev_gid (tno);
552 
553   if (action == SET && setegid (nobody_gid) < 0)
554     {
555        printf ("setegid failed: %m\n");
556        exit (1);
557     }
558 
559   if (action != CHECK_BEFORE)
560     {
561       gid_t rgid, egid, sgid;
562       if (getresgid (&rgid, &egid, &sgid) < 0)
563 	{
564 	  printf ("getresgid failed: %d %m\n", tno);
565 	  exit (1);
566 	}
567 
568       if (rgid != prev_rgid || egid != nobody_gid || sgid != prev_sgid)
569 	{
570 	  printf ("after setegid %d (%d %d %d) != (%d %d %d)\n", tno,
571 		  rgid, egid, sgid, prev_rgid, nobody_gid, prev_sgid);
572 	  exit (1);
573 	}
574     }
575 }
576 
577 
578 static void
test_setegid2(enum ACTION action,int tno)579 test_setegid2 (enum ACTION action, int tno)
580 {
581   if (action == PREPARE)
582     {
583       if (setresgid (nobody_gid, nobody_gid, -1) < 0)
584 	{
585 	  printf ("setresgid failed: %m\n");
586 	  exit (1);
587 	}
588 
589       prev_rgid = nobody_gid;
590       prev_egid = nobody_gid;
591       nobody_gid = prev_sgid;
592       return;
593     }
594 
595   test_setegid1 (action, tno);
596 }
597 
598 
599 static void
test_setregid1(enum ACTION action,int tno)600 test_setregid1 (enum ACTION action, int tno)
601 {
602   if (action == PREPARE)
603     return;
604 
605   if (action != CHECK_AFTER)
606     check_prev_gid (tno);
607 
608   if (action == SET && setregid (-1, nobody_gid) < 0)
609     {
610        printf ("setregid failed: %m\n");
611        exit (1);
612     }
613 
614   if (action != CHECK_BEFORE)
615     {
616       gid_t rgid, egid, sgid, esgid;
617       if (getresgid (&rgid, &egid, &sgid) < 0)
618 	{
619 	  printf ("getresgid failed: %d %m\n", tno);
620 	  exit (1);
621 	}
622 
623       if (prev_rgid != nobody_gid)
624 	esgid = nobody_gid;
625       else
626 	esgid = prev_sgid;
627 
628       if (rgid != prev_rgid || egid != nobody_gid || sgid != esgid)
629 	{
630 	  printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno,
631 		  rgid, egid, sgid, prev_rgid, nobody_gid, esgid);
632 	  exit (1);
633 	}
634     }
635 }
636 
637 
638 static void
test_setregid2(enum ACTION action,int tno)639 test_setregid2 (enum ACTION action, int tno)
640 {
641   if (action == PREPARE)
642     return;
643 
644   if (action != CHECK_AFTER)
645     check_prev_gid (tno);
646 
647   if (action == SET && setregid (nobody_gid, -1) < 0)
648     {
649        printf ("setregid failed: %m\n");
650        exit (1);
651     }
652 
653   if (action != CHECK_BEFORE)
654     {
655       gid_t rgid, egid, sgid;
656       if (getresgid (&rgid, &egid, &sgid) < 0)
657 	{
658 	  printf ("getresgid failed: %d %m\n", tno);
659 	  exit (1);
660 	}
661 
662       if (rgid != nobody_gid || egid != prev_egid || sgid != prev_egid)
663 	{
664 	  printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno,
665 		  rgid, egid, sgid, nobody_gid, prev_egid, prev_egid);
666 	  exit (1);
667 	}
668     }
669 }
670 
671 
672 static void
test_setregid3(enum ACTION action,int tno)673 test_setregid3 (enum ACTION action, int tno)
674 {
675   if (action == PREPARE)
676     return;
677 
678   if (action != CHECK_AFTER)
679     check_prev_gid (tno);
680 
681   if (action == SET && setregid (nobody_gid, nobody_gid) < 0)
682     {
683        printf ("setregid failed: %m\n");
684        exit (1);
685     }
686 
687   if (action != CHECK_BEFORE)
688     {
689       gid_t rgid, egid, sgid;
690       if (getresgid (&rgid, &egid, &sgid) < 0)
691 	{
692 	  printf ("getresgid failed: %d %m\n", tno);
693 	  exit (1);
694 	}
695 
696       if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid)
697 	{
698 	  printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno,
699 		  rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid);
700 	  exit (1);
701 	}
702     }
703 }
704 
705 
706 static void
test_setregid4(enum ACTION action,int tno)707 test_setregid4 (enum ACTION action, int tno)
708 {
709   if (action == PREPARE)
710     {
711       if (setresgid (nobody_gid, nobody_gid, -1) < 0)
712 	{
713 	  printf ("setresgid failed: %m\n");
714 	  exit (1);
715 	}
716 
717       prev_rgid = nobody_gid;
718       prev_egid = nobody_gid;
719       nobody_gid = prev_sgid;
720       return;
721     }
722 
723   test_setregid1 (action, tno);
724 }
725 
726 
727 static void
test_setresgid1(enum ACTION action,int tno)728 test_setresgid1 (enum ACTION action, int tno)
729 {
730   if (action == PREPARE)
731     return;
732 
733   if (action != CHECK_AFTER)
734     check_prev_gid (tno);
735 
736   if (action == SET && setresgid (-1, nobody_gid, -1) < 0)
737     {
738        printf ("setresgid failed: %m\n");
739        exit (1);
740     }
741 
742   if (action != CHECK_BEFORE)
743     {
744       gid_t rgid, egid, sgid;
745       if (getresgid (&rgid, &egid, &sgid) < 0)
746 	{
747 	  printf ("getresgid failed: %d %m\n", tno);
748 	  exit (1);
749 	}
750 
751       if (rgid != prev_rgid || egid != nobody_gid || sgid != prev_sgid)
752 	{
753 	  printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno,
754 		  rgid, egid, sgid, prev_rgid, nobody_gid, prev_sgid);
755 	  exit (1);
756 	}
757     }
758 }
759 
760 
761 static void
test_setresgid2(enum ACTION action,int tno)762 test_setresgid2 (enum ACTION action, int tno)
763 {
764   if (action == PREPARE)
765     return;
766 
767   if (action != CHECK_AFTER)
768     check_prev_gid (tno);
769 
770   if (action == SET && setresgid (prev_egid, nobody_gid, nobody_gid) < 0)
771     {
772        printf ("setresgid failed: %m\n");
773        exit (1);
774     }
775 
776   if (action != CHECK_BEFORE)
777     {
778       gid_t rgid, egid, sgid;
779       if (getresgid (&rgid, &egid, &sgid) < 0)
780 	{
781 	  printf ("getresgid failed: %d %m\n", tno);
782 	  exit (1);
783 	}
784 
785       if (rgid != prev_egid || egid != nobody_gid || sgid != nobody_gid)
786 	{
787 	  printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno,
788 		  rgid, egid, sgid, prev_egid, nobody_gid, nobody_gid);
789 	  exit (1);
790 	}
791     }
792 }
793 
794 
795 static void
test_setresgid3(enum ACTION action,int tno)796 test_setresgid3 (enum ACTION action, int tno)
797 {
798   if (action == PREPARE)
799     return;
800 
801   if (action != CHECK_AFTER)
802     check_prev_gid (tno);
803 
804   if (action == SET && setresgid (nobody_gid, nobody_gid, nobody_gid) < 0)
805     {
806        printf ("setresgid failed: %m\n");
807        exit (1);
808     }
809 
810   if (action != CHECK_BEFORE)
811     {
812       gid_t rgid, egid, sgid;
813       if (getresgid (&rgid, &egid, &sgid) < 0)
814 	{
815 	  printf ("getresgid failed: %d %m\n", tno);
816 	  exit (1);
817 	}
818 
819       if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid)
820 	{
821 	  printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno,
822 		  rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid);
823 	  exit (1);
824 	}
825     }
826 }
827 
828 
829 static void
test_setresgid4(enum ACTION action,int tno)830 test_setresgid4 (enum ACTION action, int tno)
831 {
832   if (action == PREPARE)
833     {
834       if (setresgid (nobody_gid, nobody_gid, -1) < 0)
835 	{
836 	  printf ("setresgid failed: %m\n");
837 	  exit (1);
838 	}
839 
840       prev_rgid = nobody_gid;
841       prev_egid = nobody_gid;
842       nobody_gid = prev_sgid;
843       return;
844     }
845 
846   test_setresgid1 (action, tno);
847 }
848 
849 
850 static struct setuid_test
851 {
852   const char *name;
853   void (*test) (enum ACTION, int tno);
854 } setuid_tests[] =
855 {
856   { "setuid1", test_setuid1 },
857   { "setuid2", test_setuid2 },
858   { "seteuid1", test_seteuid1 },
859   { "seteuid2", test_seteuid2 },
860   { "setreuid1", test_setreuid1 },
861   { "setreuid2", test_setreuid2 },
862   { "setreuid3", test_setreuid3 },
863   { "setreuid4", test_setreuid4 },
864   { "setresuid1", test_setresuid1 },
865   { "setresuid2", test_setresuid2 },
866   { "setresuid3", test_setresuid3 },
867   { "setresuid4", test_setresuid4 },
868   { "setgid1", test_setgid1 },
869   { "setgid2", test_setgid2 },
870   { "setegid1", test_setegid1 },
871   { "setegid2", test_setegid2 },
872   { "setregid1", test_setregid1 },
873   { "setregid2", test_setregid2 },
874   { "setregid3", test_setregid3 },
875   { "setregid4", test_setregid4 },
876   { "setresgid1", test_setresgid1 },
877   { "setresgid2", test_setresgid2 },
878   { "setresgid3", test_setresgid3 },
879   { "setresgid4", test_setresgid4 }
880 };
881 
882 
883 static void *
tf2(void * arg)884 tf2 (void *arg)
885 {
886   int e = pthread_barrier_wait (&b4);
887   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
888     {
889       puts ("barrier_wait failed");
890       exit (1);
891     }
892 
893   setuid_tests[TESTNO (arg)].test (CHECK_AFTER, THREADNO (arg));
894   return NULL;
895 }
896 
897 
898 static void *
tf(void * arg)899 tf (void *arg)
900 {
901   setuid_tests[TESTNO (arg)].test (CHECK_BEFORE, THREADNO (arg));
902 
903   int e = pthread_barrier_wait (&b3);
904   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
905     {
906       puts ("barrier_wait failed");
907       exit (1);
908     }
909 
910   return tf2 (arg);
911 }
912 
913 
914 static int
do_one_test(long int testno)915 do_one_test (long int testno)
916 {
917   printf ("%s test\n", setuid_tests[testno].name);
918 
919   pid_t pid = fork ();
920   if (pid == 0)
921     {
922       setuid_tests[testno].test (PREPARE, 0);
923       setuid_tests[testno].test (SET, 0);
924       exit (0);
925     }
926 
927   if (pid < 0)
928     {
929       printf ("fork failed: %m\n");
930       exit (1);
931     }
932 
933   int status;
934   if (waitpid (pid, &status, 0) < 0)
935     {
936       printf ("waitpid failed: %m\n");
937       exit (1);
938     }
939 
940   if (!WIFEXITED (status))
941     {
942       puts ("child did not exit");
943       exit (1);
944     }
945 
946   if (WEXITSTATUS (status))
947     {
948       printf ("skipping %s test\n", setuid_tests[testno].name);
949       return 0;
950     }
951 
952   pid = fork ();
953   if (pid == 0)
954     {
955       setuid_tests[testno].test (PREPARE, 0);
956 
957       pthread_t th;
958       int e = pthread_create (&th, NULL, tf, (void *) (testno | 0x100L));
959       if (e != 0)
960 	{
961 	  printf ("create failed: %m\n");
962 	  exit (1);
963 	}
964 
965       pthread_t th2;
966       e = pthread_create (&th2, NULL, tf, (void *) (testno | 0x200L));
967       if (e != 0)
968 	{
969 	  printf ("create failed: %m\n");
970 	  exit (1);
971 	}
972 
973       e = pthread_barrier_wait (&b3);
974       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
975 	{
976 	  puts ("barrier_wait failed");
977 	  exit (1);
978 	}
979 
980       setuid_tests[testno].test (SET, 0);
981 
982       pthread_t th3;
983       e = pthread_create (&th3, NULL, tf2, (void *) (testno | 0x300L));
984       if (e != 0)
985 	{
986 	  printf ("create failed: %m\n");
987 	  exit (1);
988 	}
989 
990       e = pthread_barrier_wait (&b4);
991       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
992 	{
993 	  puts ("barrier_wait failed");
994 	  exit (1);
995 	}
996 
997       exit (0);
998     }
999 
1000   if (pid < 0)
1001     {
1002       printf ("fork failed: %m\n");
1003       exit (1);
1004     }
1005 
1006   if (waitpid (pid, &status, 0) < 0)
1007     {
1008       printf ("waitpid failed: %m\n");
1009       exit (1);
1010     }
1011 
1012   if (!WIFEXITED (status))
1013     {
1014       puts ("second child did not exit");
1015       exit (1);
1016     }
1017 
1018   if (WEXITSTATUS (status))
1019     exit (WEXITSTATUS (status));
1020 
1021   return 0;
1022 }
1023 
1024 
1025 static int
do_test(void)1026 do_test (void)
1027 {
1028   struct passwd *pwd = getpwnam ("nobody");
1029   if (pwd == NULL)
1030     {
1031       puts ("User nobody doesn't exist");
1032       return 0;
1033     }
1034   nobody_uid = pwd->pw_uid;
1035   nobody_gid = pwd->pw_gid;
1036 
1037   if (getresuid (&prev_ruid, &prev_euid, &prev_suid) < 0)
1038     {
1039       printf ("getresuid failed: %m\n");
1040       exit (1);
1041     }
1042 
1043   if (getresgid (&prev_rgid, &prev_egid, &prev_sgid) < 0)
1044     {
1045       printf ("getresgid failed: %m\n");
1046       exit (1);
1047     }
1048 
1049   if (prev_ruid == nobody_uid || prev_euid == nobody_uid
1050       || prev_suid == nobody_uid)
1051     {
1052       puts ("already running as user nobody, skipping tests");
1053       exit (0);
1054     }
1055 
1056   if (prev_rgid == nobody_gid || prev_egid == nobody_gid
1057       || prev_sgid == nobody_gid)
1058     {
1059       puts ("already running as group nobody, skipping tests");
1060       exit (0);
1061     }
1062 
1063   if (pthread_barrier_init (&b3, NULL, 3) != 0)
1064     {
1065       puts ("barrier_init failed");
1066       exit (1);
1067     }
1068 
1069   if (pthread_barrier_init (&b4, NULL, 4) != 0)
1070     {
1071       puts ("barrier_init failed");
1072       exit (1);
1073     }
1074 
1075   for (unsigned long int testno = 0;
1076        testno < sizeof (setuid_tests) / sizeof (setuid_tests[0]);
1077        ++testno)
1078     do_one_test (testno);
1079   return 0;
1080 }
1081 
1082 #define TEST_FUNCTION do_test ()
1083 #include "../test-skeleton.c"
1084