exec: properly apply capability bounding set, add inverted bounding sets
This commit is contained in:
parent
893844ed43
commit
260abb780a
17
TODO
17
TODO
|
@ -23,23 +23,26 @@ F15:
|
||||||
* 0595f9a1c182a84581749823ef47c5f292e545f9 is borked, freezes shutdown
|
* 0595f9a1c182a84581749823ef47c5f292e545f9 is borked, freezes shutdown
|
||||||
(path: after installing inotify watches, recheck file again to fix race)
|
(path: after installing inotify watches, recheck file again to fix race)
|
||||||
|
|
||||||
* capability_bounding_set_drop not used
|
|
||||||
|
|
||||||
* rework syslog.service being up logic in PID 1
|
|
||||||
|
|
||||||
* rsyslog.service should hook itself into syslog.target?
|
* rsyslog.service should hook itself into syslog.target?
|
||||||
|
|
||||||
* syslog.target should be pulled in by multi-user.target?
|
* syslog.target should be pulled in by multi-user.target?
|
||||||
|
|
||||||
* pull in .service from meta .targers AND vice versa too. i.e. syslog.target ←→ rsyslog.service, rpcbind similarly
|
* pull in .service from meta .targers AND vice versa too. i.e. syslog.target ←→ rsyslog.service, rpcbind similarly
|
||||||
|
|
||||||
* drop Names= option? Symlinks only should be used. We don't want to need to read all service files.
|
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* hide passwords on TAB
|
||||||
|
|
||||||
|
* add switch to systemctl to show enabled but not running services. Or
|
||||||
|
another switch that shows service that have been running since
|
||||||
|
booting but aren't running anymore.
|
||||||
|
|
||||||
|
* reuse mkdtemp namespace dirs in /tmp?
|
||||||
|
|
||||||
* don't strip facility from kmsg log messages as soon as that is possible.
|
* don't strip facility from kmsg log messages as soon as that is possible.
|
||||||
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=9d90c8d9cde929cbc575098e825d7c29d9f45054
|
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=9d90c8d9cde929cbc575098e825d7c29d9f45054
|
||||||
|
|
||||||
* recreate systemd'd D-Bus private socket file on SIGUSR2
|
* recreate systemd's D-Bus private socket file on SIGUSR2
|
||||||
|
|
||||||
* be more specific what failed:
|
* be more specific what failed:
|
||||||
Unmounting file systems.
|
Unmounting file systems.
|
||||||
|
|
|
@ -597,16 +597,34 @@
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>Capabilities=</varname></term>
|
<term><varname>CapabilityBoundingSet=</varname></term>
|
||||||
<listitem><para>Controls the
|
|
||||||
|
<listitem><para>Controls which
|
||||||
|
capabilities to include in the
|
||||||
|
capability bounding set for the
|
||||||
|
executed process. See
|
||||||
<citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||||
set for the executed process. Take a
|
for details. Takes a whitespace
|
||||||
capability string as described in
|
seperated list of capability names as
|
||||||
<citerefentry><refentrytitle>cap_from_text</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
read by
|
||||||
Note that this capability set is
|
<citerefentry><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||||
usually influenced by the capabilities
|
Capabilities listed will be included
|
||||||
attached to the executed
|
in the bounding set, all others are
|
||||||
file.</para></listitem>
|
removed. If the list of capabilities
|
||||||
|
is prefixed with ~ all but the listed
|
||||||
|
capabilities will be included, the
|
||||||
|
effect of this assignment
|
||||||
|
inverted. Note that this option does
|
||||||
|
not actually set or unset any
|
||||||
|
capabilities in the effective,
|
||||||
|
permitted or inherited capability
|
||||||
|
sets. That's what
|
||||||
|
<varname>Capabilities=</varname> is
|
||||||
|
for. If this option is not used the
|
||||||
|
capability bounding set is not
|
||||||
|
modified on process execution, hence
|
||||||
|
no limits on the capabilities of the
|
||||||
|
process are enforced.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -625,16 +643,21 @@
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>CapabilityBoundingSetDrop=</varname></term>
|
<term><varname>Capabilities=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Controls the
|
<listitem><para>Controls the
|
||||||
capability bounding set drop set for
|
|
||||||
the executed process. See
|
|
||||||
<citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||||
for details. Takes a list of
|
set for the executed process. Take a
|
||||||
capability names as read by
|
capability string describing the
|
||||||
<citerefentry><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
effective, permitted and inherited
|
||||||
</para></listitem>
|
capability sets as documented in
|
||||||
|
<citerefentry><refentrytitle>cap_from_text</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||||
|
Note that these capability sets are
|
||||||
|
usually influenced by the capabilities
|
||||||
|
attached to the executed file. Due to
|
||||||
|
that
|
||||||
|
<varname>CapabilityBoundingSet=</varname>
|
||||||
|
is probably the much more useful
|
||||||
|
setting.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -234,6 +234,24 @@ int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const ch
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bus_execute_append_capability_bs(Manager *m, DBusMessageIter *i, const char *property, void *data) {
|
||||||
|
ExecContext *c = data;
|
||||||
|
uint64_t normal, inverted;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(i);
|
||||||
|
assert(property);
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
/* We store this negated internally, to match the kernel, bu
|
||||||
|
* we expose it normalized. */
|
||||||
|
|
||||||
|
normal = *(uint64_t*) data;
|
||||||
|
inverted = ~normal;
|
||||||
|
|
||||||
|
return bus_property_append_uint64(m, i, property, &inverted);
|
||||||
|
}
|
||||||
|
|
||||||
int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data) {
|
int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data) {
|
||||||
ExecContext *c = data;
|
ExecContext *c = data;
|
||||||
char *t = NULL;
|
char *t = NULL;
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
{ interface, "SyslogLevelPrefix", bus_property_append_bool, "b", &(context).syslog_level_prefix }, \
|
{ interface, "SyslogLevelPrefix", bus_property_append_bool, "b", &(context).syslog_level_prefix }, \
|
||||||
{ interface, "Capabilities", bus_execute_append_capabilities, "s",&(context) }, \
|
{ interface, "Capabilities", bus_execute_append_capabilities, "s",&(context) }, \
|
||||||
{ interface, "SecureBits", bus_property_append_int, "i", &(context).secure_bits }, \
|
{ interface, "SecureBits", bus_property_append_int, "i", &(context).secure_bits }, \
|
||||||
{ interface, "CapabilityBoundingSetDrop", bus_property_append_uint64, "t", &(context).capability_bounding_set_drop }, \
|
{ interface, "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", &(context).capability_bounding_set_drop }, \
|
||||||
{ interface, "User", bus_property_append_string, "s", (context).user }, \
|
{ interface, "User", bus_property_append_string, "s", (context).user }, \
|
||||||
{ interface, "Group", bus_property_append_string, "s", (context).group }, \
|
{ interface, "Group", bus_property_append_string, "s", (context).group }, \
|
||||||
{ interface, "SupplementaryGroups", bus_property_append_strv, "as", (context).supplementary_groups }, \
|
{ interface, "SupplementaryGroups", bus_property_append_strv, "as", (context).supplementary_groups }, \
|
||||||
|
@ -167,6 +167,7 @@ int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const
|
||||||
int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||||
int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||||
int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||||
|
int bus_execute_append_capability_bs(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||||
int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||||
int bus_execute_append_command(Manager *m, DBusMessageIter *u, const char *property, void *data);
|
int bus_execute_append_command(Manager *m, DBusMessageIter *u, const char *property, void *data);
|
||||||
int bus_execute_append_kill_mode(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
int bus_execute_append_kill_mode(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||||
|
|
|
@ -1249,6 +1249,15 @@ int exec_spawn(ExecCommand *command,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context->capability_bounding_set_drop)
|
||||||
|
for (i = 0; i <= CAP_LAST_CAP; i++)
|
||||||
|
if (context->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i)) {
|
||||||
|
if (prctl(PR_CAPBSET_DROP, i) < 0) {
|
||||||
|
r = EXIT_CAPABILITIES;
|
||||||
|
goto fail_child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (context->user)
|
if (context->user)
|
||||||
if (enforce_user(context, uid) < 0) {
|
if (enforce_user(context, uid) < 0) {
|
||||||
r = EXIT_USER;
|
r = EXIT_USER;
|
||||||
|
@ -1664,15 +1673,15 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
||||||
(c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
|
(c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
|
||||||
|
|
||||||
if (c->capability_bounding_set_drop) {
|
if (c->capability_bounding_set_drop) {
|
||||||
fprintf(f, "%sCapabilityBoundingSetDrop:", prefix);
|
fprintf(f, "%sCapabilityBoundingSet:", prefix);
|
||||||
|
|
||||||
for (i = 0; i <= CAP_LAST_CAP; i++)
|
for (i = 0; i <= CAP_LAST_CAP; i++)
|
||||||
if (c->capability_bounding_set_drop & (1 << i)) {
|
if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i))) {
|
||||||
char *t;
|
char *t;
|
||||||
|
|
||||||
if ((t = cap_to_name(i))) {
|
if ((t = cap_to_name(i))) {
|
||||||
fprintf(f, " %s", t);
|
fprintf(f, " %s", t);
|
||||||
free(t);
|
cap_free(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -852,12 +852,24 @@ static int config_parse_bounding_set(
|
||||||
char *w;
|
char *w;
|
||||||
size_t l;
|
size_t l;
|
||||||
char *state;
|
char *state;
|
||||||
|
bool invert = false;
|
||||||
|
uint64_t sum = 0;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
assert(lvalue);
|
assert(lvalue);
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
assert(data);
|
||||||
|
|
||||||
|
if (rvalue[0] == '~') {
|
||||||
|
invert = true;
|
||||||
|
rvalue++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that we store this inverted internally, since the
|
||||||
|
* kernel wants it like this. But we actually expose it
|
||||||
|
* non-inverted everywhere to have a fully normalized
|
||||||
|
* interface. */
|
||||||
|
|
||||||
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
|
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
|
||||||
char *t;
|
char *t;
|
||||||
int r;
|
int r;
|
||||||
|
@ -874,9 +886,14 @@ static int config_parse_bounding_set(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->capability_bounding_set_drop |= 1 << cap;
|
sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (invert)
|
||||||
|
c->capability_bounding_set_drop |= sum;
|
||||||
|
else
|
||||||
|
c->capability_bounding_set_drop |= ~sum;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1772,7 +1789,7 @@ static int load_from_path(Unit *u, const char *path) {
|
||||||
{ "SyslogLevelPrefix", config_parse_bool, &(context).syslog_level_prefix, section }, \
|
{ "SyslogLevelPrefix", config_parse_bool, &(context).syslog_level_prefix, section }, \
|
||||||
{ "Capabilities", config_parse_capabilities, &(context), section }, \
|
{ "Capabilities", config_parse_capabilities, &(context), section }, \
|
||||||
{ "SecureBits", config_parse_secure_bits, &(context), section }, \
|
{ "SecureBits", config_parse_secure_bits, &(context), section }, \
|
||||||
{ "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context), section }, \
|
{ "CapabilityBoundingSet", config_parse_bounding_set, &(context), section }, \
|
||||||
{ "TimerSlackNSec", config_parse_timer_slack_nsec,&(context), section }, \
|
{ "TimerSlackNSec", config_parse_timer_slack_nsec,&(context), section }, \
|
||||||
{ "LimitCPU", config_parse_limit, &(context).rlimit[RLIMIT_CPU], section }, \
|
{ "LimitCPU", config_parse_limit, &(context).rlimit[RLIMIT_CPU], section }, \
|
||||||
{ "LimitFSIZE", config_parse_limit, &(context).rlimit[RLIMIT_FSIZE], section }, \
|
{ "LimitFSIZE", config_parse_limit, &(context).rlimit[RLIMIT_FSIZE], section }, \
|
||||||
|
|
Loading…
Reference in New Issue