]>
Commit | Line | Data |
---|---|---|
bfff8b1b | 1 | /* Copyright (C) 2014-2017 Free Software Foundation, Inc. |
771eb141 FW |
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 | <http://www.gnu.org/licenses/>. */ | |
17 | ||
99d86ea3 | 18 | #include <stdio.h> |
771eb141 FW |
19 | #include <errno.h> |
20 | #include <pthread.h> | |
21 | #include <stdbool.h> | |
22 | #include <unistd.h> | |
23 | ||
24 | /* The test must run under a non-privileged user ID. */ | |
25 | static const uid_t test_uid = 1; | |
26 | ||
27 | static pthread_barrier_t barrier1; | |
28 | static pthread_barrier_t barrier2; | |
29 | ||
99d86ea3 AS |
30 | #define FAIL(fmt, ...) \ |
31 | do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0) | |
32 | ||
33 | #define FAIL_ERR(fmt, ...) \ | |
34 | do { printf ("FAIL: " fmt ": %m\n", __VA_ARGS__); _exit (1); } while (0) | |
35 | ||
fad7e4d7 PM |
36 | /* True if x is not a successful return code from pthread_barrier_wait. */ |
37 | static inline bool | |
38 | is_invalid_barrier_ret (int x) | |
39 | { | |
40 | return x != 0 && x != PTHREAD_BARRIER_SERIAL_THREAD; | |
41 | } | |
42 | ||
771eb141 FW |
43 | static void * |
44 | thread_func (void *ctx __attribute__ ((unused))) | |
45 | { | |
46 | int ret = pthread_barrier_wait (&barrier1); | |
fad7e4d7 | 47 | if (is_invalid_barrier_ret (ret)) |
99d86ea3 | 48 | FAIL ("pthread_barrier_wait (barrier1) (on thread): %d", ret); |
771eb141 | 49 | ret = pthread_barrier_wait (&barrier2); |
fad7e4d7 | 50 | if (is_invalid_barrier_ret (ret)) |
99d86ea3 | 51 | FAIL ("pthread_barrier_wait (barrier2) (on thread): %d", ret); |
771eb141 FW |
52 | return NULL; |
53 | } | |
54 | ||
55 | static void | |
56 | setuid_failure (int phase) | |
57 | { | |
58 | int ret = setuid (0); | |
59 | switch (ret) | |
60 | { | |
61 | case 0: | |
99d86ea3 | 62 | FAIL ("setuid succeeded unexpectedly in phase %d", phase); |
771eb141 FW |
63 | case -1: |
64 | if (errno != EPERM) | |
99d86ea3 | 65 | FAIL_ERR ("setuid phase %d", phase); |
771eb141 FW |
66 | break; |
67 | default: | |
99d86ea3 | 68 | FAIL ("invalid setuid return value in phase %d: %d", phase, ret); |
771eb141 FW |
69 | } |
70 | } | |
71 | ||
72 | static int | |
73 | do_test (void) | |
74 | { | |
75 | if (getuid () == 0) | |
76 | if (setuid (test_uid) != 0) | |
99d86ea3 | 77 | FAIL_ERR ("setuid (%u)", (unsigned) test_uid); |
771eb141 | 78 | if (setuid (getuid ())) |
99d86ea3 | 79 | FAIL_ERR ("setuid (%s)", "getuid ()"); |
771eb141 FW |
80 | setuid_failure (1); |
81 | ||
82 | int ret = pthread_barrier_init (&barrier1, NULL, 2); | |
83 | if (ret != 0) | |
99d86ea3 | 84 | FAIL ("pthread_barrier_init (barrier1): %d", ret); |
771eb141 FW |
85 | ret = pthread_barrier_init (&barrier2, NULL, 2); |
86 | if (ret != 0) | |
99d86ea3 | 87 | FAIL ("pthread_barrier_init (barrier2): %d", ret); |
771eb141 FW |
88 | |
89 | pthread_t thread; | |
90 | ret = pthread_create (&thread, NULL, thread_func, NULL); | |
91 | if (ret != 0) | |
99d86ea3 | 92 | FAIL ("pthread_create: %d", ret); |
771eb141 FW |
93 | |
94 | /* Ensure that the thread is running properly. */ | |
95 | ret = pthread_barrier_wait (&barrier1); | |
fad7e4d7 | 96 | if (is_invalid_barrier_ret (ret)) |
99d86ea3 | 97 | FAIL ("pthread_barrier_wait (barrier1): %d", ret); |
771eb141 FW |
98 | |
99 | setuid_failure (2); | |
100 | ||
101 | /* Check success case. */ | |
102 | if (setuid (getuid ()) != 0) | |
99d86ea3 | 103 | FAIL_ERR ("setuid (%s)", "getuid ()"); |
771eb141 FW |
104 | |
105 | /* Shutdown. */ | |
106 | ret = pthread_barrier_wait (&barrier2); | |
fad7e4d7 | 107 | if (is_invalid_barrier_ret (ret)) |
99d86ea3 | 108 | FAIL ("pthread_barrier_wait (barrier2): %d", ret); |
771eb141 | 109 | |
fad7e4d7 PM |
110 | ret = pthread_join (thread, NULL); |
111 | if (ret != 0) | |
99d86ea3 | 112 | FAIL ("pthread_join: %d", ret); |
771eb141 FW |
113 | |
114 | return 0; | |
115 | } | |
116 | ||
117 | #define TEST_FUNCTION do_test () | |
118 | #include "../test-skeleton.c" |