]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/setpriv.c
setpriv: add landlock support
[thirdparty/util-linux.git] / sys-utils / setpriv.c
1 /*
2 * setpriv(1) - set various kernel privilege bits and run something
3 *
4 * Copyright (C) 2012 Andy Lutomirski <luto@amacapital.net>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <cap-ng.h>
22 #include <errno.h>
23 #include <getopt.h>
24 #include <grp.h>
25 #include <linux/securebits.h>
26 #include <pwd.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/prctl.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 #include "c.h"
35 #include "caputils.h"
36 #include "closestream.h"
37 #include "nls.h"
38 #include "optutils.h"
39 #include "strutils.h"
40 #include "xalloc.h"
41 #include "pathnames.h"
42 #include "signames.h"
43 #include "env.h"
44 #include "setpriv-landlock.h"
45
46 #ifndef PR_SET_NO_NEW_PRIVS
47 # define PR_SET_NO_NEW_PRIVS 38
48 #endif
49 #ifndef PR_GET_NO_NEW_PRIVS
50 # define PR_GET_NO_NEW_PRIVS 39
51 #endif
52
53 #define SETPRIV_EXIT_PRIVERR 127 /* how we exit when we fail to set privs */
54
55 /* The shell to set SHELL env.variable if none is given in the user's passwd entry. */
56 #define DEFAULT_SHELL "/bin/sh"
57
58 static gid_t get_group(const char *s, const char *err);
59
60 enum cap_type {
61 CAP_TYPE_EFFECTIVE = CAPNG_EFFECTIVE,
62 CAP_TYPE_PERMITTED = CAPNG_PERMITTED,
63 CAP_TYPE_INHERITABLE = CAPNG_INHERITABLE,
64 CAP_TYPE_BOUNDING = CAPNG_BOUNDING_SET,
65 CAP_TYPE_AMBIENT = (1 << 4)
66 };
67
68 /*
69 * Note: We are subject to https://bugzilla.redhat.com/show_bug.cgi?id=895105
70 * and we will therefore have problems if new capabilities are added. Once
71 * that bug is fixed, I'll (Andy Lutomirski) submit a corresponding fix to
72 * setpriv. In the mean time, the code here tries to work reasonably well.
73 */
74
75 struct privctx {
76 unsigned int
77 nnp:1, /* no_new_privs */
78 have_ruid:1, /* real uid */
79 have_euid:1, /* effective uid */
80 have_rgid:1, /* real gid */
81 have_egid:1, /* effective gid */
82 have_passwd:1, /* passwd entry */
83 have_groups:1, /* add groups */
84 keep_groups:1, /* keep groups */
85 clear_groups:1, /* remove groups */
86 init_groups:1, /* initialize groups */
87 reset_env:1, /* reset environment */
88 have_securebits:1; /* remove groups */
89
90 /* uids and gids */
91 uid_t ruid, euid;
92 gid_t rgid, egid;
93
94 /* real user passwd entry */
95 struct passwd passwd;
96
97 /* supplementary groups */
98 size_t num_groups;
99 gid_t *groups;
100
101 /* caps */
102 const char *caps_to_inherit;
103 const char *ambient_caps;
104 const char *bounding_set;
105
106 /* securebits */
107 int securebits;
108 /* parent death signal (<0 clear, 0 nothing, >0 signal) */
109 int pdeathsig;
110
111 /* LSMs */
112 const char *selinux_label;
113 const char *apparmor_profile;
114 struct setpriv_landlock_opts landlock;
115 };
116
117 static void __attribute__((__noreturn__)) usage(void)
118 {
119 FILE *out = stdout;
120 fputs(USAGE_HEADER, out);
121 fprintf(out, _(" %s [options] <program> [<argument>...]\n"),
122 program_invocation_short_name);
123
124 fputs(USAGE_SEPARATOR, out);
125 fputs(_("Run a program with different privilege settings.\n"), out);
126
127 fputs(USAGE_OPTIONS, out);
128 fputs(_(" -d, --dump show current state (and do not exec)\n"), out);
129 fputs(_(" --nnp, --no-new-privs disallow granting new privileges\n"), out);
130 fputs(_(" --ambient-caps <caps,...> set ambient capabilities\n"), out);
131 fputs(_(" --inh-caps <caps,...> set inheritable capabilities\n"), out);
132 fputs(_(" --bounding-set <caps> set capability bounding set\n"), out);
133 fputs(_(" --ruid <uid|user> set real uid\n"), out);
134 fputs(_(" --euid <uid|user> set effective uid\n"), out);
135 fputs(_(" --rgid <gid|user> set real gid\n"), out);
136 fputs(_(" --egid <gid|group> set effective gid\n"), out);
137 fputs(_(" --reuid <uid|user> set real and effective uid\n"), out);
138 fputs(_(" --regid <gid|group> set real and effective gid\n"), out);
139 fputs(_(" --clear-groups clear supplementary groups\n"), out);
140 fputs(_(" --keep-groups keep supplementary groups\n"), out);
141 fputs(_(" --init-groups initialize supplementary groups\n"), out);
142 fputs(_(" --groups <group,...> set supplementary groups by UID or name\n"), out);
143 fputs(_(" --securebits <bits> set securebits\n"), out);
144 fputs(_(" --pdeathsig keep|clear|<signame>\n"
145 " set or clear parent death signal\n"), out);
146 fputs(_(" --selinux-label <label> set SELinux label\n"), out);
147 fputs(_(" --apparmor-profile <pr> set AppArmor profile\n"), out);
148 fputs(_(" --landlock-access <access> add Landlock access\n"), out);
149 fputs(_(" --landlock-rule <rule> add Landlock rule\n"), out);
150 fputs(_(" --reset-env clear all environment and initialize\n"
151 " HOME, SHELL, USER, LOGNAME and PATH\n"), out);
152
153 fputs(USAGE_SEPARATOR, out);
154 fprintf(out, USAGE_HELP_OPTIONS(29));
155 fputs(USAGE_SEPARATOR, out);
156 fputs(_(" This tool can be dangerous. Read the manpage, and be careful.\n"), out);
157 fprintf(out, USAGE_MAN_TAIL("setpriv(1)"));
158
159 usage_setpriv(out);
160
161 exit(EXIT_SUCCESS);
162 }
163
164 static int has_cap(enum cap_type which, unsigned int i)
165 {
166 switch (which) {
167 case CAP_TYPE_EFFECTIVE:
168 case CAP_TYPE_BOUNDING:
169 case CAP_TYPE_INHERITABLE:
170 case CAP_TYPE_PERMITTED:
171 return capng_have_capability((capng_type_t)which, i);
172 case CAP_TYPE_AMBIENT:
173 return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET,
174 (unsigned long) i, 0UL, 0UL);
175 default:
176 warnx(_("invalid capability type"));
177 return -1;
178 }
179 }
180
181 /* Returns the number of capabilities printed. */
182 static int print_caps(FILE *f, enum cap_type which)
183 {
184 int i, n = 0, max = cap_last_cap();
185
186 for (i = 0; i <= max; i++) {
187 int ret = has_cap(which, i);
188
189 if (i == 0 && ret < 0)
190 return -1;
191
192 if (ret == 1) {
193 const char *name = capng_capability_to_name(i);
194 if (n)
195 fputc(',', f);
196 if (name)
197 fputs(name, f);
198 else
199 warnx(_("cap %d: libcap-ng is broken"), i);
200 n++;
201 }
202 }
203
204 return n;
205 }
206
207 static void dump_one_secbit(int *first, int *bits, int bit, const char *name)
208 {
209 if (*bits & bit) {
210 if (*first)
211 *first = 0;
212 else
213 printf(",");
214 fputs(name, stdout);
215 *bits &= ~bit;
216 }
217 }
218
219 static void dump_securebits(void)
220 {
221 int first = 1;
222 int bits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
223
224 if (bits < 0) {
225 warnx(_("getting process secure bits failed"));
226 return;
227 }
228
229 printf(_("Securebits: "));
230
231 dump_one_secbit(&first, &bits, SECBIT_NOROOT, "noroot");
232 dump_one_secbit(&first, &bits, SECBIT_NOROOT_LOCKED, "noroot_locked");
233 dump_one_secbit(&first, &bits, SECBIT_NO_SETUID_FIXUP,
234 "no_setuid_fixup");
235 dump_one_secbit(&first, &bits, SECBIT_NO_SETUID_FIXUP_LOCKED,
236 "no_setuid_fixup_locked");
237 bits &= ~SECBIT_KEEP_CAPS;
238 dump_one_secbit(&first, &bits, SECBIT_KEEP_CAPS_LOCKED,
239 "keep_caps_locked");
240 if (bits) {
241 if (first)
242 first = 0;
243 else
244 printf(",");
245 printf("0x%x", (unsigned)bits);
246 }
247
248 if (first)
249 printf(_("[none]\n"));
250 else
251 printf("\n");
252 }
253
254 static void dump_label(const char *name)
255 {
256 char buf[4097];
257 ssize_t len;
258 int fd, e;
259
260 fd = open(_PATH_PROC_ATTR_CURRENT, O_RDONLY);
261 if (fd == -1) {
262 warn(_("cannot open %s"), _PATH_PROC_ATTR_CURRENT);
263 return;
264 }
265
266 len = read(fd, buf, sizeof(buf));
267 e = errno;
268 close(fd);
269 if (len < 0) {
270 errno = e;
271 warn(_("cannot read %s"), name);
272 return;
273 }
274 if (sizeof(buf) - 1 <= (size_t)len) {
275 warnx(_("%s: too long"), name);
276 return;
277 }
278
279 buf[len] = 0;
280 if (0 < len && buf[len - 1] == '\n')
281 buf[len - 1] = 0;
282 printf("%s: %s\n", name, buf);
283 }
284
285 static void dump_groups(void)
286 {
287 int n = getgroups(0, NULL);
288 gid_t *groups;
289
290 if (n < 0) {
291 warn("getgroups failed");
292 return;
293 }
294
295 groups = xmalloc(n * sizeof(gid_t));
296 n = getgroups(n, groups);
297 if (n < 0) {
298 free(groups);
299 warn("getgroups failed");
300 return;
301 }
302
303 printf(_("Supplementary groups: "));
304 if (n == 0)
305 printf(_("[none]"));
306 else {
307 int i;
308 for (i = 0; i < n; i++) {
309 if (0 < i)
310 printf(",");
311 printf("%ld", (long)groups[i]);
312 }
313 }
314 printf("\n");
315 free(groups);
316 }
317
318 static void dump_pdeathsig(void)
319 {
320 int pdeathsig;
321
322 if (prctl(PR_GET_PDEATHSIG, &pdeathsig) != 0) {
323 warn(_("get pdeathsig failed"));
324 return;
325 }
326
327 printf(_("Parent death signal: "));
328 if (pdeathsig && signum_to_signame(pdeathsig) != NULL)
329 printf("%s\n", signum_to_signame(pdeathsig));
330 else if (pdeathsig)
331 printf("%d\n", pdeathsig);
332 else
333 printf(_("[none]\n"));
334 }
335
336 static void dump(int dumplevel)
337 {
338 int x;
339 uid_t ru, eu, su;
340 gid_t rg, eg, sg;
341
342 if (getresuid(&ru, &eu, &su) == 0) {
343 printf(_("uid: %u\n"), ru);
344 printf(_("euid: %u\n"), eu);
345 /* Saved and fs uids always equal euid. */
346 if (3 <= dumplevel)
347 printf(_("suid: %u\n"), su);
348 } else
349 warn(_("getresuid failed"));
350
351 if (getresgid(&rg, &eg, &sg) == 0) {
352 printf("gid: %ld\n", (long)rg);
353 printf("egid: %ld\n", (long)eg);
354 /* Saved and fs gids always equal egid. */
355 if (dumplevel >= 3)
356 printf("sgid: %ld\n", (long)sg);
357 } else
358 warn(_("getresgid failed"));
359
360 dump_groups();
361
362 x = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
363 if (0 <= x)
364 printf("no_new_privs: %d\n", x);
365 else
366 warn("setting no_new_privs failed");
367
368 if (2 <= dumplevel) {
369 printf(_("Effective capabilities: "));
370 if (print_caps(stdout, CAP_TYPE_EFFECTIVE) == 0)
371 printf(_("[none]"));
372 printf("\n");
373
374 printf(_("Permitted capabilities: "));
375 if (print_caps(stdout, CAP_TYPE_PERMITTED) == 0)
376 printf(_("[none]"));
377 printf("\n");
378 }
379
380 printf(_("Inheritable capabilities: "));
381 if (print_caps(stdout, CAP_TYPE_INHERITABLE) == 0)
382 printf(_("[none]"));
383 printf("\n");
384
385 printf(_("Ambient capabilities: "));
386 x = print_caps(stdout, CAP_TYPE_AMBIENT);
387 if (x == 0)
388 printf(_("[none]"));
389 if (x < 0)
390 printf(_("[unsupported]"));
391 printf("\n");
392
393 printf(_("Capability bounding set: "));
394 if (print_caps(stdout, CAP_TYPE_BOUNDING) == 0)
395 printf(_("[none]"));
396 printf("\n");
397
398 dump_securebits();
399 dump_pdeathsig();
400
401 if (access(_PATH_SYS_SELINUX, F_OK) == 0)
402 dump_label(_("SELinux label"));
403
404 if (access(_PATH_SYS_APPARMOR, F_OK) == 0) {
405 dump_label(_("AppArmor profile"));
406 }
407 }
408
409 static void list_known_caps(void)
410 {
411 int i, max = cap_last_cap();
412
413 for (i = 0; i <= max; i++) {
414 const char *name = capng_capability_to_name(i);
415 if (name)
416 printf("%s\n", name);
417 else
418 warnx(_("cap %d: libcap-ng is broken"), i);
419 }
420 }
421
422 static void parse_groups(struct privctx *opts, const char *str)
423 {
424 char *groups = xstrdup(str);
425 char *buf = groups; /* We'll reuse it */
426 char *c;
427 size_t i = 0;
428
429 opts->have_groups = 1;
430 opts->num_groups = 0;
431 while ((c = strsep(&groups, ",")))
432 opts->num_groups++;
433
434 /* Start again */
435 strcpy(buf, str); /* It's exactly the right length */
436 groups = buf;
437
438 opts->groups = xcalloc(opts->num_groups, sizeof(gid_t));
439 while ((c = strsep(&groups, ",")))
440 opts->groups[i++] = get_group(c, _("Invalid supplementary group id"));
441
442 free(groups);
443 }
444
445 static void parse_pdeathsig(struct privctx *opts, const char *str)
446 {
447 if (!strcmp(str, "keep")) {
448 if (prctl(PR_GET_PDEATHSIG, &opts->pdeathsig) != 0)
449 errx(SETPRIV_EXIT_PRIVERR,
450 _("failed to get parent death signal"));
451 } else if (!strcmp(str, "clear")) {
452 opts->pdeathsig = -1;
453 } else if ((opts->pdeathsig = signame_to_signum(str)) < 0) {
454 errx(EXIT_FAILURE, _("unknown signal: %s"), str);
455 }
456 }
457
458 static void do_setresuid(const struct privctx *opts)
459 {
460 uid_t ruid, euid, suid;
461 if (getresuid(&ruid, &euid, &suid) != 0)
462 err(SETPRIV_EXIT_PRIVERR, _("getresuid failed"));
463 if (opts->have_ruid)
464 ruid = opts->ruid;
465 if (opts->have_euid)
466 euid = opts->euid;
467
468 /* Also copy effective to saved (for paranoia). */
469 if (setresuid(ruid, euid, euid) != 0)
470 err(SETPRIV_EXIT_PRIVERR, _("setresuid failed"));
471 }
472
473 static void do_setresgid(const struct privctx *opts)
474 {
475 gid_t rgid, egid, sgid;
476 if (getresgid(&rgid, &egid, &sgid) != 0)
477 err(SETPRIV_EXIT_PRIVERR, _("getresgid failed"));
478 if (opts->have_rgid)
479 rgid = opts->rgid;
480 if (opts->have_egid)
481 egid = opts->egid;
482
483 /* Also copy effective to saved (for paranoia). */
484 if (setresgid(rgid, egid, egid) != 0)
485 err(SETPRIV_EXIT_PRIVERR, _("setresgid failed"));
486 }
487
488 static void bump_cap(unsigned int cap)
489 {
490 if (capng_have_capability(CAPNG_PERMITTED, cap))
491 capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, cap);
492 }
493
494 static int cap_update(capng_act_t action,
495 enum cap_type type, unsigned int cap)
496 {
497 switch (type) {
498 case CAP_TYPE_EFFECTIVE:
499 case CAP_TYPE_BOUNDING:
500 case CAP_TYPE_INHERITABLE:
501 case CAP_TYPE_PERMITTED:
502 return capng_update(action, (capng_type_t) type, cap);
503 case CAP_TYPE_AMBIENT:
504 {
505 int ret;
506
507 if (action == CAPNG_ADD)
508 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE,
509 (unsigned long) cap, 0UL, 0UL);
510 else
511 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER,
512 (unsigned long) cap, 0UL, 0UL);
513
514 return ret;
515 }
516 default:
517 errx(EXIT_FAILURE, _("unsupported capability type"));
518 return -1;
519 }
520 }
521
522 static void do_caps(enum cap_type type, const char *caps)
523 {
524 char *my_caps = xstrdup(caps);
525 char *c;
526
527 while ((c = strsep(&my_caps, ","))) {
528 capng_act_t action;
529 if (*c == '+')
530 action = CAPNG_ADD;
531 else if (*c == '-')
532 action = CAPNG_DROP;
533 else
534 errx(EXIT_FAILURE, _("bad capability string"));
535
536 if (!strcmp(c + 1, "all")) {
537 int i;
538 /* We can trust the return value from cap_last_cap(),
539 * so use that directly. */
540 for (i = 0; i <= cap_last_cap(); i++)
541 cap_update(action, type, i);
542 } else {
543 int cap = capng_name_to_capability(c + 1);
544 if (0 <= cap)
545 cap_update(action, type, cap);
546 else if (sscanf(c + 1, "cap_%d", &cap) == 1
547 && 0 <= cap && cap <= cap_last_cap())
548 cap_update(action, type, cap);
549 else
550 errx(EXIT_FAILURE,
551 _("unknown capability \"%s\""), c + 1);
552 }
553 }
554
555 free(my_caps);
556 }
557
558 static void parse_securebits(struct privctx *opts, const char *arg)
559 {
560 char *buf = xstrdup(arg);
561 char *c;
562
563 opts->have_securebits = 1;
564 opts->securebits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
565 if (opts->securebits < 0)
566 err(SETPRIV_EXIT_PRIVERR, _("getting process secure bits failed"));
567
568 if (opts->securebits & ~(int)(SECBIT_NOROOT |
569 SECBIT_NOROOT_LOCKED |
570 SECBIT_NO_SETUID_FIXUP |
571 SECBIT_NO_SETUID_FIXUP_LOCKED |
572 SECBIT_KEEP_CAPS |
573 SECBIT_KEEP_CAPS_LOCKED))
574 errx(SETPRIV_EXIT_PRIVERR,
575 _("unrecognized securebit set -- refusing to adjust"));
576
577 while ((c = strsep(&buf, ","))) {
578 if (*c != '+' && *c != '-')
579 errx(EXIT_FAILURE, _("bad securebits string"));
580
581 if (!strcmp(c + 1, "all")) {
582 if (*c == '-')
583 opts->securebits = 0;
584 else
585 errx(EXIT_FAILURE,
586 _("+all securebits is not allowed"));
587 } else {
588 int bit;
589 if (!strcmp(c + 1, "noroot"))
590 bit = SECBIT_NOROOT;
591 else if (!strcmp(c + 1, "noroot_locked"))
592 bit = SECBIT_NOROOT_LOCKED;
593 else if (!strcmp(c + 1, "no_setuid_fixup"))
594 bit = SECBIT_NO_SETUID_FIXUP;
595 else if (!strcmp(c + 1, "no_setuid_fixup_locked"))
596 bit = SECBIT_NO_SETUID_FIXUP_LOCKED;
597 else if (!strcmp(c + 1, "keep_caps"))
598 errx(EXIT_FAILURE,
599 _("adjusting keep_caps does not make sense"));
600 else if (!strcmp(c + 1, "keep_caps_locked"))
601 bit = SECBIT_KEEP_CAPS_LOCKED; /* sigh */
602 else
603 errx(EXIT_FAILURE, _("unrecognized securebit"));
604
605 if (*c == '+')
606 opts->securebits |= bit;
607 else
608 opts->securebits &= ~bit;
609 }
610 }
611
612 opts->securebits |= SECBIT_KEEP_CAPS; /* We need it, and it's reset on exec */
613
614 free(buf);
615 }
616
617 static void do_selinux_label(const char *label)
618 {
619 int fd;
620 size_t len;
621
622 if (access(_PATH_SYS_SELINUX, F_OK) != 0)
623 errx(SETPRIV_EXIT_PRIVERR, _("SELinux is not running"));
624
625 fd = open(_PATH_PROC_ATTR_EXEC, O_RDWR);
626 if (fd == -1)
627 err(SETPRIV_EXIT_PRIVERR,
628 _("cannot open %s"), _PATH_PROC_ATTR_EXEC);
629
630 len = strlen(label);
631 errno = 0;
632 if (write(fd, label, len) != (ssize_t) len)
633 err(SETPRIV_EXIT_PRIVERR,
634 _("write failed: %s"), _PATH_PROC_ATTR_EXEC);
635
636 if (close(fd) != 0)
637 err(SETPRIV_EXIT_PRIVERR,
638 _("close failed: %s"), _PATH_PROC_ATTR_EXEC);
639 }
640
641 static void do_apparmor_profile(const char *label)
642 {
643 FILE *f;
644
645 if (access(_PATH_SYS_APPARMOR, F_OK) != 0)
646 errx(SETPRIV_EXIT_PRIVERR, _("AppArmor is not running"));
647
648 f = fopen(_PATH_PROC_ATTR_EXEC, "r+");
649 if (!f)
650 err(SETPRIV_EXIT_PRIVERR,
651 _("cannot open %s"), _PATH_PROC_ATTR_EXEC);
652
653 fprintf(f, "exec %s", label);
654
655 if (close_stream(f) != 0)
656 err(SETPRIV_EXIT_PRIVERR,
657 _("write failed: %s"), _PATH_PROC_ATTR_EXEC);
658 }
659
660 static void do_reset_environ(struct passwd *pw)
661 {
662 char *term = getenv("TERM");
663
664 if (term)
665 term = xstrdup(term);
666 #ifdef HAVE_CLEARENV
667 clearenv();
668 #else
669 environ = NULL;
670 #endif
671 if (term) {
672 xsetenv("TERM", term, 1);
673 free(term);
674 }
675
676 if (pw->pw_shell && *pw->pw_shell)
677 xsetenv("SHELL", pw->pw_shell, 1);
678 else
679 xsetenv("SHELL", DEFAULT_SHELL, 1);
680
681 xsetenv("HOME", pw->pw_dir, 1);
682 xsetenv("USER", pw->pw_name, 1);
683 xsetenv("LOGNAME", pw->pw_name, 1);
684
685 if (pw->pw_uid)
686 xsetenv("PATH", _PATH_DEFPATH, 1);
687 else
688 xsetenv("PATH", _PATH_DEFPATH_ROOT, 1);
689 }
690
691 static uid_t get_user(const char *s, const char *err)
692 {
693 struct passwd *pw;
694 long tmp;
695 pw = getpwnam(s);
696 if (pw)
697 return pw->pw_uid;
698 tmp = strtol_or_err(s, err);
699 return tmp;
700 }
701
702 static gid_t get_group(const char *s, const char *err)
703 {
704 struct group *gr;
705 long tmp;
706 gr = getgrnam(s);
707 if (gr)
708 return gr->gr_gid;
709 tmp = strtol_or_err(s, err);
710 return tmp;
711 }
712
713 static struct passwd *get_passwd(const char *s, uid_t *uid, const char *err)
714 {
715 struct passwd *pw;
716 long tmp;
717 pw = getpwnam(s);
718 if (pw) {
719 *uid = pw->pw_uid;
720 } else {
721 tmp = strtol_or_err(s, err);
722 *uid = tmp;
723 pw = getpwuid(*uid);
724 }
725 return pw;
726 }
727
728 static struct passwd *passwd_copy(struct passwd *dst, const struct passwd *src)
729 {
730 struct passwd *rv;
731 rv = memcpy(dst, src, sizeof(*dst));
732 rv->pw_name = xstrdup(rv->pw_name);
733 rv->pw_passwd = xstrdup(rv->pw_passwd);
734 rv->pw_gecos = xstrdup(rv->pw_gecos);
735 rv->pw_dir = xstrdup(rv->pw_dir);
736 rv->pw_shell = xstrdup(rv->pw_shell);
737 return rv;
738 }
739
740 int main(int argc, char **argv)
741 {
742 enum {
743 NNP = CHAR_MAX + 1,
744 RUID,
745 EUID,
746 RGID,
747 EGID,
748 REUID,
749 REGID,
750 CLEAR_GROUPS,
751 KEEP_GROUPS,
752 INIT_GROUPS,
753 GROUPS,
754 INHCAPS,
755 AMBCAPS,
756 LISTCAPS,
757 CAPBSET,
758 SECUREBITS,
759 PDEATHSIG,
760 SELINUX_LABEL,
761 APPARMOR_PROFILE,
762 LANDLOCK_ACCESS,
763 LANDLOCK_RULE,
764 RESET_ENV
765 };
766
767 static const struct option longopts[] = {
768 { "dump", no_argument, NULL, 'd' },
769 { "nnp", no_argument, NULL, NNP },
770 { "no-new-privs", no_argument, NULL, NNP },
771 { "inh-caps", required_argument, NULL, INHCAPS },
772 { "ambient-caps", required_argument, NULL, AMBCAPS },
773 { "list-caps", no_argument, NULL, LISTCAPS },
774 { "ruid", required_argument, NULL, RUID },
775 { "euid", required_argument, NULL, EUID },
776 { "rgid", required_argument, NULL, RGID },
777 { "egid", required_argument, NULL, EGID },
778 { "reuid", required_argument, NULL, REUID },
779 { "regid", required_argument, NULL, REGID },
780 { "clear-groups", no_argument, NULL, CLEAR_GROUPS },
781 { "keep-groups", no_argument, NULL, KEEP_GROUPS },
782 { "init-groups", no_argument, NULL, INIT_GROUPS },
783 { "groups", required_argument, NULL, GROUPS },
784 { "bounding-set", required_argument, NULL, CAPBSET },
785 { "securebits", required_argument, NULL, SECUREBITS },
786 { "pdeathsig", required_argument, NULL, PDEATHSIG, },
787 { "selinux-label", required_argument, NULL, SELINUX_LABEL },
788 { "apparmor-profile", required_argument, NULL, APPARMOR_PROFILE },
789 { "landlock-access", required_argument, NULL, LANDLOCK_ACCESS },
790 { "landlock-rule", required_argument, NULL, LANDLOCK_RULE },
791 { "help", no_argument, NULL, 'h' },
792 { "reset-env", no_argument, NULL, RESET_ENV, },
793 { "version", no_argument, NULL, 'V' },
794 { NULL, 0, NULL, 0 }
795 };
796
797 static const ul_excl_t excl[] = {
798 /* keep in same order with enum definitions */
799 {CLEAR_GROUPS, KEEP_GROUPS, INIT_GROUPS, GROUPS},
800 {0}
801 };
802 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
803
804 int c;
805 struct privctx opts;
806 struct passwd *pw = NULL;
807 int dumplevel = 0;
808 int total_opts = 0;
809 int list_caps = 0;
810
811 setlocale(LC_ALL, "");
812 bindtextdomain(PACKAGE, LOCALEDIR);
813 textdomain(PACKAGE);
814 close_stdout_atexit();
815
816 memset(&opts, 0, sizeof(opts));
817 init_landlock_opts(&opts.landlock);
818
819 while ((c = getopt_long(argc, argv, "+dhV", longopts, NULL)) != -1) {
820 err_exclusive_options(c, longopts, excl, excl_st);
821 total_opts++;
822 switch (c) {
823 case 'd':
824 dumplevel++;
825 break;
826 case NNP:
827 if (opts.nnp)
828 errx(EXIT_FAILURE,
829 _("duplicate --no-new-privs option"));
830 opts.nnp = 1;
831 break;
832 case RUID:
833 if (opts.have_ruid)
834 errx(EXIT_FAILURE, _("duplicate ruid"));
835 opts.have_ruid = 1;
836 pw = get_passwd(optarg, &opts.ruid, _("failed to parse ruid"));
837 if (pw) {
838 passwd_copy(&opts.passwd, pw);
839 opts.have_passwd = 1;
840 }
841 break;
842 case EUID:
843 if (opts.have_euid)
844 errx(EXIT_FAILURE, _("duplicate euid"));
845 opts.have_euid = 1;
846 opts.euid = get_user(optarg, _("failed to parse euid"));
847 break;
848 case REUID:
849 if (opts.have_ruid || opts.have_euid)
850 errx(EXIT_FAILURE, _("duplicate ruid or euid"));
851 opts.have_ruid = opts.have_euid = 1;
852 pw = get_passwd(optarg, &opts.ruid, _("failed to parse reuid"));
853 opts.euid = opts.ruid;
854 if (pw) {
855 passwd_copy(&opts.passwd, pw);
856 opts.have_passwd = 1;
857 }
858 break;
859 case RGID:
860 if (opts.have_rgid)
861 errx(EXIT_FAILURE, _("duplicate rgid"));
862 opts.have_rgid = 1;
863 opts.rgid = get_group(optarg, _("failed to parse rgid"));
864 break;
865 case EGID:
866 if (opts.have_egid)
867 errx(EXIT_FAILURE, _("duplicate egid"));
868 opts.have_egid = 1;
869 opts.egid = get_group(optarg, _("failed to parse egid"));
870 break;
871 case REGID:
872 if (opts.have_rgid || opts.have_egid)
873 errx(EXIT_FAILURE, _("duplicate rgid or egid"));
874 opts.have_rgid = opts.have_egid = 1;
875 opts.rgid = opts.egid = get_group(optarg, _("failed to parse regid"));
876 break;
877 case CLEAR_GROUPS:
878 if (opts.clear_groups)
879 errx(EXIT_FAILURE,
880 _("duplicate --clear-groups option"));
881 opts.clear_groups = 1;
882 break;
883 case KEEP_GROUPS:
884 if (opts.keep_groups)
885 errx(EXIT_FAILURE,
886 _("duplicate --keep-groups option"));
887 opts.keep_groups = 1;
888 break;
889 case INIT_GROUPS:
890 if (opts.init_groups)
891 errx(EXIT_FAILURE,
892 _("duplicate --init-groups option"));
893 opts.init_groups = 1;
894 break;
895 case GROUPS:
896 if (opts.have_groups)
897 errx(EXIT_FAILURE,
898 _("duplicate --groups option"));
899 parse_groups(&opts, optarg);
900 break;
901 case PDEATHSIG:
902 if (opts.pdeathsig)
903 errx(EXIT_FAILURE,
904 _("duplicate --keep-pdeathsig option"));
905 parse_pdeathsig(&opts, optarg);
906 break;
907 case LISTCAPS:
908 list_caps = 1;
909 break;
910 case INHCAPS:
911 if (opts.caps_to_inherit)
912 errx(EXIT_FAILURE,
913 _("duplicate --inh-caps option"));
914 opts.caps_to_inherit = optarg;
915 break;
916 case AMBCAPS:
917 if (opts.ambient_caps)
918 errx(EXIT_FAILURE,
919 _("duplicate --ambient-caps option"));
920 opts.ambient_caps = optarg;
921 break;
922 case CAPBSET:
923 if (opts.bounding_set)
924 errx(EXIT_FAILURE,
925 _("duplicate --bounding-set option"));
926 opts.bounding_set = optarg;
927 break;
928 case SECUREBITS:
929 if (opts.have_securebits)
930 errx(EXIT_FAILURE,
931 _("duplicate --securebits option"));
932 parse_securebits(&opts, optarg);
933 break;
934 case SELINUX_LABEL:
935 if (opts.selinux_label)
936 errx(EXIT_FAILURE,
937 _("duplicate --selinux-label option"));
938 opts.selinux_label = optarg;
939 break;
940 case APPARMOR_PROFILE:
941 if (opts.apparmor_profile)
942 errx(EXIT_FAILURE,
943 _("duplicate --apparmor-profile option"));
944 opts.apparmor_profile = optarg;
945 break;
946 case LANDLOCK_ACCESS:
947 parse_landlock_access(&opts.landlock, optarg);
948 break;
949 case LANDLOCK_RULE:
950 parse_landlock_rule(&opts.landlock, optarg);
951 break;
952 case RESET_ENV:
953 opts.reset_env = 1;
954 break;
955
956 case 'h':
957 usage();
958 case 'V':
959 print_version(EXIT_SUCCESS);
960 default:
961 errtryhelp(EXIT_FAILURE);
962 }
963 }
964
965 if (dumplevel) {
966 if (total_opts != dumplevel || optind < argc)
967 errx(EXIT_FAILURE,
968 _("--dump is incompatible with all other options"));
969 dump(dumplevel);
970 return EXIT_SUCCESS;
971 }
972
973 if (list_caps) {
974 if (total_opts != 1 || optind < argc)
975 errx(EXIT_FAILURE,
976 _("--list-caps must be specified alone"));
977 list_known_caps();
978 return EXIT_SUCCESS;
979 }
980
981 if (argc <= optind)
982 errx(EXIT_FAILURE, _("No program specified"));
983
984 if ((opts.have_rgid || opts.have_egid)
985 && !opts.keep_groups && !opts.clear_groups && !opts.init_groups
986 && !opts.have_groups)
987 errx(EXIT_FAILURE,
988 _("--[re]gid requires --keep-groups, --clear-groups, --init-groups, or --groups"));
989
990 if (opts.init_groups && !opts.have_ruid)
991 errx(EXIT_FAILURE,
992 _("--init-groups requires --ruid or --reuid"));
993
994 if (opts.init_groups && !opts.have_passwd)
995 errx(EXIT_FAILURE,
996 _("uid %ld not found, --init-groups requires an user that "
997 "can be found on the system"),
998 (long) opts.ruid);
999
1000 if (opts.reset_env) {
1001 if (opts.have_passwd)
1002 /* pwd according to --ruid or --reuid */
1003 pw = &opts.passwd;
1004 else
1005 /* pwd for the current user */
1006 pw = getpwuid(getuid());
1007 do_reset_environ(pw);
1008 }
1009
1010 if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
1011 err(EXIT_FAILURE, _("disallow granting new privileges failed"));
1012
1013 if (opts.selinux_label)
1014 do_selinux_label(opts.selinux_label);
1015 if (opts.apparmor_profile)
1016 do_apparmor_profile(opts.apparmor_profile);
1017
1018 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
1019 err(EXIT_FAILURE, _("keep process capabilities failed"));
1020
1021 /* We're going to want CAP_SETPCAP, CAP_SETUID, and CAP_SETGID if
1022 * possible. */
1023 bump_cap(CAP_SETPCAP);
1024 bump_cap(CAP_SETUID);
1025 bump_cap(CAP_SETGID);
1026 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
1027 err(SETPRIV_EXIT_PRIVERR, _("activate capabilities"));
1028
1029 if (opts.have_ruid || opts.have_euid) {
1030 do_setresuid(&opts);
1031 /* KEEPCAPS doesn't work for the effective mask. */
1032 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
1033 err(SETPRIV_EXIT_PRIVERR, _("reactivate capabilities"));
1034 }
1035
1036 if (opts.have_rgid || opts.have_egid)
1037 do_setresgid(&opts);
1038
1039 if (opts.have_groups) {
1040 if (setgroups(opts.num_groups, opts.groups) != 0)
1041 err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
1042 } else if (opts.init_groups) {
1043 if (initgroups(opts.passwd.pw_name, opts.passwd.pw_gid) != 0)
1044 err(SETPRIV_EXIT_PRIVERR, _("initgroups failed"));
1045 } else if (opts.clear_groups) {
1046 gid_t x = 0;
1047 if (setgroups(0, &x) != 0)
1048 err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
1049 }
1050
1051 if (opts.have_securebits && prctl(PR_SET_SECUREBITS, opts.securebits, 0, 0, 0) != 0)
1052 err(SETPRIV_EXIT_PRIVERR, _("set process securebits failed"));
1053
1054 if (opts.bounding_set) {
1055 do_caps(CAP_TYPE_BOUNDING, opts.bounding_set);
1056 errno = EPERM; /* capng doesn't set errno if we're missing CAP_SETPCAP */
1057 if (capng_apply(CAPNG_SELECT_BOUNDS) != 0)
1058 err(SETPRIV_EXIT_PRIVERR, _("apply bounding set"));
1059 }
1060
1061 if (opts.caps_to_inherit) {
1062 do_caps(CAP_TYPE_INHERITABLE, opts.caps_to_inherit);
1063 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
1064 err(SETPRIV_EXIT_PRIVERR, _("apply capabilities"));
1065 }
1066
1067 if (opts.ambient_caps) {
1068 do_caps(CAP_TYPE_AMBIENT, opts.ambient_caps);
1069 }
1070
1071 /* Clear or set parent death signal */
1072 if (opts.pdeathsig && prctl(PR_SET_PDEATHSIG, opts.pdeathsig < 0 ? 0 : opts.pdeathsig) != 0)
1073 err(SETPRIV_EXIT_PRIVERR, _("set parent death signal failed"));
1074
1075 do_landlock(&opts.landlock);
1076
1077 execvp(argv[optind], argv + optind);
1078 errexec(argv[optind]);
1079 }