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 &&