core/execute: add the magic character '!' to allow privileged execution (#3493)
This patch implements the new magic character '!'. By putting '!' in front of a command, systemd executes it with full privileges ignoring paramters such as User, Group, SupplementaryGroups, CapabilityBoundingSet, AmbientCapabilities, SecureBits, SystemCallFilter, SELinuxContext, AppArmorProfile, SmackProcessLabel, and RestrictAddressFamilies. Fixes partially https://github.com/systemd/systemd/issues/3414 Related to https://github.com/coreos/rkt/issues/2482 Testing: 1. Create a user 'bob' 2. Create the unit file /etc/systemd/system/exec-perm.service (You can use the example below) 3. sudo systemctl start ext-perm.service 4. Verify that the commands starting with '!' were not executed as bob, 4.1 Looking to the output of ls -l /tmp/exec-perm 4.2 Each file contains the result of the id command. ````````````````````````````````````````````````````````````````` [Unit] Description=ext-perm [Service] Type=oneshot TimeoutStartSec=0 User=bob ExecStartPre=!/usr/bin/sh -c "/usr/bin/rm /tmp/exec-perm*" ; /usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start-pre" ExecStart=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start" ; !/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-star-2" ExecStartPost=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start-post" ExecReload=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-reload" ExecStop=!/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-stop" ExecStopPost=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-stop-post" [Install] WantedBy=multi-user.target] `````````````````````````````````````````````````````````````````
This commit is contained in:
parent
a4e9499d8d
commit
cf677fe686
|
@ -146,7 +146,7 @@
|
|||
<listitem><para>Sets the Unix user or group that the processes
|
||||
are executed as, respectively. Takes a single user or group
|
||||
name or ID as argument. If no group is set, the default group
|
||||
of the user is chosen.</para></listitem>
|
||||
of the user is chosen. These do not affect commands prefixed with <literal>!</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -161,7 +161,7 @@
|
|||
this one will have no effect. In any way, this option does not
|
||||
override, but extends the list of supplementary groups
|
||||
configured in the system group database for the
|
||||
user.</para></listitem>
|
||||
user. This does not affect commands prefixed with <literal>!</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -795,7 +795,8 @@
|
|||
process are enforced. This option may appear more than once, in which case the bounding sets are merged. If the
|
||||
empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior
|
||||
settings have no effect. If set to <literal>~</literal> (without any further argument), the bounding set is
|
||||
reset to the full set of available capabilities, also undoing any previous settings.</para></listitem>
|
||||
reset to the full set of available capabilities, also undoing any previous settings. This does not affect
|
||||
commands prefixed with <literal>!</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -824,7 +825,8 @@
|
|||
as a non-privileged user but still want to give it some capabilities.
|
||||
Note that in this case option <constant>keep-caps</constant> is
|
||||
automatically added to <varname>SecureBits=</varname> to retain the
|
||||
capabilities over the user change.</para></listitem>
|
||||
capabilities over the user change. <varname>AmbientCapabilities=</varname> does not affect
|
||||
commands prefixed with <literal>!</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -840,8 +842,8 @@
|
|||
<option>noroot-locked</option>.
|
||||
This option may appear more than once, in which case the secure
|
||||
bits are ORed. If the empty string is assigned to this option,
|
||||
the bits are reset to 0. See
|
||||
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
the bits are reset to 0. This does not affect commands prefixed with <literal>!</literal>.
|
||||
See <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
for details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -1097,8 +1099,8 @@
|
|||
domain transition. However, the policy still needs to
|
||||
authorize the transition. This directive is ignored if SELinux
|
||||
is disabled. If prefixed by <literal>-</literal>, all errors
|
||||
will be ignored. See
|
||||
<citerefentry project='die-net'><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
will be ignored. This does not affect commands prefixed with <literal>!</literal>.
|
||||
See <citerefentry project='die-net'><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
for details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -1110,7 +1112,7 @@
|
|||
Profiles must already be loaded in the kernel, or the unit
|
||||
will fail. This result in a non operation if AppArmor is not
|
||||
enabled. If prefixed by <literal>-</literal>, all errors will
|
||||
be ignored. </para></listitem>
|
||||
be ignored. This does not affect commands prefixed with <literal>!</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -1129,7 +1131,8 @@
|
|||
|
||||
<para>The value may be prefixed by <literal>-</literal>, in
|
||||
which case all errors will be ignored. An empty value may be
|
||||
specified to unset previous assignments.</para>
|
||||
specified to unset previous assignments. This does not affect
|
||||
commands prefixed with <literal>!</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -1180,7 +1183,7 @@
|
|||
listed explicitly. This option may be specified more than once,
|
||||
in which case the filter masks are merged. If the empty string
|
||||
is assigned, the filter is reset, all prior assignments will
|
||||
have no effect.</para>
|
||||
have no effect. This does not affect commands prefixed with <literal>!</literal>.</para>
|
||||
|
||||
<para>If you specify both types of this option (i.e.
|
||||
whitelisting and blacklisting), the first encountered will
|
||||
|
@ -1343,7 +1346,7 @@
|
|||
family should be included in the configured whitelist as it is
|
||||
frequently used for local communication, including for
|
||||
<citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
logging.</para></listitem>
|
||||
logging. This does not affect commands prefixed with <literal>!</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -295,9 +295,10 @@
|
|||
If the absolute filename is prefixed with
|
||||
<literal>-</literal>, an exit code of the command normally
|
||||
considered a failure (i.e. non-zero exit status or abnormal
|
||||
exit due to signal) is ignored and considered success. If both
|
||||
<literal>-</literal> and <literal>@</literal> are used, they
|
||||
can appear in either order.</para>
|
||||
exit due to signal) is ignored and considered success.
|
||||
If the absolute path is prefixed with <literal>!</literal> then
|
||||
it is executed with full privileges. <literal>-</literal>, <literal>@</literal>, and <literal>!</literal>
|
||||
may be used together and they can appear in any order.</para>
|
||||
|
||||
<para>If more than one command is specified, the commands are
|
||||
invoked sequentially in the order they appear in the unit
|
||||
|
|
|
@ -1717,7 +1717,7 @@ static int exec_child(
|
|||
|
||||
umask(context->umask);
|
||||
|
||||
if (params->apply_permissions) {
|
||||
if (params->apply_permissions && !command->privileged) {
|
||||
r = enforce_groups(context, username, gid);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_GROUP;
|
||||
|
@ -1842,7 +1842,7 @@ static int exec_child(
|
|||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
|
||||
if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) {
|
||||
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_SELINUX_CONTEXT;
|
||||
|
@ -1867,7 +1867,7 @@ static int exec_child(
|
|||
return r;
|
||||
}
|
||||
|
||||
if (params->apply_permissions) {
|
||||
if (params->apply_permissions && !command->privileged) {
|
||||
|
||||
bool use_address_families = context->address_families_whitelist ||
|
||||
!set_isempty(context->address_families);
|
||||
|
|
|
@ -81,7 +81,8 @@ struct ExecCommand {
|
|||
char **argv;
|
||||
ExecStatus exec_status;
|
||||
LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
|
||||
bool ignore;
|
||||
bool ignore:1;
|
||||
bool privileged:1;
|
||||
};
|
||||
|
||||
struct ExecRuntime {
|
||||
|
|
|
@ -596,7 +596,7 @@ int config_parse_exec(
|
|||
p = rvalue;
|
||||
do {
|
||||
_cleanup_free_ char *path = NULL, *firstword = NULL;
|
||||
bool separate_argv0 = false, ignore = false;
|
||||
bool separate_argv0 = false, ignore = false, privileged = false;
|
||||
_cleanup_free_ ExecCommand *nce = NULL;
|
||||
_cleanup_strv_free_ char **n = NULL;
|
||||
size_t nlen = 0, nbufsize = 0;
|
||||
|
@ -610,14 +610,18 @@ int config_parse_exec(
|
|||
return 0;
|
||||
|
||||
f = firstword;
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* We accept an absolute path as first argument, or
|
||||
* alternatively an absolute prefixed with @ to allow
|
||||
* overriding of argv[0]. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* We accept an absolute path as first argument.
|
||||
* If it's prefixed with - and the path doesn't exist,
|
||||
* we ignore it instead of erroring out;
|
||||
* if it's prefixed with @, we allow overriding of argv[0];
|
||||
* and if it's prefixed with !, it will be run with full privileges */
|
||||
if (*f == '-' && !ignore)
|
||||
ignore = true;
|
||||
else if (*f == '@' && !separate_argv0)
|
||||
separate_argv0 = true;
|
||||
else if (*f == '!' && !privileged)
|
||||
privileged = true;
|
||||
else
|
||||
break;
|
||||
f++;
|
||||
|
@ -715,6 +719,7 @@ int config_parse_exec(
|
|||
nce->argv = n;
|
||||
nce->path = path;
|
||||
nce->ignore = ignore;
|
||||
nce->privileged = privileged;
|
||||
|
||||
exec_command_append_list(e, nce);
|
||||
|
||||
|
|
Loading…
Reference in New Issue