Enable changing of mount context on restore

This change is motivated by checkpointing and restoring container in
Pods.

When restoring a container into a new Pod the SELinux label of the
existing Pod needs to be used and not the SELinux label saved during
checkpointing.

The option --lsm-profile already enables changing of process SELinux
labels on restore. If there are, however, tmpfs checkpointed they
will be mounted during restore with the same context as during
checkpointing. This can look like the following example:

 context="system_u:object_r:container_file_t:s0:c82,c137"

On restore we want to change this context to match the mount label of
the Pod this container is restored into. Changing of the mount label
is now possible with the new option --mount-context:

 criu restore --mount-context "system_u:object_r:container_file_t:s0:c204,c495"

This will lead to mount options being changed to

 context="system_u:object_r:container_file_t:s0:c204,c495"

Now the restored container can access all the files in the container
again.

This has been tested in combination with runc and CRI-O.

Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
Adrian Reber 2021-06-08 17:22:03 +00:00 committed by Andrei Vagin
parent 5be71273f6
commit 64dd64e504
7 changed files with 99 additions and 2 deletions

View file

@ -554,6 +554,28 @@ The 'mode' may be one of the following:
Specify an LSM profile to be used during restore. The _type_ can be
either *apparmor* or *selinux*.
*--lsm-mount-context* 'context'::
Specify a new mount context to be used during restore.
+
This option will only replace existing mount context information
with the one specified with this option. Mounts without the
'context=' option will not be changed.
+
If a mountpoint has been checkpointed with an option like
context="system_u:object_r:container_file_t:s0:c82,c137"
+
it is possible to change this option using
--lsm-mount-context "system_u:object_r:container_file_t:s0:c204,c495"
+
which will result that the mountpoint will be restored
with the new 'context='.
+
This option is useful if using *selinux* and if the *selinux*
labels need to be changed on restore like if a container is
restored into an existing Pod.
*--auto-dedup*::
As soon as a page is restored it get punched out from image.

View file

@ -690,6 +690,7 @@ int parse_options(int argc, char **argv, bool *usage_error,
{ "cgroup-yard", required_argument, 0, 1096 },
{ "pre-dump-mode", required_argument, 0, 1097},
{ "file-validation", required_argument, 0, 1098 },
{ "lsm-mount-context", required_argument, 0, 1099 },
{ },
};
@ -1019,6 +1020,9 @@ int parse_options(int argc, char **argv, bool *usage_error,
if (parse_file_validation_method(&opts, optarg))
return 2;
break;
case 1099:
SET_CHAR_OPTS(lsm_mount_context, optarg);
break;
case 'V':
pr_msg("Version: %s\n", CRIU_VERSION);
if (strcmp(CRIU_GITID, "0"))

View file

@ -623,6 +623,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
SET_CHAR_OPTS(lsm_profile, req->lsm_profile);
}
if (req->lsm_mount_context)
SET_CHAR_OPTS(lsm_mount_context, req->lsm_mount_context);
if (req->has_timeout)
opts.timeout = req->timeout;

View file

@ -422,6 +422,10 @@ usage:
" --lsm-profile TYPE:NAME\n"
" Specify an LSM profile to be used during restore.\n"
" The type can be either 'apparmor' or 'selinux'.\n"
" --lsm-mount-context CTX\n"
" Specify a mount context to be used during restore.\n"
" Only mounts with an existing context will have their\n"
" mount context replaced with CTX.\n"
" --skip-mnt PATH ignore this mountpoint when dumping the mount namespace\n"
" --enable-fs FSNAMES a comma separated list of filesystem names or \"all\"\n"
" force criu to (try to) dump/restore these filesystem's\n"

View file

@ -145,6 +145,7 @@ struct cr_options {
struct list_head irmap_scan_paths;
bool lsm_supplied;
char *lsm_profile;
char *lsm_mount_context;
unsigned int timeout;
unsigned int empty_ns;
int tcp_skip_in_flight;

View file

@ -45,6 +45,8 @@
#define BINFMT_MISC_HOME "proc/sys/fs/binfmt_misc"
#define CRTIME_MNT_ID 0
#define CONTEXT_OPT "context="
/* A helper mount_info entry for the roots yard */
static struct mount_info *root_yard_mp = NULL;
@ -2942,6 +2944,66 @@ static int get_mp_mountpoint(char *mountpoint, struct mount_info *mi, char *root
return 0;
}
static char *mount_update_lsm_context(char *mount_opts)
{
cleanup_free char *before_context = NULL;
char *other_options;
char *context_start;
char *context_end;
char *old_context;
char *new_options;
int ret;
old_context = strstr(mount_opts, CONTEXT_OPT);
if (!old_context || !opts.lsm_mount_context)
return xstrdup(mount_opts);
/*
* If the user specified a different mount_context we need
* to replace the existing mount context in the mount
* options with the one specified by the user.
*
* The original mount options will be something like:
*
* context="system_u:object_r:container_file_t:s0:c82,c137",inode64
*
* and it needs to be replaced with opts.lsm_mount_context.
*
* The content between 'context=' and ',inode64' will be replaced
* with opts.lsm_mount_context in quotes.
*/
/* Skip 'context=' */
context_start = old_context + strlen(CONTEXT_OPT);
if (context_start[0] == '"' && context_start + 1 < mount_opts + strlen(mount_opts)) {
/* Skip quotes */
context_end = strchr(context_start + 1, '"');
if (!context_end) {
pr_err("Failed parsing mount option 'context'\n");
return NULL;
}
} else {
context_end = context_start;
}
/* Find next after optionally skipping quotes. */
other_options = strchr(context_end, ',');
before_context = xstrdup(mount_opts);
if (unlikely(!before_context))
return NULL;
before_context[context_start - mount_opts] = 0;
ret = asprintf(&new_options, "%s\"%s\"%s", before_context,
opts.lsm_mount_context, other_options ? other_options : "");
if (unlikely(ret < 0))
return NULL;
pr_debug("\t\tChanged mount 'context=' to %s\n", new_options);
return new_options;
}
static int collect_mnt_from_image(struct mount_info **head, struct mount_info **tail, struct ns_id *nsid)
{
MntEntry *me = NULL;
@ -3006,8 +3068,8 @@ static int collect_mnt_from_image(struct mount_info **head, struct mount_info **
if (!pm->source)
goto err;
pm->options = xstrdup(me->options);
if (!pm->options)
pm->options = mount_update_lsm_context(me->options);
if (unlikely(!pm->options))
goto err;
if (me->fstype != FSTYPE__AUTO && me->fsname) {

View file

@ -130,6 +130,7 @@ message criu_opts {
optional string cgroup_yard = 60;
optional criu_pre_dump_mode pre_dump_mode = 61 [default = SPLICE];
optional int32 pidfd_store_sk = 62;
optional string lsm_mount_context = 63;
/* optional bool check_mounts = 128; */
}