Skip to content

Commit 7143e24

Browse files
authored
Merge pull request #1747 from kolyshkin/criu-3
criu: fix c/r for container with bind mounts where dest is a symlink
2 parents 819c2a7 + 174963d commit 7143e24

File tree

3 files changed

+54
-41
lines changed

3 files changed

+54
-41
lines changed

src/libcrun/criu.c

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
# define CLONE_NEWTIME 0x00000080 /* New time namespace */
5252
# endif
5353

54+
/* Defined in chroot_realpath.c */
55+
char *chroot_realpath (const char *chroot, const char *path, char resolved_path[]);
56+
5457
static const char *console_socket = NULL;
5558

5659
# define LIBCRIU_MIN_VERSION 31500
@@ -283,7 +286,8 @@ restore_cgroup_v1_mount (runtime_spec_schema_config_schema *def, libcrun_error_t
283286
/* First check if there is actually a cgroup mount in the container. */
284287
for (i = 0; i < def->mounts_len; i++)
285288
{
286-
if (strcmp (def->mounts[i]->type, "cgroup") == 0)
289+
char *type = def->mounts[i]->type;
290+
if (type && strcmp (type, "cgroup") == 0)
287291
{
288292
has_cgroup_mount = true;
289293
break;
@@ -353,7 +357,8 @@ checkpoint_cgroup_v1_mount (runtime_spec_schema_config_schema *def, libcrun_erro
353357
/* First check if there is actually a cgroup mount in the container. */
354358
for (i = 0; i < def->mounts_len; i++)
355359
{
356-
if (strcmp (def->mounts[i]->type, "cgroup") == 0)
360+
char *type = def->mounts[i]->type;
361+
if (type && strcmp (type, "cgroup") == 0)
357362
{
358363
has_cgroup_mount = true;
359364
break;
@@ -413,7 +418,7 @@ libcrun_container_checkpoint_linux_criu (libcrun_container_status_t *status, lib
413418
cleanup_wrapper struct libcriu_wrapper_s *wrapper = NULL;
414419
cleanup_free char *descriptors_path = NULL;
415420
cleanup_free char *freezer_path = NULL;
416-
cleanup_free char *path = NULL;
421+
cleanup_free char *rootfs = NULL;
417422
cleanup_close int image_fd = -1;
418423
cleanup_close int work_fd = -1;
419424
int cgroup_mode;
@@ -552,13 +557,13 @@ libcrun_container_checkpoint_linux_criu (libcrun_container_status_t *status, lib
552557
if (UNLIKELY (ret < 0))
553558
return crun_error_wrap (err, "error saving CRIU descriptors file");
554559

555-
ret = append_paths (&path, err, status->bundle, status->rootfs, NULL);
560+
ret = append_paths (&rootfs, err, status->bundle, status->rootfs, NULL);
556561
if (UNLIKELY (ret < 0))
557562
return ret;
558563

559-
ret = libcriu_wrapper->criu_set_root (path);
564+
ret = libcriu_wrapper->criu_set_root (rootfs);
560565
if (UNLIKELY (ret != 0))
561-
return crun_make_error (err, 0, "error setting CRIU root to `%s`", path);
566+
return crun_make_error (err, 0, "error setting CRIU root to `%s`", rootfs);
562567

563568
cgroup_mode = libcrun_get_cgroup_mode (err);
564569
if (UNLIKELY (cgroup_mode < 0))
@@ -575,17 +580,20 @@ libcrun_container_checkpoint_linux_criu (libcrun_container_status_t *status, lib
575580
/* Tell CRIU about external bind mounts. */
576581
for (i = 0; i < def->mounts_len; i++)
577582
{
578-
size_t j;
579-
580-
for (j = 0; j < def->mounts[i]->options_len; j++)
583+
if (is_bind_mount (def->mounts[i], NULL))
581584
{
582-
if (strcmp (def->mounts[i]->options[j], "bind") == 0 || strcmp (def->mounts[i]->options[j], "rbind") == 0)
583-
{
584-
ret = libcriu_wrapper->criu_add_ext_mount (def->mounts[i]->destination, def->mounts[i]->destination);
585-
if (UNLIKELY (ret < 0))
586-
return crun_make_error (err, -ret, "CRIU: failed adding external mount to `%s`", def->mounts[i]->destination);
587-
break;
588-
}
585+
/* We need to resolve mount destination inside container's root for CRIU to handle. */
586+
char buf[PATH_MAX];
587+
const char *dest_in_root;
588+
589+
dest_in_root = chroot_realpath (rootfs, def->mounts[i]->destination, buf);
590+
if (UNLIKELY (dest_in_root == NULL))
591+
return crun_make_error (err, errno, "unable to resolve external bind mount `%s` under rootfs", def->mounts[i]->destination);
592+
dest_in_root += strlen (rootfs);
593+
594+
ret = libcriu_wrapper->criu_add_ext_mount (dest_in_root, dest_in_root);
595+
if (UNLIKELY (ret < 0))
596+
return crun_make_error (err, -ret, "CRIU: failed adding external mount to `%s`", def->mounts[i]->destination);
589597
}
590598
}
591599

@@ -720,17 +728,18 @@ prepare_restore_mounts (runtime_spec_schema_config_schema *def, char *root, libc
720728
size_t j;
721729

722730
/* cgroup restore should be handled by CRIU itself */
723-
if (strcmp (type, "cgroup") == 0 || strcmp (type, "cgroup2") == 0)
731+
if (type && (strcmp (type, "cgroup") == 0 || strcmp (type, "cgroup2") == 0))
724732
continue;
725733

726734
/* Check if the mountpoint is on a tmpfs. CRIU restores
727735
* all tmpfs. We do need to recreate directories on a tmpfs. */
736+
size_t dest_len = strlen (dest);
728737
for (j = 0; j < def->mounts_len; j++)
729738
{
730-
cleanup_free char *dest_loop = NULL;
731-
732-
xasprintf (&dest_loop, "%s/", def->mounts[j]->destination);
733-
if (strncmp (dest, dest_loop, strlen (dest_loop)) == 0 && strcmp (def->mounts[j]->type, "tmpfs") == 0)
739+
if (def->mounts[j]->type == NULL || strcmp (def->mounts[j]->type, "tmpfs") != 0)
740+
continue;
741+
size_t mount_len = strlen (def->mounts[j]->destination);
742+
if (mount_len < dest_len && dest[mount_len] == '/' && strncmp (dest, def->mounts[j]->destination, mount_len) == 0)
734743
{
735744
/* This is a mountpoint which is on a tmpfs.*/
736745
on_tmpfs = true;
@@ -742,16 +751,11 @@ prepare_restore_mounts (runtime_spec_schema_config_schema *def, char *root, libc
742751
continue;
743752

744753
/* For bind mounts check if the source is a file or a directory. */
745-
for (j = 0; j < def->mounts[i]->options_len; j++)
754+
if (is_bind_mount (def->mounts[i], NULL))
746755
{
747-
const char *opt = def->mounts[i]->options[j];
748-
if (strcmp (opt, "bind") == 0 || strcmp (opt, "rbind") == 0)
749-
{
750-
is_dir = crun_dir_p (def->mounts[i]->source, false, err);
751-
if (UNLIKELY (is_dir < 0))
752-
return is_dir;
753-
break;
754-
}
756+
is_dir = crun_dir_p (def->mounts[i]->source, false, err);
757+
if (UNLIKELY (is_dir < 0))
758+
return is_dir;
755759
}
756760

757761
root_fd = open (root, O_RDONLY | O_CLOEXEC);
@@ -789,6 +793,7 @@ libcrun_container_restore_linux_criu (libcrun_container_status_t *status, libcru
789793
cleanup_close int inherit_new_pid_fd = -1;
790794
cleanup_close int image_fd = -1;
791795
cleanup_free char *root = NULL;
796+
cleanup_free char *rootfs = NULL;
792797
cleanup_free char *bundle_cleanup = NULL;
793798
cleanup_close int work_fd = -1;
794799
int ret_out;
@@ -899,19 +904,25 @@ libcrun_container_restore_linux_criu (libcrun_container_status_t *status, libcru
899904
}
900905

901906
/* Tell CRIU about external bind mounts. */
907+
ret = append_paths (&rootfs, err, status->bundle, status->rootfs, NULL);
908+
if (UNLIKELY (ret < 0))
909+
return ret;
902910
for (i = 0; i < def->mounts_len; i++)
903911
{
904-
size_t j;
905-
906-
for (j = 0; j < def->mounts[i]->options_len; j++)
912+
if (is_bind_mount (def->mounts[i], NULL))
907913
{
908-
if (strcmp (def->mounts[i]->options[j], "bind") == 0 || strcmp (def->mounts[i]->options[j], "rbind") == 0)
909-
{
910-
ret = libcriu_wrapper->criu_add_ext_mount (def->mounts[i]->destination, def->mounts[i]->source);
911-
if (UNLIKELY (ret < 0))
912-
return crun_make_error (err, -ret, "CRIU: failed adding external mount to `%s`", def->mounts[i]->source);
913-
break;
914-
}
914+
/* We need to resolve mount destination inside container's root for CRIU to handle. */
915+
char buf[PATH_MAX];
916+
const char *dest_in_root;
917+
918+
dest_in_root = chroot_realpath (rootfs, def->mounts[i]->destination, buf);
919+
if (UNLIKELY (dest_in_root == NULL))
920+
return crun_make_error (err, errno, "unable to resolve external bind mount `%s` under rootfs", def->mounts[i]->destination);
921+
dest_in_root += strlen (rootfs);
922+
923+
ret = libcriu_wrapper->criu_add_ext_mount (dest_in_root, def->mounts[i]->source);
924+
if (UNLIKELY (ret < 0))
925+
return crun_make_error (err, -ret, "CRIU: failed adding external mount to `%s`", def->mounts[i]->source);
915926
}
916927
}
917928

src/libcrun/linux.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4002,7 +4002,7 @@ get_fd_map (libcrun_container_t *container)
40024002
return mount_fds;
40034003
}
40044004

4005-
static bool
4005+
bool
40064006
is_bind_mount (runtime_spec_schema_defs_mount *mnt, bool *recursive)
40074007
{
40084008
size_t i;

src/libcrun/linux.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ int libcrun_safe_chdir (const char *path, libcrun_error_t *err);
149149

150150
int get_bind_mount (int dirfd, const char *src, bool recursive, bool rdonly, libcrun_error_t *err);
151151

152+
bool is_bind_mount (runtime_spec_schema_defs_mount *mnt, bool *recursive);
153+
152154
int libcrun_make_runtime_mounts (libcrun_container_t *container, libcrun_container_status_t *status, runtime_spec_schema_defs_mount **mounts, size_t len, libcrun_error_t *err);
153155

154156
int libcrun_destroy_runtime_mounts (libcrun_container_t *container, libcrun_container_status_t *status, runtime_spec_schema_defs_mount **mounts, size_t len, libcrun_error_t *err);

0 commit comments

Comments
 (0)