]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemd-nspawn: Allow setting ambient capability set
authorTorsten Hilbrich <torsten.hilbrich@secunet.com>
Fri, 4 Dec 2020 10:27:12 +0000 (11:27 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 7 Dec 2020 18:56:59 +0000 (19:56 +0100)
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.

man/systemd-nspawn.xml
man/systemd.nspawn.xml
src/nspawn/nspawn-gperf.gperf
src/nspawn/nspawn-settings.h
src/nspawn/nspawn.c

index 588924ee61b595bc692241c809809907b0a1d24f..a720d401e78bfaddc3939dc7f8cf6600d0965699 100644 (file)
         If the special value <literal>all</literal> is passed, all capabilities are retained.</para>
 
         <para>If the special value of <literal>help</literal> is passed, the program will print known
-        capability names and exit.</para></listitem>
+        capability names and exit.</para>
+
+        <para>This option sets the bounding set of capabilities which
+        also limits the ambient capabilities as given with the
+        <option>--ambient-capability=</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         above).</para>
 
         <para>If the special value of <literal>help</literal> is passed, the program will print known
-        capability names and exit.</para></listitem>
+        capability names and exit.</para>
+
+        <para>This option sets the bounding set of capabilities which
+        also limits the ambient capabilities as given with the
+        <option>--ambient-capability=</option>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--ambient-capability=</option></term>
+
+        <listitem><para>Specify one or more additional capabilities to
+        pass in the inheritable and ambient set to the program started
+        within the container. The value <literal>all</literal> is not
+        supported for this setting.</para>
+
+        <para>All capabilities specified here must be in the set
+        allowed with the <option>--capability=</option> and
+        <option>--drop-capability=</option> options. Otherwise, an
+        error message will be shown.</para>
+
+        <para>This option cannot be combined with the boot mode of the
+        container (as requested via <option>--boot</option>).</para>
+
+        <para>If the special value of <literal>help</literal> is
+        passed, the program will print known capability names and
+        exit.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 0125b71e349589d33eb4641a2c0dc525a219e4b4..6ad0e1a1018501cb595234214cefff67d68b2706 100644 (file)
         <filename>/run/system/nspawn/</filename> (see above). On the
         other hand, <varname>DropCapability=</varname> takes effect in
         all cases. If the special value <literal>all</literal> is passed, all
-        capabilities are retained (or dropped).</para></listitem>
+        capabilities are retained (or dropped).</para>
+        <para>These settings change the bounding set of capabilities which
+        also limits the ambient capabilities as given with the
+        <varname>AmbientCapability=</varname>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>AmbientCapability=</varname></term>
+        <listitem><para>Takes a space-separated list of Linux process
+        capabilities (see
+        <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+        for details). The <varname>AmbientCapability=</varname> 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 <option>--ambient-capability=</option> command line switch.
+        </para>
+
+        <para>The value <literal>all</literal> is not supported for this
+        setting.</para>
+
+        <para>The setting of <varname>AmbientCapability=</varname> must
+        be covered by the bounding set settings which were established by
+        <varname>Capability=</varname> and <varname>DropCapability=</varname>.
+        </para>
+
+        <para>Note that <varname>AmbientCapability=</varname> is a privileged
+        setting (see above).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 79304d21aba2760b7ed2f6762c559b4004887f44..7751c3c062a7f7a34eb82a714c44a3502bfe8971 100644 (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)
index 4a83e552026a1e455aeb58b3b88bb2c3b8023e5c..66ee0cc979d0ded219b806e502dcf9f0816cf36c 100644 (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;
index ad2f572869cc3553f14ed7b56a9febc4dd3e0cb9..5e3d11be36cbc70433b19d826ebec6cbab8c5b27 100644 (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 &&