1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #define _GNU_SOURCE
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <cap-ng.h>
5*4882a593Smuzhiyun #include <linux/capability.h>
6*4882a593Smuzhiyun #include <stdbool.h>
7*4882a593Smuzhiyun #include <string.h>
8*4882a593Smuzhiyun #include <stdio.h>
9*4882a593Smuzhiyun #include <fcntl.h>
10*4882a593Smuzhiyun #include <errno.h>
11*4882a593Smuzhiyun #include <stdarg.h>
12*4882a593Smuzhiyun #include <sched.h>
13*4882a593Smuzhiyun #include <sys/mount.h>
14*4882a593Smuzhiyun #include <limits.h>
15*4882a593Smuzhiyun #include <libgen.h>
16*4882a593Smuzhiyun #include <malloc.h>
17*4882a593Smuzhiyun #include <sys/wait.h>
18*4882a593Smuzhiyun #include <sys/prctl.h>
19*4882a593Smuzhiyun #include <sys/stat.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "../kselftest.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #ifndef PR_CAP_AMBIENT
24*4882a593Smuzhiyun #define PR_CAP_AMBIENT 47
25*4882a593Smuzhiyun # define PR_CAP_AMBIENT_IS_SET 1
26*4882a593Smuzhiyun # define PR_CAP_AMBIENT_RAISE 2
27*4882a593Smuzhiyun # define PR_CAP_AMBIENT_LOWER 3
28*4882a593Smuzhiyun # define PR_CAP_AMBIENT_CLEAR_ALL 4
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun static int nerrs;
32*4882a593Smuzhiyun static pid_t mpid; /* main() pid is used to avoid duplicate test counts */
33*4882a593Smuzhiyun
vmaybe_write_file(bool enoent_ok,char * filename,char * fmt,va_list ap)34*4882a593Smuzhiyun static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list ap)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun char buf[4096];
37*4882a593Smuzhiyun int fd;
38*4882a593Smuzhiyun ssize_t written;
39*4882a593Smuzhiyun int buf_len;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
42*4882a593Smuzhiyun if (buf_len < 0)
43*4882a593Smuzhiyun ksft_exit_fail_msg("vsnprintf failed - %s\n", strerror(errno));
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (buf_len >= sizeof(buf))
46*4882a593Smuzhiyun ksft_exit_fail_msg("vsnprintf output truncated\n");
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun fd = open(filename, O_WRONLY);
50*4882a593Smuzhiyun if (fd < 0) {
51*4882a593Smuzhiyun if ((errno == ENOENT) && enoent_ok)
52*4882a593Smuzhiyun return;
53*4882a593Smuzhiyun ksft_exit_fail_msg("open of %s failed - %s\n",
54*4882a593Smuzhiyun filename, strerror(errno));
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun written = write(fd, buf, buf_len);
57*4882a593Smuzhiyun if (written != buf_len) {
58*4882a593Smuzhiyun if (written >= 0) {
59*4882a593Smuzhiyun ksft_exit_fail_msg("short write to %s\n", filename);
60*4882a593Smuzhiyun } else {
61*4882a593Smuzhiyun ksft_exit_fail_msg("write to %s failed - %s\n",
62*4882a593Smuzhiyun filename, strerror(errno));
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun if (close(fd) != 0) {
66*4882a593Smuzhiyun ksft_exit_fail_msg("close of %s failed - %s\n",
67*4882a593Smuzhiyun filename, strerror(errno));
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
maybe_write_file(char * filename,char * fmt,...)71*4882a593Smuzhiyun static void maybe_write_file(char *filename, char *fmt, ...)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun va_list ap;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun va_start(ap, fmt);
76*4882a593Smuzhiyun vmaybe_write_file(true, filename, fmt, ap);
77*4882a593Smuzhiyun va_end(ap);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
write_file(char * filename,char * fmt,...)80*4882a593Smuzhiyun static void write_file(char *filename, char *fmt, ...)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun va_list ap;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun va_start(ap, fmt);
85*4882a593Smuzhiyun vmaybe_write_file(false, filename, fmt, ap);
86*4882a593Smuzhiyun va_end(ap);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
create_and_enter_ns(uid_t inner_uid)89*4882a593Smuzhiyun static bool create_and_enter_ns(uid_t inner_uid)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun uid_t outer_uid;
92*4882a593Smuzhiyun gid_t outer_gid;
93*4882a593Smuzhiyun int i;
94*4882a593Smuzhiyun bool have_outer_privilege;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun outer_uid = getuid();
97*4882a593Smuzhiyun outer_gid = getgid();
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /*
100*4882a593Smuzhiyun * TODO: If we're already root, we could skip creating the userns.
101*4882a593Smuzhiyun */
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (unshare(CLONE_NEWNS) == 0) {
104*4882a593Smuzhiyun ksft_print_msg("[NOTE]\tUsing global UIDs for tests\n");
105*4882a593Smuzhiyun if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0)
106*4882a593Smuzhiyun ksft_exit_fail_msg("PR_SET_KEEPCAPS - %s\n",
107*4882a593Smuzhiyun strerror(errno));
108*4882a593Smuzhiyun if (setresuid(inner_uid, inner_uid, -1) != 0)
109*4882a593Smuzhiyun ksft_exit_fail_msg("setresuid - %s\n", strerror(errno));
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun // Re-enable effective caps
112*4882a593Smuzhiyun capng_get_caps_process();
113*4882a593Smuzhiyun for (i = 0; i < CAP_LAST_CAP; i++)
114*4882a593Smuzhiyun if (capng_have_capability(CAPNG_PERMITTED, i))
115*4882a593Smuzhiyun capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, i);
116*4882a593Smuzhiyun if (capng_apply(CAPNG_SELECT_CAPS) != 0)
117*4882a593Smuzhiyun ksft_exit_fail_msg(
118*4882a593Smuzhiyun "capng_apply - %s\n", strerror(errno));
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun have_outer_privilege = true;
121*4882a593Smuzhiyun } else if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == 0) {
122*4882a593Smuzhiyun ksft_print_msg("[NOTE]\tUsing a user namespace for tests\n");
123*4882a593Smuzhiyun maybe_write_file("/proc/self/setgroups", "deny");
124*4882a593Smuzhiyun write_file("/proc/self/uid_map", "%d %d 1", inner_uid, outer_uid);
125*4882a593Smuzhiyun write_file("/proc/self/gid_map", "0 %d 1", outer_gid);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun have_outer_privilege = false;
128*4882a593Smuzhiyun } else {
129*4882a593Smuzhiyun ksft_exit_skip("must be root or be able to create a userns\n");
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
133*4882a593Smuzhiyun ksft_exit_fail_msg("remount everything private - %s\n",
134*4882a593Smuzhiyun strerror(errno));
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun return have_outer_privilege;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
chdir_to_tmpfs(void)139*4882a593Smuzhiyun static void chdir_to_tmpfs(void)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun char cwd[PATH_MAX];
142*4882a593Smuzhiyun if (getcwd(cwd, sizeof(cwd)) != cwd)
143*4882a593Smuzhiyun ksft_exit_fail_msg("getcwd - %s\n", strerror(errno));
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if (mount("private_tmp", ".", "tmpfs", 0, "mode=0777") != 0)
146*4882a593Smuzhiyun ksft_exit_fail_msg("mount private tmpfs - %s\n",
147*4882a593Smuzhiyun strerror(errno));
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (chdir(cwd) != 0)
150*4882a593Smuzhiyun ksft_exit_fail_msg("chdir to private tmpfs - %s\n",
151*4882a593Smuzhiyun strerror(errno));
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
copy_fromat_to(int fromfd,const char * fromname,const char * toname)154*4882a593Smuzhiyun static void copy_fromat_to(int fromfd, const char *fromname, const char *toname)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun int from = openat(fromfd, fromname, O_RDONLY);
157*4882a593Smuzhiyun if (from == -1)
158*4882a593Smuzhiyun ksft_exit_fail_msg("open copy source - %s\n", strerror(errno));
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun int to = open(toname, O_CREAT | O_WRONLY | O_EXCL, 0700);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun while (true) {
163*4882a593Smuzhiyun char buf[4096];
164*4882a593Smuzhiyun ssize_t sz = read(from, buf, sizeof(buf));
165*4882a593Smuzhiyun if (sz == 0)
166*4882a593Smuzhiyun break;
167*4882a593Smuzhiyun if (sz < 0)
168*4882a593Smuzhiyun ksft_exit_fail_msg("read - %s\n", strerror(errno));
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (write(to, buf, sz) != sz)
171*4882a593Smuzhiyun /* no short writes on tmpfs */
172*4882a593Smuzhiyun ksft_exit_fail_msg("write - %s\n", strerror(errno));
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun close(from);
176*4882a593Smuzhiyun close(to);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
fork_wait(void)179*4882a593Smuzhiyun static bool fork_wait(void)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun pid_t child = fork();
182*4882a593Smuzhiyun if (child == 0) {
183*4882a593Smuzhiyun nerrs = 0;
184*4882a593Smuzhiyun return true;
185*4882a593Smuzhiyun } else if (child > 0) {
186*4882a593Smuzhiyun int status;
187*4882a593Smuzhiyun if (waitpid(child, &status, 0) != child ||
188*4882a593Smuzhiyun !WIFEXITED(status)) {
189*4882a593Smuzhiyun ksft_print_msg("Child died\n");
190*4882a593Smuzhiyun nerrs++;
191*4882a593Smuzhiyun } else if (WEXITSTATUS(status) != 0) {
192*4882a593Smuzhiyun ksft_print_msg("Child failed\n");
193*4882a593Smuzhiyun nerrs++;
194*4882a593Smuzhiyun } else {
195*4882a593Smuzhiyun /* don't print this message for mpid */
196*4882a593Smuzhiyun if (getpid() != mpid)
197*4882a593Smuzhiyun ksft_test_result_pass("Passed\n");
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun return false;
200*4882a593Smuzhiyun } else {
201*4882a593Smuzhiyun ksft_exit_fail_msg("fork - %s\n", strerror(errno));
202*4882a593Smuzhiyun return false;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
exec_other_validate_cap(const char * name,bool eff,bool perm,bool inh,bool ambient)206*4882a593Smuzhiyun static void exec_other_validate_cap(const char *name,
207*4882a593Smuzhiyun bool eff, bool perm, bool inh, bool ambient)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun execl(name, name, (eff ? "1" : "0"),
210*4882a593Smuzhiyun (perm ? "1" : "0"), (inh ? "1" : "0"), (ambient ? "1" : "0"),
211*4882a593Smuzhiyun NULL);
212*4882a593Smuzhiyun ksft_exit_fail_msg("execl - %s\n", strerror(errno));
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
exec_validate_cap(bool eff,bool perm,bool inh,bool ambient)215*4882a593Smuzhiyun static void exec_validate_cap(bool eff, bool perm, bool inh, bool ambient)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap", eff, perm, inh, ambient);
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
do_tests(int uid,const char * our_path)220*4882a593Smuzhiyun static int do_tests(int uid, const char *our_path)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun bool have_outer_privilege = create_and_enter_ns(uid);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun int ourpath_fd = open(our_path, O_RDONLY | O_DIRECTORY);
225*4882a593Smuzhiyun if (ourpath_fd == -1)
226*4882a593Smuzhiyun ksft_exit_fail_msg("open '%s' - %s\n",
227*4882a593Smuzhiyun our_path, strerror(errno));
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun chdir_to_tmpfs();
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun copy_fromat_to(ourpath_fd, "validate_cap", "validate_cap");
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (have_outer_privilege) {
234*4882a593Smuzhiyun uid_t gid = getegid();
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun copy_fromat_to(ourpath_fd, "validate_cap",
237*4882a593Smuzhiyun "validate_cap_suidroot");
238*4882a593Smuzhiyun if (chown("validate_cap_suidroot", 0, -1) != 0)
239*4882a593Smuzhiyun ksft_exit_fail_msg("chown - %s\n", strerror(errno));
240*4882a593Smuzhiyun if (chmod("validate_cap_suidroot", S_ISUID | 0700) != 0)
241*4882a593Smuzhiyun ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun copy_fromat_to(ourpath_fd, "validate_cap",
244*4882a593Smuzhiyun "validate_cap_suidnonroot");
245*4882a593Smuzhiyun if (chown("validate_cap_suidnonroot", uid + 1, -1) != 0)
246*4882a593Smuzhiyun ksft_exit_fail_msg("chown - %s\n", strerror(errno));
247*4882a593Smuzhiyun if (chmod("validate_cap_suidnonroot", S_ISUID | 0700) != 0)
248*4882a593Smuzhiyun ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun copy_fromat_to(ourpath_fd, "validate_cap",
251*4882a593Smuzhiyun "validate_cap_sgidroot");
252*4882a593Smuzhiyun if (chown("validate_cap_sgidroot", -1, 0) != 0)
253*4882a593Smuzhiyun ksft_exit_fail_msg("chown - %s\n", strerror(errno));
254*4882a593Smuzhiyun if (chmod("validate_cap_sgidroot", S_ISGID | 0710) != 0)
255*4882a593Smuzhiyun ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun copy_fromat_to(ourpath_fd, "validate_cap",
258*4882a593Smuzhiyun "validate_cap_sgidnonroot");
259*4882a593Smuzhiyun if (chown("validate_cap_sgidnonroot", -1, gid + 1) != 0)
260*4882a593Smuzhiyun ksft_exit_fail_msg("chown - %s\n", strerror(errno));
261*4882a593Smuzhiyun if (chmod("validate_cap_sgidnonroot", S_ISGID | 0710) != 0)
262*4882a593Smuzhiyun ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun capng_get_caps_process();
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /* Make sure that i starts out clear */
268*4882a593Smuzhiyun capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
269*4882a593Smuzhiyun if (capng_apply(CAPNG_SELECT_CAPS) != 0)
270*4882a593Smuzhiyun ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (uid == 0) {
273*4882a593Smuzhiyun ksft_print_msg("[RUN]\tRoot => ep\n");
274*4882a593Smuzhiyun if (fork_wait())
275*4882a593Smuzhiyun exec_validate_cap(true, true, false, false);
276*4882a593Smuzhiyun } else {
277*4882a593Smuzhiyun ksft_print_msg("[RUN]\tNon-root => no caps\n");
278*4882a593Smuzhiyun if (fork_wait())
279*4882a593Smuzhiyun exec_validate_cap(false, false, false, false);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun ksft_print_msg("Check cap_ambient manipulation rules\n");
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* We should not be able to add ambient caps yet. */
285*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != -1 || errno != EPERM) {
286*4882a593Smuzhiyun if (errno == EINVAL)
287*4882a593Smuzhiyun ksft_test_result_fail(
288*4882a593Smuzhiyun "PR_CAP_AMBIENT_RAISE isn't supported\n");
289*4882a593Smuzhiyun else
290*4882a593Smuzhiyun ksft_test_result_fail(
291*4882a593Smuzhiyun "PR_CAP_AMBIENT_RAISE should have failed eith EPERM on a non-inheritable cap\n");
292*4882a593Smuzhiyun return 1;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun ksft_test_result_pass(
295*4882a593Smuzhiyun "PR_CAP_AMBIENT_RAISE failed on non-inheritable cap\n");
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_RAW);
298*4882a593Smuzhiyun capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_NET_RAW);
299*4882a593Smuzhiyun capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_NET_RAW);
300*4882a593Smuzhiyun if (capng_apply(CAPNG_SELECT_CAPS) != 0)
301*4882a593Smuzhiyun ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
302*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0, 0) != -1 || errno != EPERM) {
303*4882a593Smuzhiyun ksft_test_result_fail(
304*4882a593Smuzhiyun "PR_CAP_AMBIENT_RAISE should have failed on a non-permitted cap\n");
305*4882a593Smuzhiyun return 1;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun ksft_test_result_pass(
308*4882a593Smuzhiyun "PR_CAP_AMBIENT_RAISE failed on non-permitted cap\n");
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
311*4882a593Smuzhiyun if (capng_apply(CAPNG_SELECT_CAPS) != 0)
312*4882a593Smuzhiyun ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
313*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) {
314*4882a593Smuzhiyun ksft_test_result_fail(
315*4882a593Smuzhiyun "PR_CAP_AMBIENT_RAISE should have succeeded\n");
316*4882a593Smuzhiyun return 1;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun ksft_test_result_pass("PR_CAP_AMBIENT_RAISE worked\n");
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 1) {
321*4882a593Smuzhiyun ksft_test_result_fail("PR_CAP_AMBIENT_IS_SET is broken\n");
322*4882a593Smuzhiyun return 1;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0) != 0)
326*4882a593Smuzhiyun ksft_exit_fail_msg("PR_CAP_AMBIENT_CLEAR_ALL - %s\n",
327*4882a593Smuzhiyun strerror(errno));
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) {
330*4882a593Smuzhiyun ksft_test_result_fail(
331*4882a593Smuzhiyun "PR_CAP_AMBIENT_CLEAR_ALL didn't work\n");
332*4882a593Smuzhiyun return 1;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0)
336*4882a593Smuzhiyun ksft_exit_fail_msg("PR_CAP_AMBIENT_RAISE - %s\n",
337*4882a593Smuzhiyun strerror(errno));
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
340*4882a593Smuzhiyun if (capng_apply(CAPNG_SELECT_CAPS) != 0)
341*4882a593Smuzhiyun ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) {
344*4882a593Smuzhiyun ksft_test_result_fail("Dropping I should have dropped A\n");
345*4882a593Smuzhiyun return 1;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun ksft_test_result_pass("Basic manipulation appears to work\n");
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
351*4882a593Smuzhiyun if (capng_apply(CAPNG_SELECT_CAPS) != 0)
352*4882a593Smuzhiyun ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
353*4882a593Smuzhiyun if (uid == 0) {
354*4882a593Smuzhiyun ksft_print_msg("[RUN]\tRoot +i => eip\n");
355*4882a593Smuzhiyun if (fork_wait())
356*4882a593Smuzhiyun exec_validate_cap(true, true, true, false);
357*4882a593Smuzhiyun } else {
358*4882a593Smuzhiyun ksft_print_msg("[RUN]\tNon-root +i => i\n");
359*4882a593Smuzhiyun if (fork_wait())
360*4882a593Smuzhiyun exec_validate_cap(false, false, true, false);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0)
364*4882a593Smuzhiyun ksft_exit_fail_msg("PR_CAP_AMBIENT_RAISE - %s\n",
365*4882a593Smuzhiyun strerror(errno));
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun ksft_print_msg("[RUN]\tUID %d +ia => eipa\n", uid);
368*4882a593Smuzhiyun if (fork_wait())
369*4882a593Smuzhiyun exec_validate_cap(true, true, true, true);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun /* The remaining tests need real privilege */
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (!have_outer_privilege) {
374*4882a593Smuzhiyun ksft_test_result_skip("SUID/SGID tests (needs privilege)\n");
375*4882a593Smuzhiyun goto done;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun if (uid == 0) {
379*4882a593Smuzhiyun ksft_print_msg("[RUN]\tRoot +ia, suidroot => eipa\n");
380*4882a593Smuzhiyun if (fork_wait())
381*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap_suidroot",
382*4882a593Smuzhiyun true, true, true, true);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun ksft_print_msg("[RUN]\tRoot +ia, suidnonroot => ip\n");
385*4882a593Smuzhiyun if (fork_wait())
386*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap_suidnonroot",
387*4882a593Smuzhiyun false, true, true, false);
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun ksft_print_msg("[RUN]\tRoot +ia, sgidroot => eipa\n");
390*4882a593Smuzhiyun if (fork_wait())
391*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap_sgidroot",
392*4882a593Smuzhiyun true, true, true, true);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun if (fork_wait()) {
395*4882a593Smuzhiyun ksft_print_msg(
396*4882a593Smuzhiyun "[RUN]\tRoot, gid != 0, +ia, sgidroot => eip\n");
397*4882a593Smuzhiyun if (setresgid(1, 1, 1) != 0)
398*4882a593Smuzhiyun ksft_exit_fail_msg("setresgid - %s\n",
399*4882a593Smuzhiyun strerror(errno));
400*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap_sgidroot",
401*4882a593Smuzhiyun true, true, true, false);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun ksft_print_msg("[RUN]\tRoot +ia, sgidnonroot => eip\n");
405*4882a593Smuzhiyun if (fork_wait())
406*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap_sgidnonroot",
407*4882a593Smuzhiyun true, true, true, false);
408*4882a593Smuzhiyun } else {
409*4882a593Smuzhiyun ksft_print_msg("[RUN]\tNon-root +ia, sgidnonroot => i\n");
410*4882a593Smuzhiyun if (fork_wait())
411*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap_sgidnonroot",
412*4882a593Smuzhiyun false, false, true, false);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if (fork_wait()) {
415*4882a593Smuzhiyun ksft_print_msg("[RUN]\tNon-root +ia, sgidroot => i\n");
416*4882a593Smuzhiyun if (setresgid(1, 1, 1) != 0)
417*4882a593Smuzhiyun ksft_exit_fail_msg("setresgid - %s\n",
418*4882a593Smuzhiyun strerror(errno));
419*4882a593Smuzhiyun exec_other_validate_cap("./validate_cap_sgidroot",
420*4882a593Smuzhiyun false, false, true, false);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun done:
425*4882a593Smuzhiyun ksft_print_cnts();
426*4882a593Smuzhiyun return nerrs ? 1 : 0;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
main(int argc,char ** argv)429*4882a593Smuzhiyun int main(int argc, char **argv)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun char *tmp1, *tmp2, *our_path;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun /* Find our path */
434*4882a593Smuzhiyun tmp1 = strdup(argv[0]);
435*4882a593Smuzhiyun if (!tmp1)
436*4882a593Smuzhiyun ksft_exit_fail_msg("strdup - %s\n", strerror(errno));
437*4882a593Smuzhiyun tmp2 = dirname(tmp1);
438*4882a593Smuzhiyun our_path = strdup(tmp2);
439*4882a593Smuzhiyun if (!our_path)
440*4882a593Smuzhiyun ksft_exit_fail_msg("strdup - %s\n", strerror(errno));
441*4882a593Smuzhiyun free(tmp1);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun mpid = getpid();
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun if (fork_wait()) {
446*4882a593Smuzhiyun ksft_print_header();
447*4882a593Smuzhiyun ksft_set_plan(12);
448*4882a593Smuzhiyun ksft_print_msg("[RUN]\t+++ Tests with uid == 0 +++\n");
449*4882a593Smuzhiyun return do_tests(0, our_path);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun ksft_print_msg("==================================================\n");
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun if (fork_wait()) {
455*4882a593Smuzhiyun ksft_print_header();
456*4882a593Smuzhiyun ksft_set_plan(9);
457*4882a593Smuzhiyun ksft_print_msg("[RUN]\t+++ Tests with uid != 0 +++\n");
458*4882a593Smuzhiyun return do_tests(1, our_path);
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun return nerrs ? 1 : 0;
462*4882a593Smuzhiyun }
463