1 /* Copyright (C) 2014-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 <errno.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <sys/syscall.h>
24 #include <unistd.h>
25
26 /* Check that a partial setuid failure aborts the process. */
27
28 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
29 static pthread_cond_t cond_send;
30 static void (*func_sent) (void);
31 static pthread_cond_t cond_recv;
32
33 #define FAIL(fmt, ...) \
34 do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0)
35
36 static void *
thread_func(void * ctx)37 thread_func (void *ctx __attribute__ ((unused)))
38 {
39 int ret = pthread_mutex_lock (&mutex);
40 if (ret != 0)
41 FAIL ("pthread_mutex_lock (thread): %d", ret);
42
43 while (true)
44 {
45 if (func_sent != NULL)
46 {
47 void (*func) (void) = func_sent;
48 ret = pthread_mutex_unlock (&mutex);
49 if (ret != 0)
50 FAIL ("pthread_mutex_unlock (thread): %d", ret);
51 func ();
52 ret = pthread_mutex_lock (&mutex);
53 if (ret != 0)
54 FAIL ("pthread_mutex_lock (thread): %d", ret);
55 func_sent = NULL;
56 ret = pthread_cond_signal (&cond_recv);
57 if (ret != 0)
58 FAIL ("pthread_cond_signal (recv): %d", ret);
59 }
60 ret = pthread_cond_wait (&cond_send, &mutex);
61 if (ret != 0)
62 FAIL ("pthread_cond_wait (send): %d", ret);
63 }
64 return NULL;
65 }
66
67 static void
run_on_thread(void (* func)(void))68 run_on_thread (void (*func) (void))
69 {
70 int ret = pthread_mutex_lock (&mutex);
71 if (ret != 0)
72 FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
73 func_sent = func;
74 ret = pthread_mutex_unlock (&mutex);
75 if (ret != 0)
76 FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret);
77
78 ret = pthread_cond_signal (&cond_send);
79 if (ret != 0)
80 FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
81
82 ret = pthread_mutex_lock (&mutex);
83 if (ret != 0)
84 FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
85
86 while (func_sent != NULL)
87 {
88 ret = pthread_cond_wait (&cond_recv, &mutex);
89 if (ret != 0)
90 FAIL ("pthread_mutex_wait (%s): %d", __func__, ret);
91 }
92 ret = pthread_mutex_unlock (&mutex);
93 if (ret != 0)
94 FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret);
95 }
96
97 static void
change_thread_ids(void)98 change_thread_ids (void)
99 {
100 long ret = syscall (__NR_setresuid, 2001, 2002, 2003);
101 if (ret != 0)
102 FAIL ("setresuid (2001, 2002, 2003): %ld", ret);
103 }
104
105 static uid_t ruid, euid, suid;
106
107 static void
get_thread_ids(void)108 get_thread_ids (void)
109 {
110 if (getresuid (&ruid, &euid, &suid) < 0)
111 FAIL ("getresuid: %m (%d)", errno);
112 }
113
114 static void
abort_expected(int signal)115 abort_expected (int signal __attribute__ ((unused)))
116 {
117 _exit (0);
118 }
119
120 static int
do_test(void)121 do_test (void)
122 {
123 pthread_t thread;
124 int ret = pthread_create (&thread, NULL, thread_func, NULL);
125 if (ret != 0)
126 FAIL ("pthread_create: %d", ret);
127
128 run_on_thread (change_thread_ids);
129
130 signal (SIGABRT, &abort_expected);
131 /* This should abort the process. */
132 if (setresuid (1001, 1002, 1003) < 0)
133 FAIL ("setresuid: %m (%d)", errno);
134 signal (SIGABRT, SIG_DFL);
135
136 /* If we get here, check that the kernel did the right thing. */
137 run_on_thread (get_thread_ids);
138 if (ruid != 1001 || euid != 1002 || suid != 1003)
139 FAIL ("unexpected UIDs after setuid: %ld, %ld, %ld",
140 (long) ruid, (long) euid, (long) suid);
141 return 0;
142 }
143
144 #define TEST_FUNCTION do_test ()
145 #include "../test-skeleton.c"
146