diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 588924ee61..a720d401e7 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -1002,7 +1002,11 @@ If the special value all is passed, all capabilities are retained. If the special value of help is passed, the program will print known - capability names and exit. + capability names and exit. + + This option sets the bounding set of capabilities which + also limits the ambient capabilities as given with the + . @@ -1014,7 +1018,32 @@ above). If the special value of help is passed, the program will print known - capability names and exit. + capability names and exit. + + This option sets the bounding set of capabilities which + also limits the ambient capabilities as given with the + . + + + + + + Specify one or more additional capabilities to + pass in the inheritable and ambient set to the program started + within the container. The value all is not + supported for this setting. + + All capabilities specified here must be in the set + allowed with the and + options. Otherwise, an + error message will be shown. + + This option cannot be combined with the boot mode of the + container (as requested via ). + + If the special value of help is + passed, the program will print known capability names and + exit. diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 0125b71e34..6ad0e1a101 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -190,7 +190,34 @@ /run/system/nspawn/ (see above). On the other hand, DropCapability= takes effect in all cases. If the special value all is passed, all - capabilities are retained (or dropped). + capabilities are retained (or dropped). + These settings change the bounding set of capabilities which + also limits the ambient capabilities as given with the + AmbientCapability=. + + + + AmbientCapability= + Takes a space-separated list of Linux process + capabilities (see + capabilities7 + for details). The AmbientCapability= setting + specifies capability which will be passed to to started program + in the inheritable and ambient capability sets. This will grant + these capabilities to this process. This setting correspond to + the command line switch. + + + The value all is not supported for this + setting. + + The setting of AmbientCapability= must + be covered by the bounding set settings which were established by + Capability= and DropCapability=. + + + Note that AmbientCapability= is a privileged + setting (see above). diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 79304d21ab..7751c3c062 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -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) diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 4a83e55202..66ee0cc979 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -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; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ad2f572869..5e3d11be36 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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 &&