systemd-nspawn: Allow setting ambient capability set

The old code was only able to pass the value 0 for the inheritable
and ambient capability set when a non-root user was specified.

However, sometimes it is useful to run a program in its own container
with a user specification and some capabilities set. This is needed
when the capabilities cannot be provided by file capabilities (because
the file system is mounted with MS_NOSUID for additional security).

This commit introduces the option --ambient-capability and the config
file option AmbientCapability=. Both are used in a similar way to the
existing Capability= setting. It changes the inheritable and ambient
set (which is 0 by default). The code also checks that the settings
for the bounding set (as defined by Capability= and DropCapability=)
and the setting for the ambient set (as defined by AmbientCapability=)
are compatible. Otherwise, the operation would fail in any way.

Due to the current use of -1 to indicate no support for ambient
capability set the special value "all" cannot be supported.

Also, the setting of ambient capability is restricted to running a
single program in the container payload.
This commit is contained in:
Torsten Hilbrich
2020-12-07 19:56:59 +01:00
committed by Zbigniew Jędrzejewski-Szmek
parent bf20d93750
commit 88fc9c9bad
5 changed files with 100 additions and 9 deletions
+1
View File
@@ -25,6 +25,7 @@ Exec.Parameters, config_parse_strv, 0, of
Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment)
Exec.User, config_parse_string, 0, offsetof(Settings, user)
Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability)
Exec.AmbientCapability, config_parse_capability, 0, offsetof(Settings, ambient_capability)
Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability)
Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal)
Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality)
+1
View File
@@ -157,6 +157,7 @@ typedef struct Settings {
char *user;
uint64_t capability;
uint64_t drop_capability;
uint64_t ambient_capability;
int kill_signal;
unsigned long personality;
sd_id128_t machine_id;
+39 -6
View File
@@ -165,6 +165,7 @@ static uint64_t arg_caps_retain =
(1ULL << CAP_SYS_PTRACE) |
(1ULL << CAP_SYS_RESOURCE) |
(1ULL << CAP_SYS_TTY_CONFIG);
static uint64_t arg_caps_ambient = 0;
static CapabilityQuintet arg_full_capabilities = CAPABILITY_QUINTET_NULL;
static CustomMount *arg_custom_mounts = NULL;
static size_t arg_n_custom_mounts = 0;
@@ -379,6 +380,9 @@ static int help(void) {
" --capability=CAP In addition to the default, retain specified\n"
" capability\n"
" --drop-capability=CAP Drop the specified capability from the default set\n"
" --ambient-capability=CAP\n"
" Sets the specified capability for the started\n"
" process. Not useful if booting a machine.\n"
" --no-new-privileges Set PR_SET_NO_NEW_PRIVS flag for container payload\n"
" --system-call-filter=LIST|~LIST\n"
" Permit/prohibit specific system calls\n"
@@ -648,6 +652,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_UUID,
ARG_READ_ONLY,
ARG_CAPABILITY,
ARG_AMBIENT_CAPABILITY,
ARG_DROP_CAPABILITY,
ARG_LINK_JOURNAL,
ARG_BIND,
@@ -709,6 +714,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "uuid", required_argument, NULL, ARG_UUID },
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
{ "capability", required_argument, NULL, ARG_CAPABILITY },
{ "ambient-capability", required_argument, NULL, ARG_AMBIENT_CAPABILITY },
{ "drop-capability", required_argument, NULL, ARG_DROP_CAPABILITY },
{ "no-new-privileges", required_argument, NULL, ARG_NO_NEW_PRIVILEGES },
{ "link-journal", required_argument, NULL, ARG_LINK_JOURNAL },
@@ -1018,6 +1024,15 @@ static int parse_argv(int argc, char *argv[]) {
arg_settings_mask |= SETTING_READ_ONLY;
break;
case ARG_AMBIENT_CAPABILITY: {
uint64_t m;
r = parse_capability_spec(optarg, &m);
if (r <= 0)
return r;
arg_caps_ambient |= m;
arg_settings_mask |= SETTING_CAPABILITY;
break;
}
case ARG_CAPABILITY:
case ARG_DROP_CAPABILITY: {
uint64_t m;
@@ -1760,6 +1775,17 @@ static int verify_arguments(void) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--port= is not supported, compiled without libiptc support.");
#endif
if (arg_caps_ambient) {
if (arg_caps_ambient == (uint64_t)-1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= does not support the value all.");
if ((arg_caps_ambient & arg_caps_retain) != arg_caps_ambient)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= setting is not fully covered by Capability= setting.");
if (arg_start_mode == START_BOOT)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= setting is not useful for boot mode.");
}
r = custom_mount_check_all();
if (r < 0)
return r;
@@ -2622,13 +2648,13 @@ static int drop_capabilities(uid_t uid) {
q.effective = uid == 0 ? q.bounding : 0;
if (q.inheritable == (uint64_t) -1)
q.inheritable = uid == 0 ? q.bounding : 0;
q.inheritable = uid == 0 ? q.bounding : arg_caps_ambient;
if (q.permitted == (uint64_t) -1)
q.permitted = uid == 0 ? q.bounding : 0;
q.permitted = uid == 0 ? q.bounding : arg_caps_ambient;
if (q.ambient == (uint64_t) -1 && ambient_capabilities_supported())
q.ambient = 0;
q.ambient = arg_caps_ambient;
if (capability_quintet_mangle(&q))
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Cannot set capabilities that are not in the current bounding set.");
@@ -2637,9 +2663,9 @@ static int drop_capabilities(uid_t uid) {
q = (CapabilityQuintet) {
.bounding = arg_caps_retain,
.effective = uid == 0 ? arg_caps_retain : 0,
.inheritable = uid == 0 ? arg_caps_retain : 0,
.permitted = uid == 0 ? arg_caps_retain : 0,
.ambient = ambient_capabilities_supported() ? 0 : (uint64_t) -1,
.inheritable = uid == 0 ? arg_caps_retain : arg_caps_ambient,
.permitted = uid == 0 ? arg_caps_retain : arg_caps_ambient,
.ambient = ambient_capabilities_supported() ? arg_caps_ambient : (uint64_t) -1,
};
/* If we're not using OCI, proceed with mangled capabilities (so we don't error out)
@@ -4070,6 +4096,7 @@ static int merge_settings(Settings *settings, const char *path) {
if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
uint64_t plus, minus;
uint64_t network_minus = 0;
uint64_t ambient;
/* Note that we copy both the simple plus/minus caps here, and the full quintet from the
* Settings structure */
@@ -4101,6 +4128,12 @@ static int merge_settings(Settings *settings, const char *path) {
else
arg_full_capabilities = settings->full_capabilities;
}
ambient = settings->ambient_capability;
if (!arg_settings_trusted && ambient != 0)
log_warning("Ignoring AmbientCapability= setting, file %s is not trusted.", path);
else
arg_caps_ambient |= ambient;
}
if ((arg_settings_mask & SETTING_KILL_SIGNAL) == 0 &&