1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd
5 Copyright 2014 Ronny Chevalier
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/in.h>
23 #include <sys/capability.h>
24 #include <sys/prctl.h>
25 #include <sys/socket.h>
29 #include "alloc-util.h"
30 #include "capability-util.h"
34 #include "parse-util.h"
37 static uid_t test_uid
= -1;
38 static gid_t test_gid
= -1;
40 /* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */
41 static uint64_t test_flags
= 1ULL << CAP_DAC_OVERRIDE
;
43 /* verify cap_last_cap() against /proc/sys/kernel/cap_last_cap */
44 static void test_last_cap_file(void) {
45 _cleanup_free_
char *content
= NULL
;
46 unsigned long val
= 0;
49 r
= read_one_line_file("/proc/sys/kernel/cap_last_cap", &content
);
52 r
= safe_atolu(content
, &val
);
55 assert_se(val
== cap_last_cap());
58 /* verify cap_last_cap() against syscall probing */
59 static void test_last_cap_probe(void) {
60 unsigned long p
= (unsigned long)CAP_LAST_CAP
;
62 if (prctl(PR_CAPBSET_READ
, p
) < 0) {
63 for (p
--; p
> 0; p
--)
64 if (prctl(PR_CAPBSET_READ
, p
) >= 0)
68 if (prctl(PR_CAPBSET_READ
, p
+1) < 0)
73 assert_se(p
== cap_last_cap());
76 static void fork_test(void (*test_func
)(void)) {
87 assert_se(waitpid(pid
, &status
, 0) > 0);
88 assert_se(WIFEXITED(status
) && WEXITSTATUS(status
) == 0);
92 static void show_capabilities(void) {
96 caps
= cap_get_proc();
99 text
= cap_to_text(caps
, NULL
);
102 log_info("Capabilities:%s", text
);
107 static int setup_tests(bool *run_ambient
) {
108 struct passwd
*nobody
;
111 nobody
= getpwnam(NOBODY_USER_NAME
);
113 log_error_errno(errno
, "Could not find nobody user: %m");
114 return -EXIT_TEST_SKIP
;
116 test_uid
= nobody
->pw_uid
;
117 test_gid
= nobody
->pw_gid
;
119 *run_ambient
= false;
121 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_CLEAR_ALL
, 0, 0, 0);
123 /* There's support for PR_CAP_AMBIENT if the prctl() call
124 * succeeded or error code was something else than EINVAL. The
125 * EINVAL check should be good enough to rule out false
128 if (r
>= 0 || errno
!= EINVAL
)
134 static void test_drop_privileges_keep_net_raw(void) {
137 sock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_UDP
);
138 assert_se(sock
>= 0);
141 assert_se(drop_privileges(test_uid
, test_gid
, test_flags
| (1ULL << CAP_NET_RAW
)) >= 0);
142 assert_se(getuid() == test_uid
);
143 assert_se(getgid() == test_gid
);
146 sock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_UDP
);
147 assert_se(sock
>= 0);
151 static void test_drop_privileges_dontkeep_net_raw(void) {
154 sock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_UDP
);
155 assert_se(sock
>= 0);
158 assert_se(drop_privileges(test_uid
, test_gid
, test_flags
) >= 0);
159 assert_se(getuid() == test_uid
);
160 assert_se(getgid() == test_gid
);
163 sock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_UDP
);
167 static void test_drop_privileges_fail(void) {
168 assert_se(drop_privileges(test_uid
, test_gid
, test_flags
) >= 0);
169 assert_se(getuid() == test_uid
);
170 assert_se(getgid() == test_gid
);
172 assert_se(drop_privileges(test_uid
, test_gid
, test_flags
) < 0);
173 assert_se(drop_privileges(0, 0, test_flags
) < 0);
176 static void test_drop_privileges(void) {
177 fork_test(test_drop_privileges_keep_net_raw
);
178 fork_test(test_drop_privileges_dontkeep_net_raw
);
179 fork_test(test_drop_privileges_fail
);
182 static void test_have_effective_cap(void) {
183 assert_se(have_effective_cap(CAP_KILL
));
184 assert_se(have_effective_cap(CAP_CHOWN
));
186 assert_se(drop_privileges(test_uid
, test_gid
, test_flags
| (1ULL << CAP_KILL
)) >= 0);
187 assert_se(getuid() == test_uid
);
188 assert_se(getgid() == test_gid
);
190 assert_se(have_effective_cap(CAP_KILL
));
191 assert_se(!have_effective_cap(CAP_CHOWN
));
194 static void test_update_inherited_set(void) {
199 caps
= cap_get_proc();
201 assert_se(!cap_get_flag(caps
, CAP_CHOWN
, CAP_INHERITABLE
, &fv
));
202 assert(fv
== CAP_CLEAR
);
204 set
= (UINT64_C(1) << CAP_CHOWN
);
206 assert_se(!capability_update_inherited_set(caps
, set
));
207 assert_se(!cap_get_flag(caps
, CAP_CHOWN
, CAP_INHERITABLE
, &fv
));
208 assert(fv
== CAP_SET
);
213 static void test_set_ambient_caps(void) {
218 caps
= cap_get_proc();
220 assert_se(!cap_get_flag(caps
, CAP_CHOWN
, CAP_INHERITABLE
, &fv
));
221 assert(fv
== CAP_CLEAR
);
224 assert_se(prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_IS_SET
, CAP_CHOWN
, 0, 0) == 0);
226 set
= (UINT64_C(1) << CAP_CHOWN
);
228 assert_se(!capability_ambient_set_apply(set
, true));
230 caps
= cap_get_proc();
231 assert_se(!cap_get_flag(caps
, CAP_CHOWN
, CAP_INHERITABLE
, &fv
));
232 assert(fv
== CAP_SET
);
235 assert_se(prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_IS_SET
, CAP_CHOWN
, 0, 0) == 1);
238 int main(int argc
, char *argv
[]) {
242 test_last_cap_file();
243 test_last_cap_probe();
245 log_parse_environment();
248 log_info("have ambient caps: %s", yes_no(ambient_capabilities_supported()));
251 return EXIT_TEST_SKIP
;
253 r
= setup_tests(&run_ambient
);
259 test_drop_privileges();
260 test_update_inherited_set();
262 fork_test(test_have_effective_cap
);
265 fork_test(test_set_ambient_caps
);