core: add PrivateUsers=managed
This commit is contained in:
+25
-17
@@ -2202,16 +2202,17 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
<varlistentry>
|
||||
<term><varname>PrivateUsers=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument or one of <literal>self</literal>, <literal>identity</literal>,
|
||||
or <literal>full</literal>. Defaults to false. If enabled, sets up a new user namespace for the
|
||||
executed processes and configures a user and group mapping. If set to a true value or
|
||||
<literal>self</literal>, a minimal user and group mapping is configured that maps the
|
||||
<literal>root</literal> user and group as well as the unit's own user and group to themselves and
|
||||
everything else to the <literal>nobody</literal> user and group. This is useful to securely detach
|
||||
the user and group databases used by the unit from the rest of the system, and thus to create an
|
||||
effective sandbox environment. All files, directories, processes, IPC objects and other resources
|
||||
owned by users/groups not equaling <literal>root</literal> or the unit's own will stay visible from
|
||||
within the unit but appear owned by the <literal>nobody</literal> user and group. </para>
|
||||
<listitem><para>Takes a boolean argument or one of <literal>self</literal>,
|
||||
<literal>identity</literal>, <literal>full</literal> or <literal>managed</literal>. Defaults to
|
||||
false. If enabled, sets up a new user namespace for the executed processes and configures a user and
|
||||
group mapping. If set to a true value or <literal>self</literal>, a minimal user and group mapping is
|
||||
configured that maps the <literal>root</literal> user and group as well as the unit's own user and
|
||||
group to themselves and everything else to the <literal>nobody</literal> user and group. This is
|
||||
useful to securely detach the user and group databases used by the unit from the rest of the system,
|
||||
and thus to create an effective sandbox environment. All files, directories, processes, IPC objects
|
||||
and other resources owned by users/groups not equaling <literal>root</literal> or the unit's own will
|
||||
stay visible from within the unit but appear owned by the <literal>nobody</literal> user and
|
||||
group. </para>
|
||||
|
||||
<para>If the parameter is <literal>identity</literal>, user namespacing is set up with an identity
|
||||
mapping for the first 65536 UIDs/GIDs. Any UIDs/GIDs above 65536 will be mapped to the
|
||||
@@ -2224,14 +2225,21 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
to call <function>setgroups()</function> system calls (by setting
|
||||
<filename>/proc/<replaceable>pid</replaceable>/setgroups</filename> to <literal>allow</literal>).
|
||||
Similar to <literal>identity</literal>, this does not provide UID/GID isolation, but it does provide
|
||||
process capability isolation.</para>
|
||||
process capability isolation. If this mode is enabled, all unit processes are run without privileges
|
||||
in the host user namespace (regardless of whether the unit's own user/group is
|
||||
<literal>root</literal> or not). Specifically this means that the process will have zero process
|
||||
capabilities on the host's user namespace, but full capabilities within the service's user
|
||||
namespace. Settings such as <varname>CapabilityBoundingSet=</varname> will affect only the latter,
|
||||
and there's no way to acquire additional capabilities in the host's user namespace.</para>
|
||||
|
||||
<para>If this mode is enabled, all unit processes are run without privileges in the host user
|
||||
namespace (regardless of whether the unit's own user/group is <literal>root</literal> or not). Specifically
|
||||
this means that the process will have zero process capabilities on the host's user namespace, but
|
||||
full capabilities within the service's user namespace. Settings such as
|
||||
<varname>CapabilityBoundingSet=</varname> will affect only the latter, and there's no way to acquire
|
||||
additional capabilities in the host's user namespace.</para>
|
||||
<para>If the paramater is <literal>managed</literal> a transient, dynamically allocated range of
|
||||
65536 UIDs/GIDs is allocated for the unit, and a UID/GID mapping is assigned to the unit's process
|
||||
so the UID/GID 0 from inside the unit maps to the first UID/GID of the allocated mapping. Note that
|
||||
in this mode the UID/GID the service process will run as is different depending if looking from the
|
||||
host side (where it will be a high, dynamically assigned UID) or from inside the unit (where it will
|
||||
be 0). Also note that this mode will enable file system UID mapping for the file systems this service
|
||||
accesses, mapping the "foreign" UID range on disk to the selected dynamic UID range at
|
||||
runtime.</para>
|
||||
|
||||
<para>When this setting is set up by a per-user instance of the service manager, the mapping of the
|
||||
<literal>root</literal> user and group to itself is omitted (unless the user manager is root).
|
||||
|
||||
+24
-4
@@ -57,6 +57,7 @@
|
||||
#include "mountpoint-util.h"
|
||||
#include "namespace-util.h"
|
||||
#include "nsflags.h"
|
||||
#include "nsresource.h"
|
||||
#include "open-file.h"
|
||||
#include "osc-context.h"
|
||||
#include "pam-util.h"
|
||||
@@ -2396,10 +2397,10 @@ static int setup_private_users_child(int unshare_ready_fd, const char *uid_map,
|
||||
|
||||
static int setup_private_users(
|
||||
PrivateUsers private_users,
|
||||
uid_t ouid,
|
||||
gid_t ogid,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
uid_t ouid, /* service manager uid */
|
||||
gid_t ogid, /* service manager gid */
|
||||
uid_t uid, /* unit uid */
|
||||
gid_t gid, /* unit gid */
|
||||
bool allow_setgroups) {
|
||||
|
||||
_cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
|
||||
@@ -2425,6 +2426,25 @@ static int setup_private_users(
|
||||
case PRIVATE_USERS_NO:
|
||||
return 0; /* Early exit */
|
||||
|
||||
case PRIVATE_USERS_MANAGED: {
|
||||
if (uid != 0 || gid != 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EPERM), "When allocating dynamic user namespace range, target UID/GID must be root, refusing.");
|
||||
|
||||
_cleanup_close_ int userns_fd = nsresource_allocate_userns(/* name= */ NULL, NSRESOURCE_UIDS_64K);
|
||||
if (userns_fd < 0)
|
||||
return userns_fd;
|
||||
|
||||
if (setns(userns_fd, CLONE_NEWUSER) < 0)
|
||||
return log_debug_errno(errno, "Failed to join freshly allocated user namespace: %m");
|
||||
|
||||
/* In "managed" mode the originating UID is not mapped hence we need to explicitly become root in the new userns now. */
|
||||
r = reset_uid_gid();
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to reset UID/GID to root: %m");
|
||||
|
||||
return 1; /* Early exit */
|
||||
}
|
||||
|
||||
case PRIVATE_USERS_IDENTITY:
|
||||
uid_map = strdup("0 0 65536\n");
|
||||
if (!uid_map)
|
||||
|
||||
@@ -4137,6 +4137,7 @@ static const char* const private_users_table[_PRIVATE_USERS_MAX] = {
|
||||
[PRIVATE_USERS_SELF] = "self",
|
||||
[PRIVATE_USERS_IDENTITY] = "identity",
|
||||
[PRIVATE_USERS_FULL] = "full",
|
||||
[PRIVATE_USERS_MANAGED] = "managed",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(private_users, PrivateUsers, PRIVATE_USERS_SELF);
|
||||
|
||||
@@ -70,6 +70,7 @@ typedef enum PrivateUsers {
|
||||
PRIVATE_USERS_SELF,
|
||||
PRIVATE_USERS_IDENTITY,
|
||||
PRIVATE_USERS_FULL,
|
||||
PRIVATE_USERS_MANAGED,
|
||||
_PRIVATE_USERS_MAX,
|
||||
_PRIVATE_USERS_INVALID = -EINVAL,
|
||||
} PrivateUsers;
|
||||
|
||||
@@ -4328,6 +4328,9 @@ static int unit_verify_contexts(const Unit *u) {
|
||||
if (ec->pam_name && kc && !IN_SET(kc->kill_mode, KILL_CONTROL_GROUP, KILL_MIXED))
|
||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOEXEC), "Unit has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.");
|
||||
|
||||
if ((ec->user || ec->dynamic_user) && ec->private_users == PRIVATE_USERS_MANAGED)
|
||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOEXEC), "PrivateUsers=managed may not be used in combination with User=/DynamicUser=, refusing.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user