Skip to content

Commit

Permalink
linux: support options to idmap
Browse files Browse the repository at this point in the history
allow to specify what mapping must be used for idmapped mounts.

The mapping can be specified after the `idmap` option like:
`idmap=uids=0-1-10;gids=0-100-10`.

When `uids` and `gids` are specified, then a new user namespace is
created and used for the bind mount.

Closes: containers#873

Signed-off-by: Giuseppe Scrivano <[email protected]>
  • Loading branch information
giuseppe committed Feb 14, 2022
1 parent af00681 commit c4ffcf8
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 11 deletions.
18 changes: 18 additions & 0 deletions crun.1
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,24 @@ If the \fB\fCidmap\fR option is specified then the mount is ID mapped using the
target user namespace. This is an experimental feature and can change at any time
without notice.

.PP
The \fB\fCidmap\fR option supports a custom mapping that can be different
than the user namespace used by the container.

.PP
The mapping can be specified after the \fB\fCidmap\fR option like:
\fB\fCidmap=uids=0-1-10;gids=0-100-10\fR\&.

.PP
The only two options that are currently supported are \fB\fCuids\fR and \fB\fCgids\fR\&.

.PP
When a custom mapping is specified, a new user namespace is created
for the idmapped mount.

.PP
If no option is specified, then the container user namespace is used.

.SH Automatically create user namespace
.PP
When running as user different than root, an user namespace is
Expand Down
13 changes: 13 additions & 0 deletions crun.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,19 @@ If the `idmap` option is specified then the mount is ID mapped using the contain
target user namespace. This is an experimental feature and can change at any time
without notice.

The `idmap` option supports a custom mapping that can be different
than the user namespace used by the container.

The mapping can be specified after the `idmap` option like:
`idmap=uids=0-1-10;gids=0-100-10`.

The only two options that are currently supported are `uids` and `gids`.

When a custom mapping is specified, a new user namespace is created
for the idmapped mount.

If no option is specified, then the container user namespace is used.

## Automatically create user namespace

When running as user different than root, an user namespace is
Expand Down
92 changes: 81 additions & 11 deletions src/libcrun/linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,16 +430,85 @@ get_bind_mount (const char *src, libcrun_error_t *err)
return get_and_reset (&open_tree_fd);
}

static pid_t
create_userns_for_idmapped_mount (const char *options, libcrun_error_t *err)
{
cleanup_free char *dup_options = xstrdup (options);
char *option, *saveptr = NULL;
cleanup_pid pid_t pid = -1;
pid_t xchg_pid;

pid = syscall_clone (CLONE_NEWUSER | SIGCHLD, NULL);
if (UNLIKELY (pid < 0))
return crun_make_error (err, errno, "clone");

if (pid == 0)
{
prctl (PR_SET_PDEATHSIG, SIGKILL);
while (1)
pause ();
_exit (EXIT_SUCCESS);
}
for (option = strtok_r (dup_options, ";", &saveptr); option; option = strtok_r (NULL, ";", &saveptr))
{
cleanup_free char *ids = xstrdup (option + 5 /* strlen ("uids=") and strlen ("gids=") */);
char proc_file[64];
char *it;
int ret;

for (it = ids; *it; it++)
{
if (*it == '-')
*it = ' ';
else if (*it == ',')
*it = '\n';
}

if (has_prefix (option, "uids="))
{
sprintf (proc_file, "/proc/%d/uid_map", pid);
ret = write_file (proc_file, ids, strlen (ids), err);
if (UNLIKELY (ret < 0))
return ret;
}
else if (has_prefix (option, "gids="))
{
sprintf (proc_file, "/proc/%d/gid_map", pid);
ret = write_file (proc_file, ids, strlen (ids), err);
if (UNLIKELY (ret < 0))
return ret;
}
else
return crun_make_error (err, 0, "invalid option `%s` specified", option);
}

xchg_pid = pid;
pid = -1;
return xchg_pid;
}

static int
get_idmapped_mount (const char *src, pid_t pid, libcrun_error_t *err)
get_idmapped_mount (const char *src, const char *idmap_option, pid_t pid, libcrun_error_t *err)
{
cleanup_close int open_tree_fd = -1;
cleanup_close int fd = -1;
int ret;
char proc_path[64];
cleanup_pid pid_t created_pid = -1;
struct mount_attr_s attr = {
0,
};
cleanup_close int fd = -1;
const char *options;
char proc_path[64];
int ret;

/* If there are options specified, create a new user namespace with the configured mappings. */
if ((options = strchr (idmap_option, '=')))
{
created_pid = create_userns_for_idmapped_mount (options + 1, err);
if (UNLIKELY (created_pid < 0))
return created_pid;

pid = created_pid;
}

sprintf (proc_path, "/proc/%d/ns/user", pid);
fd = open (proc_path, O_RDONLY);
Expand Down Expand Up @@ -3350,15 +3419,15 @@ get_fd_map (libcrun_container_t *container)
return mount_fds;
}

static bool
is_idmapped (runtime_spec_schema_defs_mount *mnt)
static char *
get_idmapped_option (runtime_spec_schema_defs_mount *mnt)
{
size_t i;

for (i = 0; i < mnt->options_len; i++)
if (strcmp (mnt->options[i], "idmap") == 0)
return true;
return false;
if (has_prefix (mnt->options[i], "idmap"))
return mnt->options[i];
return NULL;
}

static bool
Expand Down Expand Up @@ -3393,11 +3462,12 @@ prepare_and_send_mounts (libcrun_container_t *container, pid_t pid, int sync_soc

for (i = 0; i < def->mounts_len; i++)
{
if (is_idmapped (def->mounts[i]))
const char *idmap_option = get_idmapped_option (def->mounts[i]);
if (idmap_option)
{
int fd;

fd = get_idmapped_mount (def->mounts[i]->source, pid, err);
fd = get_idmapped_mount (def->mounts[i]->source, idmap_option, pid, err);
if (UNLIKELY (fd < 0))
return fd;

Expand Down

0 comments on commit c4ffcf8

Please sign in to comment.