From: Andy Lutomirski Date: Mon, 14 Jan 2013 15:58:57 +0000 (-0800) Subject: setpriv: run a program with different Linux privilege settings X-Git-Tag: v2.23-rc1~255 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5600c405d5f1b12cad94915014e7cb46bf8fb746;p=thirdparty%2Futil-linux.git setpriv: run a program with different Linux privilege settings This new command can set no_new_privs, uid, gid, groups, securebits, inheritable caps, the cap bounding set, securebits, and selinux and apparmor labels. [kerolasa@iki.fi: a lot of small adjustment making the command to be good fit to util-linux project] Signed-off-by: Sami Kerola Signed-off-by: Andy Lutomirski --- diff --git a/.gitignore b/.gitignore index b2e9d6d545..7dbb81c0bb 100644 --- a/.gitignore +++ b/.gitignore @@ -150,6 +150,7 @@ tests/run.sh.trs /script /scriptreplay /setarch +/setpriv /setsid /setterm /sfdisk diff --git a/configure.ac b/configure.ac index 9024809e7e..d3a8e9e7f9 100644 --- a/configure.ac +++ b/configure.ac @@ -879,6 +879,20 @@ if test "x$build_nsenter" = xyes; then AC_CHECK_FUNCS([setns]) fi +dnl setpriv depends on libcap-ng. It would be possible to build +dnl a version of setpriv with limited functionality without libcap-ng, +dnl but this isn't currently supported. +UL_CHECK_LIB([cap-ng], [capng_apply], [cap_ng]) +AC_ARG_ENABLE([setpriv], + AS_HELP_STRING([--disable-setpriv], [do not build setpriv]), + [], enable_setpriv=check +) +UL_BUILD_INIT([setpriv]) +UL_REQUIRES_LINUX([setpriv]) +UL_REQUIRES_HAVE([setpriv], [cap_ng], [libcap-ng]) +AM_CONDITIONAL(BUILD_SETPRIV, test "x$build_setpriv" = xyes) + + AC_ARG_ENABLE([arch], AS_HELP_STRING([--enable-arch], [do build arch]), [], enable_arch=no diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am index 978d97f7d6..86c529eae0 100644 --- a/sys-utils/Makemodule.am +++ b/sys-utils/Makemodule.am @@ -318,3 +318,10 @@ if HAVE_AUDIT hwclock_LDADD += -laudit endif endif # BUILD_HWCLOCK + +if BUILD_SETPRIV +usrbin_exec_PROGRAMS += setpriv +dist_man_MANS += sys-utils/setpriv.1 +setpriv_SOURCES = sys-utils/setpriv.c +setpriv_LDADD = $(LDADD) -lcap-ng libcommon.la +endif diff --git a/sys-utils/setpriv.1 b/sys-utils/setpriv.1 new file mode 100644 index 0000000000..c56d89f5f9 --- /dev/null +++ b/sys-utils/setpriv.1 @@ -0,0 +1,149 @@ +.TH SETPRIV 1 "January 2013" "util-linux" "User Commands" +.SH NAME +setpriv \- run a program with different Linux privilege settings +.SH SYNOPSIS +.B setpriv +.RI [ options ] +program +.RI [ arguments ] +.SH DESCRIPTION +Sets or queries various Linux privilege settings that are inherited across +.BR execve (2). +.SH OPTION +.TP +\fB\-d\fR, \fB\-\-dump\fR +Dumps current privilege state. Specify more than once to show extra, mostly +useless, information. Incompatible with all other options. +.TP +\fB\-\-no\-new\-privs\fR +Sets the +.I no_\:new_\:privs +bit. With this bit set, +.BR execve (2) +will not grant new privileges. For example, the setuid and setgid bits as well +as file capabilities will be disabled. (Executing binaries with these bits set +will still work, but they will not gain privilege. Certain LSMs, especially +AppArmor, may result in failures to execute certain programs.) This bit is +inherited by child processes and cannot be unset. See +.BR prctl (2) +and +.IR Documentation/\:prctl/\:no_\:new_\:privs.txt +in the Linux kernel source. +.IP +The no_\:new_\:privs bit is supported since Linux 3.5. +.TP +\fB\-\-inh\-caps\fR \fI(+|\-)cap\fR,\fI...\fR or \fB\-\-bounding\-set\fR \fI(+|\-)cap\fR,\fI...\fR +Sets inheritable capabilities or capability bounding set. See +.BR capabilities (7). +The argument is a comma-separated list of +.I +cap +and +.I \-cap +entries, which add or remove an entry respectively. +.I +all +and +.I \-all +can be used to add or remove all caps. The set of capabilities starts out as +the current inheritable set for +.B \-\-\:inh\-\:caps +and the current bounding set for +.BR \-\-\:bounding\-\:set . +If you drop something from the bounding set without also dropping it from the +inheritable set, you are likely to become confused. Do not do that. +.TP +.BR \-\-list\-caps +Lists all known capabilities. Must be specified alone. +.TP +\fB\-\-ruid\fR \fIuid\fR, \fB\-\-euid\fR \fIuid\fR, \fB\-\-reuid\fR \fIuid\fR +Sets the real, effective, or both \fIuid\fRs. +.IP +Setting +.I uid +or +.I gid +does not change capabilities, although the exec call at the end might change +capabilities. This means that, if you are root, you probably want to do +something like: +.IP +\-\-reuid=1000 \-\-\:regid=1000 \-\-\:caps=\-\:all +.TP +\fB\-\-rgid\fR \fIgid\fR, \fB\-\-egid\fR \fIgid\fR, \fB\-\-regid\fR \fIgid\fR +Sets the real, effective, or both \fIgid\fRs. +.IP +For safety, you must specify one of \-\-\:keep\-\:groups, +\-\-\:clear\-\:groups, or \-\-\:groups if you set any primary +.IR gid . +.TP +.BR \-\-clear\-groups +Clears supplementary groups. +.TP +\fB\-\-keep\-groups\fR +Preserves supplementary groups. Only useful in conjunction with \-\-rgid, +\-\-egid, or \-\-regid. +.TP +\fB\-\-groups\fR \fIgroup\fR,\fI...\fR +Sets supplementary groups. +.TP +\fB\-\-securebits\fR \fI(+|\-)securebit\fR,\fI...\fR +Sets or clears securebits. The valid securebits are +.IR noroot , +.IR noroot_\:locked , +.IR no_\:setuid_\:fixup , +.IR no_\:setuid_\:fixup_\:locked , +and +.IR keep_\:caps_\:locked . +.I keep_\:caps +is cleared by +.BR execve (2) +and is therefore not allowed. +.TP +\fB\-\-selinux\-label\fR \fIlabel\fR +Requests a particular SELinux transition (using a transition on exec, not +dyntrans). This will fail and cause +.BR setpriv (1) +to abort if SELinux is not in use, and the transition may be ignored or cause +.BR execve (2) +to fail at SELinux's whim. (In particular, this is unlikely to work in +conjunction with +.IR no_\:new_\:privs .) +This is similar to +.BR runcon (1). +.TP +\fB\-\-apparmor\-profile\fR \fIprofile\fR +Requests a particular AppArmor profile (using a transition on exec). This will +fail and cause +.BR setpriv (1) +to abort if AppArmor is not in use, and the transition may be ignored or cause +.BR execve (2) +to fail at AppArmor's whim. +.TP +\fB\-V\fR, \fB\-\-version\fR +Display version information and exit. +.TP +\fB\-h\fR, \fB\-\-help\fR +Display help and exit. +.SH NOTES +If applying any specified option fails, +.I program +will not be run and +.B setpriv +will return with exit code 127. +.PP +Be careful with this tool \-\- it may have unexpected security consequences. +For example, setting no_\:new_\:privs and then execing a program that is +SELinux\-\:confined (as this tool would do) may prevent the SELinux +restrictions from taking effect. +.SH SEE ALSO +.BR prctl (2) +.BR capability (7) +.SH AUTHOR +.MT luto@amacapital.net +Andy Lutomirski +.ME +.SH AVAILABILITY +The +.B setpriv +command is part of the util-linux package and is available from +.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/ +Linux Kernel Archive +.UE . diff --git a/sys-utils/setpriv.c b/sys-utils/setpriv.c new file mode 100644 index 0000000000..1662daf871 --- /dev/null +++ b/sys-utils/setpriv.c @@ -0,0 +1,814 @@ +/* + * setpriv(1) - set various kernel privilege bits and run something + * + * Copyright (C) 2012 Andy Lutomirski + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bitops.h" +#include "c.h" +#include "closestream.h" +#include "nls.h" +#include "optutils.h" +#include "strutils.h" +#include "xalloc.h" + +#ifndef PR_SET_NO_NEW_PRIVS +# define PR_SET_NO_NEW_PRIVS 38 +#endif +#ifndef PR_GET_NO_NEW_PRIVS +# define PR_GET_NO_NEW_PRIVS 39 +#endif + +#define SETPRIV_EXIT_PRIVERR 127 /* how we exit when we fail to set privs */ + +/* + * Note: We are subject to https://bugzilla.redhat.com/show_bug.cgi?id=895105 + * and we will therefore have problems if new capabilities are added. Once + * that bug is fixed, I'll (Andy Lutomirski) submit a corresponding fix to + * setpriv. In the mean time, the code here tries to work reasonably well. + */ + +struct privctx { + /* bit arrays -- see include/bitops.h */ + unsigned int + nnp:1, /* no_new_privs */ + have_ruid:1, /* real uid */ + have_euid:1, /* effective uid */ + have_rgid:1, /* real gid */ + have_egid:1, /* effective gid */ + have_groups:1, /* add groups */ + keep_groups:1, /* keep groups */ + clear_groups:1, /* remove groups */ + have_securebits:1; /* remove groups */ + + /* uids and gids */ + uid_t ruid, euid; + gid_t rgid, egid; + + /* supplementary groups */ + size_t num_groups; + gid_t *groups; + + /* caps */ + const char *caps_to_inherit; + const char *bounding_set; + + /* securebits */ + int securebits; + + /* LSMs */ + const char *selinux_label; + const char *apparmor_profile; +}; + +static void __attribute__((__noreturn__)) usage(FILE *out) +{ + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options] [args...]\n"), program_invocation_short_name); + fputs(USAGE_OPTIONS, out); + fputs(_(" -d, --dump show current state (and do not exec anything)\n"), out); + fputs(_(" --nnp, --no-new-privs disallow granting new privileges\n"), out); + fputs(_(" --inh-caps set inheritable capabilities\n"), out); + fputs(_(" --bounding-set set capability bounding set\n"), out); + fputs(_(" --ruid set real uid\n"), out); + fputs(_(" --euid set effective uid\n"), out); + fputs(_(" --rgid set real gid\n"), out); + fputs(_(" --egid set effective gid\n"), out); + fputs(_(" --reuid set real and effective uid\n"), out); + fputs(_(" --regid set real and effective gid\n"), out); + fputs(_(" --clear-groups clear supplementary groups\n"), out); + fputs(_(" --keep-groups keep supplementary groups\n"), out); + fputs(_(" --groups set supplementary groups\n"), out); + fputs(_(" --securebits set securebits\n"), out); + fputs(_(" --selinux-label