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 |
36 | check_prev_uid (int tno) |
37 | { |
38 | uid_t ruid, euid, suid; |
39 | if (getresuid (ruid: &ruid, euid: &euid, suid: &suid) < 0) |
40 | { |
41 | printf (format: "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 (format: "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 |
55 | check_prev_gid (int tno) |
56 | { |
57 | gid_t rgid, egid, sgid; |
58 | if (getresgid (rgid: &rgid, egid: &egid, sgid: &sgid) < 0) |
59 | { |
60 | printf (format: "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 (format: "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 |
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 (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
92 | { |
93 | printf (format: "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 (format: "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 |
108 | test_setuid2 (enum ACTION action, int tno) |
109 | { |
110 | if (action == PREPARE) |
111 | { |
112 | if (setresuid (ruid: nobody_uid, euid: nobody_uid, suid: -1) < 0) |
113 | { |
114 | printf (format: "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 (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
136 | { |
137 | printf (format: "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 (format: "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 |
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 (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
170 | { |
171 | printf (format: "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 (format: "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 |
186 | test_seteuid2 (enum ACTION action, int tno) |
187 | { |
188 | if (action == PREPARE) |
189 | { |
190 | if (setresuid (ruid: nobody_uid, euid: nobody_uid, suid: -1) < 0) |
191 | { |
192 | printf (format: "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 |
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 (ruid: -1, euid: nobody_uid) < 0) |
216 | { |
217 | printf (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
225 | { |
226 | printf (format: "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 (format: "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 |
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 (ruid: nobody_uid, euid: -1) < 0) |
255 | { |
256 | printf (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
264 | { |
265 | printf (format: "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 (format: "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 |
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 (ruid: nobody_uid, euid: nobody_uid) < 0) |
289 | { |
290 | printf (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
298 | { |
299 | printf (format: "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 (format: "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 |
314 | test_setreuid4 (enum ACTION action, int tno) |
315 | { |
316 | if (action == PREPARE) |
317 | { |
318 | if (setresuid (ruid: nobody_uid, euid: nobody_uid, suid: -1) < 0) |
319 | { |
320 | printf (format: "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 |
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 (ruid: -1, euid: nobody_uid, suid: -1) < 0) |
344 | { |
345 | printf (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
353 | { |
354 | printf (format: "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 (format: "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 |
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 (ruid: prev_euid, euid: nobody_uid, suid: nobody_uid) < 0) |
378 | { |
379 | printf (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
387 | { |
388 | printf (format: "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 (format: "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 |
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 (ruid: nobody_uid, euid: nobody_uid, suid: nobody_uid) < 0) |
412 | { |
413 | printf (format: "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: &ruid, euid: &euid, suid: &suid) < 0) |
421 | { |
422 | printf (format: "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 (format: "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 |
437 | test_setresuid4 (enum ACTION action, int tno) |
438 | { |
439 | if (action == PREPARE) |
440 | { |
441 | if (setresuid (ruid: nobody_uid, euid: nobody_uid, suid: -1) < 0) |
442 | { |
443 | printf (format: "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 |
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 (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
476 | { |
477 | printf (format: "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 (format: "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 |
492 | test_setgid2 (enum ACTION action, int tno) |
493 | { |
494 | if (action == PREPARE) |
495 | { |
496 | if (setresgid (rgid: nobody_gid, egid: nobody_gid, sgid: -1) < 0) |
497 | { |
498 | printf (format: "setresgid failed: %m\n" ); |
499 | exit (1); |
500 | } |
501 | |
502 | prev_rgid = nobody_gid; |
503 | prev_egid = nobody_gid; |
504 | |
505 | if (setresuid (ruid: nobody_uid, euid: nobody_uid, suid: -1) < 0) |
506 | { |
507 | printf (format: "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 (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
529 | { |
530 | printf (format: "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 (format: "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 |
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 (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
563 | { |
564 | printf (format: "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 (format: "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 |
579 | test_setegid2 (enum ACTION action, int tno) |
580 | { |
581 | if (action == PREPARE) |
582 | { |
583 | if (setresgid (rgid: nobody_gid, egid: nobody_gid, sgid: -1) < 0) |
584 | { |
585 | printf (format: "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 |
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 (rgid: -1, egid: nobody_gid) < 0) |
609 | { |
610 | printf (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
618 | { |
619 | printf (format: "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 (format: "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 |
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 (rgid: nobody_gid, egid: -1) < 0) |
648 | { |
649 | printf (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
657 | { |
658 | printf (format: "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 (format: "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 |
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 (rgid: nobody_gid, egid: nobody_gid) < 0) |
682 | { |
683 | printf (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
691 | { |
692 | printf (format: "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 (format: "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 |
707 | test_setregid4 (enum ACTION action, int tno) |
708 | { |
709 | if (action == PREPARE) |
710 | { |
711 | if (setresgid (rgid: nobody_gid, egid: nobody_gid, sgid: -1) < 0) |
712 | { |
713 | printf (format: "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 |
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 (rgid: -1, egid: nobody_gid, sgid: -1) < 0) |
737 | { |
738 | printf (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
746 | { |
747 | printf (format: "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 (format: "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 |
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 (rgid: prev_egid, egid: nobody_gid, sgid: nobody_gid) < 0) |
771 | { |
772 | printf (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
780 | { |
781 | printf (format: "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 (format: "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 |
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 (rgid: nobody_gid, egid: nobody_gid, sgid: nobody_gid) < 0) |
805 | { |
806 | printf (format: "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: &rgid, egid: &egid, sgid: &sgid) < 0) |
814 | { |
815 | printf (format: "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 (format: "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 |
830 | test_setresgid4 (enum ACTION action, int tno) |
831 | { |
832 | if (action == PREPARE) |
833 | { |
834 | if (setresgid (rgid: nobody_gid, egid: nobody_gid, sgid: -1) < 0) |
835 | { |
836 | printf (format: "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 * |
884 | tf2 (void *arg) |
885 | { |
886 | int e = pthread_barrier_wait (barrier: &b4); |
887 | if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) |
888 | { |
889 | puts (s: "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 * |
899 | tf (void *arg) |
900 | { |
901 | setuid_tests[TESTNO (arg)].test (CHECK_BEFORE, THREADNO (arg)); |
902 | |
903 | int e = pthread_barrier_wait (barrier: &b3); |
904 | if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) |
905 | { |
906 | puts (s: "barrier_wait failed" ); |
907 | exit (1); |
908 | } |
909 | |
910 | return tf2 (arg); |
911 | } |
912 | |
913 | |
914 | static int |
915 | do_one_test (long int testno) |
916 | { |
917 | printf (format: "%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 (format: "fork failed: %m\n" ); |
930 | exit (1); |
931 | } |
932 | |
933 | int status; |
934 | if (waitpid (pid: pid, stat_loc: &status, options: 0) < 0) |
935 | { |
936 | printf (format: "waitpid failed: %m\n" ); |
937 | exit (1); |
938 | } |
939 | |
940 | if (!WIFEXITED (status)) |
941 | { |
942 | puts (s: "child did not exit" ); |
943 | exit (1); |
944 | } |
945 | |
946 | if (WEXITSTATUS (status)) |
947 | { |
948 | printf (format: "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 (newthread: &th, NULL, start_routine: tf, arg: (void *) (testno | 0x100L)); |
959 | if (e != 0) |
960 | { |
961 | printf (format: "create failed: %m\n" ); |
962 | exit (1); |
963 | } |
964 | |
965 | pthread_t th2; |
966 | e = pthread_create (newthread: &th2, NULL, start_routine: tf, arg: (void *) (testno | 0x200L)); |
967 | if (e != 0) |
968 | { |
969 | printf (format: "create failed: %m\n" ); |
970 | exit (1); |
971 | } |
972 | |
973 | e = pthread_barrier_wait (barrier: &b3); |
974 | if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) |
975 | { |
976 | puts (s: "barrier_wait failed" ); |
977 | exit (1); |
978 | } |
979 | |
980 | setuid_tests[testno].test (SET, 0); |
981 | |
982 | pthread_t th3; |
983 | e = pthread_create (newthread: &th3, NULL, start_routine: tf2, arg: (void *) (testno | 0x300L)); |
984 | if (e != 0) |
985 | { |
986 | printf (format: "create failed: %m\n" ); |
987 | exit (1); |
988 | } |
989 | |
990 | e = pthread_barrier_wait (barrier: &b4); |
991 | if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) |
992 | { |
993 | puts (s: "barrier_wait failed" ); |
994 | exit (1); |
995 | } |
996 | |
997 | exit (0); |
998 | } |
999 | |
1000 | if (pid < 0) |
1001 | { |
1002 | printf (format: "fork failed: %m\n" ); |
1003 | exit (1); |
1004 | } |
1005 | |
1006 | if (waitpid (pid: pid, stat_loc: &status, options: 0) < 0) |
1007 | { |
1008 | printf (format: "waitpid failed: %m\n" ); |
1009 | exit (1); |
1010 | } |
1011 | |
1012 | if (!WIFEXITED (status)) |
1013 | { |
1014 | puts (s: "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 |
1026 | do_test (void) |
1027 | { |
1028 | struct passwd *pwd = getpwnam (name: "nobody" ); |
1029 | if (pwd == NULL) |
1030 | { |
1031 | puts (s: "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 (ruid: &prev_ruid, euid: &prev_euid, suid: &prev_suid) < 0) |
1038 | { |
1039 | printf (format: "getresuid failed: %m\n" ); |
1040 | exit (1); |
1041 | } |
1042 | |
1043 | if (getresgid (rgid: &prev_rgid, egid: &prev_egid, sgid: &prev_sgid) < 0) |
1044 | { |
1045 | printf (format: "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 (s: "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 (s: "already running as group nobody, skipping tests" ); |
1060 | exit (0); |
1061 | } |
1062 | |
1063 | if (pthread_barrier_init (barrier: &b3, NULL, count: 3) != 0) |
1064 | { |
1065 | puts (s: "barrier_init failed" ); |
1066 | exit (1); |
1067 | } |
1068 | |
1069 | if (pthread_barrier_init (barrier: &b4, NULL, count: 4) != 0) |
1070 | { |
1071 | puts (s: "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 | |