|
|
a19bc6 |
From 201006fa521199ebf109016c9dd22812c435dfe9 Mon Sep 17 00:00:00 2001
|
|
|
a19bc6 |
From: Ismo Puustinen <ismo.puustinen@intel.com>
|
|
|
a19bc6 |
Date: Fri, 8 Jan 2016 00:00:04 +0200
|
|
|
a19bc6 |
Subject: [PATCH] capabilities: keep bounding set in non-inverted format.
|
|
|
a19bc6 |
|
|
|
a19bc6 |
Change the capability bounding set parser and logic so that the bounding
|
|
|
a19bc6 |
set is kept as a positive set internally. This means that the set
|
|
|
a19bc6 |
reflects those capabilities that we want to keep instead of drop.
|
|
|
a19bc6 |
|
|
|
a19bc6 |
Resolves: #1387398
|
|
|
a19bc6 |
---
|
|
|
a19bc6 |
src/core/dbus-execute.c | 4 +-
|
|
|
a19bc6 |
src/core/execute.c | 9 ++--
|
|
|
a19bc6 |
src/core/execute.h | 2 +-
|
|
|
a19bc6 |
src/core/load-fragment-gperf.gperf.m4 | 2 +-
|
|
|
a19bc6 |
src/core/load-fragment.c | 25 +++++-----
|
|
|
a19bc6 |
src/core/load-fragment.h | 2 +-
|
|
|
a19bc6 |
src/core/main.c | 10 ++--
|
|
|
a19bc6 |
src/core/unit.c | 2 +-
|
|
|
a19bc6 |
src/import/import-common.c | 2 +-
|
|
|
a19bc6 |
src/nspawn/nspawn.c | 2 +-
|
|
|
a19bc6 |
src/shared/capability.c | 16 +++----
|
|
|
a19bc6 |
src/shared/capability.h | 12 ++++-
|
|
|
a19bc6 |
src/test/test-unit-file.c | 89 +++++++++++++++++++----------------
|
|
|
a19bc6 |
13 files changed, 96 insertions(+), 81 deletions(-)
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
|
|
|
a19bc6 |
index da8b10d..a564c53 100644
|
|
|
a19bc6 |
--- a/src/core/dbus-execute.c
|
|
|
a19bc6 |
+++ b/src/core/dbus-execute.c
|
|
|
a19bc6 |
@@ -324,9 +324,7 @@ static int property_get_capability_bounding_set(
|
|
|
a19bc6 |
assert(reply);
|
|
|
a19bc6 |
assert(c);
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- /* We store this negated internally, to match the kernel, but
|
|
|
a19bc6 |
- * we expose it normalized. */
|
|
|
a19bc6 |
- return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
|
|
|
a19bc6 |
+ return sd_bus_message_append(reply, "t", c->capability_bounding_set);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
static int property_get_capabilities(
|
|
|
a19bc6 |
diff --git a/src/core/execute.c b/src/core/execute.c
|
|
|
a19bc6 |
index f72b209..40db11e 100644
|
|
|
a19bc6 |
--- a/src/core/execute.c
|
|
|
a19bc6 |
+++ b/src/core/execute.c
|
|
|
a19bc6 |
@@ -1733,8 +1733,8 @@ static int exec_child(
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- if (context->capability_bounding_set_drop) {
|
|
|
a19bc6 |
- r = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
|
|
|
a19bc6 |
+ if (!cap_test_all(context->capability_bounding_set)) {
|
|
|
a19bc6 |
+ r = capability_bounding_set_drop(context->capability_bounding_set, false);
|
|
|
a19bc6 |
if (r < 0) {
|
|
|
a19bc6 |
*exit_status = EXIT_CAPABILITIES;
|
|
|
a19bc6 |
return r;
|
|
|
a19bc6 |
@@ -1988,6 +1988,7 @@ void exec_context_init(ExecContext *c) {
|
|
|
a19bc6 |
c->timer_slack_nsec = NSEC_INFINITY;
|
|
|
a19bc6 |
c->personality = 0xffffffffUL;
|
|
|
a19bc6 |
c->runtime_directory_mode = 0755;
|
|
|
a19bc6 |
+ c->capability_bounding_set = CAP_ALL;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
void exec_context_done(ExecContext *c) {
|
|
|
a19bc6 |
@@ -2419,12 +2420,12 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
|
|
a19bc6 |
(c->secure_bits & 1<
|
|
|
a19bc6 |
(c->secure_bits & 1<
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- if (c->capability_bounding_set_drop) {
|
|
|
a19bc6 |
+ if (c->capability_bounding_set != CAP_ALL) {
|
|
|
a19bc6 |
unsigned long l;
|
|
|
a19bc6 |
fprintf(f, "%sCapabilityBoundingSet:", prefix);
|
|
|
a19bc6 |
|
|
|
a19bc6 |
for (l = 0; l <= cap_last_cap(); l++)
|
|
|
a19bc6 |
- if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l)))
|
|
|
a19bc6 |
+ if (c->capability_bounding_set & (UINT64_C(1) << l))
|
|
|
a19bc6 |
fprintf(f, " %s", strna(capability_to_name(l)));
|
|
|
a19bc6 |
|
|
|
a19bc6 |
fputs("\n", f);
|
|
|
a19bc6 |
diff --git a/src/core/execute.h b/src/core/execute.h
|
|
|
a19bc6 |
index cadd0e6..40f7b79 100644
|
|
|
a19bc6 |
--- a/src/core/execute.h
|
|
|
a19bc6 |
+++ b/src/core/execute.h
|
|
|
a19bc6 |
@@ -150,7 +150,7 @@ struct ExecContext {
|
|
|
a19bc6 |
char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
|
|
|
a19bc6 |
unsigned long mount_flags;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- uint64_t capability_bounding_set_drop;
|
|
|
a19bc6 |
+ uint64_t capability_bounding_set;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
cap_t capabilities;
|
|
|
a19bc6 |
int secure_bits;
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
index b50fe45..e4ce292 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
+++ b/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
@@ -47,7 +47,7 @@ $1.SyslogLevel, config_parse_log_level, 0,
|
|
|
a19bc6 |
$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix)
|
|
|
a19bc6 |
$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context)
|
|
|
a19bc6 |
$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context)
|
|
|
a19bc6 |
-$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop)
|
|
|
a19bc6 |
+$1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set)
|
|
|
a19bc6 |
$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec)
|
|
|
a19bc6 |
$1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context)
|
|
|
a19bc6 |
m4_ifdef(`HAVE_SECCOMP',
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
|
|
a19bc6 |
index ab3b0c2..dbaaf2f 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment.c
|
|
|
a19bc6 |
+++ b/src/core/load-fragment.c
|
|
|
a19bc6 |
@@ -1015,7 +1015,7 @@ int config_parse_exec_secure_bits(const char *unit,
|
|
|
a19bc6 |
return 0;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
-int config_parse_bounding_set(
|
|
|
a19bc6 |
+int config_parse_capability_set(
|
|
|
a19bc6 |
const char *unit,
|
|
|
a19bc6 |
const char *filename,
|
|
|
a19bc6 |
unsigned line,
|
|
|
a19bc6 |
@@ -1027,8 +1027,8 @@ int config_parse_bounding_set(
|
|
|
a19bc6 |
void *data,
|
|
|
a19bc6 |
void *userdata) {
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- uint64_t *capability_bounding_set_drop = data;
|
|
|
a19bc6 |
- uint64_t capability_bounding_set, sum = 0;
|
|
|
a19bc6 |
+ uint64_t *capability_set = data;
|
|
|
a19bc6 |
+ uint64_t sum = 0, initial = 0;
|
|
|
a19bc6 |
bool invert = false;
|
|
|
a19bc6 |
const char *p;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -1042,10 +1042,8 @@ int config_parse_bounding_set(
|
|
|
a19bc6 |
rvalue++;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- /* Note that we store this inverted internally, since the
|
|
|
a19bc6 |
- * kernel wants it like this. But we actually expose it
|
|
|
a19bc6 |
- * non-inverted everywhere to have a fully normalized
|
|
|
a19bc6 |
- * interface. */
|
|
|
a19bc6 |
+ if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
|
|
|
a19bc6 |
+ initial = CAP_ALL; /* initialized to all bits on */
|
|
|
a19bc6 |
|
|
|
a19bc6 |
p = rvalue;
|
|
|
a19bc6 |
for (;;) {
|
|
|
a19bc6 |
@@ -1071,11 +1069,14 @@ int config_parse_bounding_set(
|
|
|
a19bc6 |
sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- capability_bounding_set = invert ? ~sum : sum;
|
|
|
a19bc6 |
- if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0)
|
|
|
a19bc6 |
- *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
|
|
|
a19bc6 |
+ sum = invert ? ~sum : sum;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (sum == 0 || *capability_set == initial)
|
|
|
a19bc6 |
+ /* "" or uninitialized data -> replace */
|
|
|
a19bc6 |
+ *capability_set = sum;
|
|
|
a19bc6 |
else
|
|
|
a19bc6 |
- *capability_bounding_set_drop = ~capability_bounding_set;
|
|
|
a19bc6 |
+ /* previous data -> merge */
|
|
|
a19bc6 |
+ *capability_set |= sum;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
return 0;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
@@ -4050,7 +4051,7 @@ void unit_dump_config_items(FILE *f) {
|
|
|
a19bc6 |
{ config_parse_log_level, "LEVEL" },
|
|
|
a19bc6 |
{ config_parse_exec_capabilities, "CAPABILITIES" },
|
|
|
a19bc6 |
{ config_parse_exec_secure_bits, "SECUREBITS" },
|
|
|
a19bc6 |
- { config_parse_bounding_set, "BOUNDINGSET" },
|
|
|
a19bc6 |
+ { config_parse_capability_set, "BOUNDINGSET" },
|
|
|
a19bc6 |
{ config_parse_limit, "LIMIT" },
|
|
|
a19bc6 |
{ config_parse_unit_deps, "UNIT [...]" },
|
|
|
a19bc6 |
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
|
|
|
a19bc6 |
index 9dd7d1b..2059353 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment.h
|
|
|
a19bc6 |
+++ b/src/core/load-fragment.h
|
|
|
a19bc6 |
@@ -54,7 +54,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit, const char *filename, uns
|
|
|
a19bc6 |
int config_parse_exec_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_exec_capabilities(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
-int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
+int config_parse_capability_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
diff --git a/src/core/main.c b/src/core/main.c
|
|
|
a19bc6 |
index a0df1e5..cba992c 100644
|
|
|
a19bc6 |
--- a/src/core/main.c
|
|
|
a19bc6 |
+++ b/src/core/main.c
|
|
|
a19bc6 |
@@ -108,7 +108,7 @@ static usec_t arg_runtime_watchdog = 0;
|
|
|
a19bc6 |
static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
|
|
|
a19bc6 |
static char **arg_default_environment = NULL;
|
|
|
a19bc6 |
static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
|
|
|
a19bc6 |
-static uint64_t arg_capability_bounding_set_drop = 0;
|
|
|
a19bc6 |
+static uint64_t arg_capability_bounding_set = CAP_ALL;
|
|
|
a19bc6 |
static nsec_t arg_timer_slack_nsec = NSEC_INFINITY;
|
|
|
a19bc6 |
static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
|
|
|
a19bc6 |
static Set* arg_syscall_archs = NULL;
|
|
|
a19bc6 |
@@ -642,7 +642,7 @@ static int parse_config_file(void) {
|
|
|
a19bc6 |
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
|
|
|
a19bc6 |
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
|
|
|
a19bc6 |
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
|
|
|
a19bc6 |
- { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop },
|
|
|
a19bc6 |
+ { "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set },
|
|
|
a19bc6 |
#ifdef HAVE_SECCOMP
|
|
|
a19bc6 |
{ "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs },
|
|
|
a19bc6 |
#endif
|
|
|
a19bc6 |
@@ -1622,14 +1622,14 @@ int main(int argc, char *argv[]) {
|
|
|
a19bc6 |
if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
|
|
|
a19bc6 |
log_error_errno(errno, "Failed to adjust timer slack: %m");
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- if (arg_capability_bounding_set_drop) {
|
|
|
a19bc6 |
- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
|
|
|
a19bc6 |
+ if (!cap_test_all(arg_capability_bounding_set)) {
|
|
|
a19bc6 |
+ r = capability_bounding_set_drop_usermode(arg_capability_bounding_set);
|
|
|
a19bc6 |
if (r < 0) {
|
|
|
a19bc6 |
log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
|
|
|
a19bc6 |
error_message = "Failed to drop capability bounding set of usermode helpers";
|
|
|
a19bc6 |
goto finish;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
- r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
|
|
|
a19bc6 |
+ r = capability_bounding_set_drop(arg_capability_bounding_set, true);
|
|
|
a19bc6 |
if (r < 0) {
|
|
|
a19bc6 |
log_emergency_errno(r, "Failed to drop capability bounding set: %m");
|
|
|
a19bc6 |
error_message = "Failed to drop capability bounding set";
|
|
|
a19bc6 |
diff --git a/src/core/unit.c b/src/core/unit.c
|
|
|
a19bc6 |
index 4eb0d78..103f920 100644
|
|
|
a19bc6 |
--- a/src/core/unit.c
|
|
|
a19bc6 |
+++ b/src/core/unit.c
|
|
|
a19bc6 |
@@ -3213,7 +3213,7 @@ int unit_patch_contexts(Unit *u) {
|
|
|
a19bc6 |
ec->no_new_privileges = true;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
if (ec->private_devices)
|
|
|
a19bc6 |
- ec->capability_bounding_set_drop |= (uint64_t) 1ULL << (uint64_t) CAP_MKNOD;
|
|
|
a19bc6 |
+ ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_MKNOD);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
cc = unit_get_cgroup_context(u);
|
|
|
a19bc6 |
diff --git a/src/import/import-common.c b/src/import/import-common.c
|
|
|
a19bc6 |
index f10a453..243e657 100644
|
|
|
a19bc6 |
--- a/src/import/import-common.c
|
|
|
a19bc6 |
+++ b/src/import/import-common.c
|
|
|
a19bc6 |
@@ -526,7 +526,7 @@ int import_fork_tar(const char *path, pid_t *ret) {
|
|
|
a19bc6 |
if (unshare(CLONE_NEWNET) < 0)
|
|
|
a19bc6 |
log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- r = capability_bounding_set_drop(~retain, true);
|
|
|
a19bc6 |
+ r = capability_bounding_set_drop(retain, true);
|
|
|
a19bc6 |
if (r < 0)
|
|
|
a19bc6 |
log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
|
|
|
a19bc6 |
index a37b640..d0003d3 100644
|
|
|
a19bc6 |
--- a/src/nspawn/nspawn.c
|
|
|
a19bc6 |
+++ b/src/nspawn/nspawn.c
|
|
|
a19bc6 |
@@ -1863,7 +1863,7 @@ static int setup_journal(const char *directory) {
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
static int drop_capabilities(void) {
|
|
|
a19bc6 |
- return capability_bounding_set_drop(~arg_retain, false);
|
|
|
a19bc6 |
+ return capability_bounding_set_drop(arg_retain, false);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
static int register_machine(pid_t pid, int local_ifindex) {
|
|
|
a19bc6 |
diff --git a/src/shared/capability.c b/src/shared/capability.c
|
|
|
a19bc6 |
index 2b963fd..3ed31df 100644
|
|
|
a19bc6 |
--- a/src/shared/capability.c
|
|
|
a19bc6 |
+++ b/src/shared/capability.c
|
|
|
a19bc6 |
@@ -98,7 +98,7 @@ unsigned long cap_last_cap(void) {
|
|
|
a19bc6 |
return p;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
-int capability_bounding_set_drop(uint64_t drop, bool right_now) {
|
|
|
a19bc6 |
+int capability_bounding_set_drop(uint64_t keep, bool right_now) {
|
|
|
a19bc6 |
_cleanup_cap_free_ cap_t after_cap = NULL;
|
|
|
a19bc6 |
cap_flag_value_t fv;
|
|
|
a19bc6 |
unsigned long i;
|
|
|
a19bc6 |
@@ -139,7 +139,7 @@ int capability_bounding_set_drop(uint64_t drop, bool right_now) {
|
|
|
a19bc6 |
|
|
|
a19bc6 |
for (i = 0; i <= cap_last_cap(); i++) {
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
|
|
|
a19bc6 |
+ if (!(keep & (UINT64_C(1) << i))) {
|
|
|
a19bc6 |
cap_value_t v;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
/* Drop it from the bounding set */
|
|
|
a19bc6 |
@@ -178,7 +178,7 @@ finish:
|
|
|
a19bc6 |
return r;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
-static int drop_from_file(const char *fn, uint64_t drop) {
|
|
|
a19bc6 |
+static int drop_from_file(const char *fn, uint64_t keep) {
|
|
|
a19bc6 |
int r, k;
|
|
|
a19bc6 |
uint32_t hi, lo;
|
|
|
a19bc6 |
uint64_t current, after;
|
|
|
a19bc6 |
@@ -198,7 +198,7 @@ static int drop_from_file(const char *fn, uint64_t drop) {
|
|
|
a19bc6 |
return -EIO;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
current = (uint64_t) lo | ((uint64_t) hi << 32ULL);
|
|
|
a19bc6 |
- after = current & ~drop;
|
|
|
a19bc6 |
+ after = current & keep;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
if (current == after)
|
|
|
a19bc6 |
return 0;
|
|
|
a19bc6 |
@@ -215,14 +215,14 @@ static int drop_from_file(const char *fn, uint64_t drop) {
|
|
|
a19bc6 |
return r;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
-int capability_bounding_set_drop_usermode(uint64_t drop) {
|
|
|
a19bc6 |
+int capability_bounding_set_drop_usermode(uint64_t keep) {
|
|
|
a19bc6 |
int r;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop);
|
|
|
a19bc6 |
+ r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep);
|
|
|
a19bc6 |
if (r < 0)
|
|
|
a19bc6 |
return r;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop);
|
|
|
a19bc6 |
+ r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep);
|
|
|
a19bc6 |
if (r < 0)
|
|
|
a19bc6 |
return r;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -259,7 +259,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
|
|
|
a19bc6 |
return log_error_errno(errno, "Failed to disable keep capabilities flag: %m");
|
|
|
a19bc6 |
|
|
|
a19bc6 |
/* Drop all caps from the bounding set, except the ones we want */
|
|
|
a19bc6 |
- r = capability_bounding_set_drop(~keep_capabilities, true);
|
|
|
a19bc6 |
+ r = capability_bounding_set_drop(keep_capabilities, true);
|
|
|
a19bc6 |
if (r < 0)
|
|
|
a19bc6 |
return log_error_errno(r, "Failed to drop capabilities: %m");
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/src/shared/capability.h b/src/shared/capability.h
|
|
|
a19bc6 |
index 6f2f6f9..04cd6e5 100644
|
|
|
a19bc6 |
--- a/src/shared/capability.h
|
|
|
a19bc6 |
+++ b/src/shared/capability.h
|
|
|
a19bc6 |
@@ -27,10 +27,12 @@
|
|
|
a19bc6 |
|
|
|
a19bc6 |
#include "util.h"
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+#define CAP_ALL (uint64_t) -1
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
unsigned long cap_last_cap(void);
|
|
|
a19bc6 |
int have_effective_cap(int value);
|
|
|
a19bc6 |
-int capability_bounding_set_drop(uint64_t drop, bool right_now);
|
|
|
a19bc6 |
-int capability_bounding_set_drop_usermode(uint64_t drop);
|
|
|
a19bc6 |
+int capability_bounding_set_drop(uint64_t keep, bool right_now);
|
|
|
a19bc6 |
+int capability_bounding_set_drop_usermode(uint64_t keep);
|
|
|
a19bc6 |
|
|
|
a19bc6 |
int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites);
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -44,3 +46,9 @@ static inline void cap_free_charpp(char **p) {
|
|
|
a19bc6 |
cap_free(*p);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
#define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp)
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+static inline bool cap_test_all(uint64_t caps) {
|
|
|
a19bc6 |
+ uint64_t m;
|
|
|
a19bc6 |
+ m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1;
|
|
|
a19bc6 |
+ return (caps & m) == m;
|
|
|
a19bc6 |
+}
|
|
|
a19bc6 |
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
|
|
|
a19bc6 |
index 0f00a8f..38ecfe9 100644
|
|
|
a19bc6 |
--- a/src/test/test-unit-file.c
|
|
|
a19bc6 |
+++ b/src/test/test-unit-file.c
|
|
|
a19bc6 |
@@ -550,6 +550,53 @@ static uint64_t make_cap(int cap) {
|
|
|
a19bc6 |
return ((uint64_t) 1ULL << (uint64_t) cap);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+static void test_config_parse_capability_set(void) {
|
|
|
a19bc6 |
+ /* int config_parse_capability_set(
|
|
|
a19bc6 |
+ const char *unit,
|
|
|
a19bc6 |
+ const char *filename,
|
|
|
a19bc6 |
+ unsigned line,
|
|
|
a19bc6 |
+ const char *section,
|
|
|
a19bc6 |
+ unsigned section_line,
|
|
|
a19bc6 |
+ const char *lvalue,
|
|
|
a19bc6 |
+ int ltype,
|
|
|
a19bc6 |
+ const char *rvalue,
|
|
|
a19bc6 |
+ void *data,
|
|
|
a19bc6 |
+ void *userdata) */
|
|
|
a19bc6 |
+ int r;
|
|
|
a19bc6 |
+ uint64_t capability_bounding_set = 0;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
+ "CapabilityBoundingSet", 0, "CAP_NET_RAW",
|
|
|
a19bc6 |
+ &capability_bounding_set, NULL);
|
|
|
a19bc6 |
+ assert_se(r >= 0);
|
|
|
a19bc6 |
+ assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
+ "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
|
|
|
a19bc6 |
+ &capability_bounding_set, NULL);
|
|
|
a19bc6 |
+ assert_se(r >= 0);
|
|
|
a19bc6 |
+ assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
+ "CapabilityBoundingSet", 0, "",
|
|
|
a19bc6 |
+ &capability_bounding_set, NULL);
|
|
|
a19bc6 |
+ assert_se(r >= 0);
|
|
|
a19bc6 |
+ assert_se(capability_bounding_set == UINT64_C(0));
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
+ "CapabilityBoundingSet", 0, "~",
|
|
|
a19bc6 |
+ &capability_bounding_set, NULL);
|
|
|
a19bc6 |
+ assert_se(r >= 0);
|
|
|
a19bc6 |
+ assert_se(cap_test_all(capability_bounding_set));
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ capability_bounding_set = 0;
|
|
|
a19bc6 |
+ r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
+ "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
|
|
|
a19bc6 |
+ &capability_bounding_set, NULL);
|
|
|
a19bc6 |
+ assert_se(r >= 0);
|
|
|
a19bc6 |
+ assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
|
|
|
a19bc6 |
+}
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
static void test_config_parse_rlimit(void) {
|
|
|
a19bc6 |
struct rlimit * rl[_RLIMIT_MAX] = {};
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -665,46 +712,6 @@ static void test_config_parse_rlimit(void) {
|
|
|
a19bc6 |
free(rl[RLIMIT_RTTIME]);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
-static void test_config_parse_bounding_set(void) {
|
|
|
a19bc6 |
- /* int config_parse_bounding_set(
|
|
|
a19bc6 |
- const char *unit,
|
|
|
a19bc6 |
- const char *filename,
|
|
|
a19bc6 |
- unsigned line,
|
|
|
a19bc6 |
- const char *section,
|
|
|
a19bc6 |
- unsigned section_line,
|
|
|
a19bc6 |
- const char *lvalue,
|
|
|
a19bc6 |
- int ltype,
|
|
|
a19bc6 |
- const char *rvalue,
|
|
|
a19bc6 |
- void *data,
|
|
|
a19bc6 |
- void *userdata) */
|
|
|
a19bc6 |
- int r;
|
|
|
a19bc6 |
- uint64_t capability_bounding_set_drop = 0;
|
|
|
a19bc6 |
-
|
|
|
a19bc6 |
- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
- "CapabilityBoundingSet", 0, "CAP_NET_RAW",
|
|
|
a19bc6 |
- &capability_bounding_set_drop, NULL);
|
|
|
a19bc6 |
- assert_se(r >= 0);
|
|
|
a19bc6 |
- assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW));
|
|
|
a19bc6 |
-
|
|
|
a19bc6 |
- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
- "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
|
|
|
a19bc6 |
- &capability_bounding_set_drop, NULL);
|
|
|
a19bc6 |
- assert_se(r >= 0);
|
|
|
a19bc6 |
- assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
|
|
|
a19bc6 |
-
|
|
|
a19bc6 |
- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
- "CapabilityBoundingSet", 0, "",
|
|
|
a19bc6 |
- &capability_bounding_set_drop, NULL);
|
|
|
a19bc6 |
- assert_se(r >= 0);
|
|
|
a19bc6 |
- assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL));
|
|
|
a19bc6 |
-
|
|
|
a19bc6 |
- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
|
|
|
a19bc6 |
- "CapabilityBoundingSet", 0, "~",
|
|
|
a19bc6 |
- &capability_bounding_set_drop, NULL);
|
|
|
a19bc6 |
- assert_se(r >= 0);
|
|
|
a19bc6 |
- assert_se(capability_bounding_set_drop == (uint64_t) 0ULL);
|
|
|
a19bc6 |
-}
|
|
|
a19bc6 |
-
|
|
|
a19bc6 |
int main(int argc, char *argv[]) {
|
|
|
a19bc6 |
int r;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -713,8 +720,8 @@ int main(int argc, char *argv[]) {
|
|
|
a19bc6 |
|
|
|
a19bc6 |
r = test_unit_file_get_set();
|
|
|
a19bc6 |
test_config_parse_exec();
|
|
|
a19bc6 |
+ test_config_parse_capability_set();
|
|
|
a19bc6 |
test_config_parse_rlimit();
|
|
|
a19bc6 |
- test_config_parse_bounding_set();
|
|
|
a19bc6 |
test_load_env_file_1();
|
|
|
a19bc6 |
test_load_env_file_2();
|
|
|
a19bc6 |
test_load_env_file_3();
|