[5/7] cr-check: use two features to verify userfaultfd availability

Submitted by Mike Rapoport on Aug. 15, 2017, 6:23 a.m.

Details

Message ID 1502778234-24415-6-git-send-email-rppt@linux.vnet.ibm.com
State New
Series "lazy-pages: update checks for availability of userfaultfd"
Headers show

Commit Message

Mike Rapoport Aug. 15, 2017, 6:23 a.m.
For the older kernels the implementation of userfaultfd would not include
non-cooperative mode. In such case it is still possible to use uffd and
enable lazy-pages, but if the restored process will change its virtual
memory layout during restore, we'll get memory corruption.

After this change 'criu check --feature uffd' will report success if the kernel
supports userfaultfd at all and 'criu check --feature uffd-noncoop' will
report success if the kernel supports non-cooperative userfaultfd.

Suggested-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
---
 criu/cr-check.c     | 23 ++++++++++++++---------
 criu/include/uffd.h |  1 +
 criu/uffd.c         |  8 ++++++++
 3 files changed, 23 insertions(+), 9 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-check.c b/criu/cr-check.c
index 0c0a760..e6bb14a 100644
--- a/criu/cr-check.c
+++ b/criu/cr-check.c
@@ -50,7 +50,7 @@ 
 #include "libnetlink.h"
 #include "net.h"
 #include "restorer.h"
-#include "linux/userfaultfd.h"
+#include "uffd.h"
 
 static char *feature_name(int (*func)());
 
@@ -1048,18 +1048,21 @@  static int check_compat_cr(void)
 
 static int check_uffd(void)
 {
-	unsigned long features = UFFD_FEATURE_EVENT_FORK |
-		UFFD_FEATURE_EVENT_REMAP |
-		UFFD_FEATURE_EVENT_UNMAP |
-		UFFD_FEATURE_EVENT_REMOVE;
-
 	if (!kdat.has_uffd) {
 		pr_err("UFFD is not supported\n");
 		return -1;
 	}
 
-	if ((kdat.uffd_features & features) != features) {
-		pr_err("Userfaultfd missing essential features\n");
+	return 0;
+}
+
+static int check_uffd_noncoop(void)
+{
+	if (check_uffd())
+		return -1;
+
+	if (!uffd_noncooperative()) {
+		pr_err("Non-cooperative UFFD is not supported\n");
 		return -1;
 	}
 
@@ -1239,6 +1242,7 @@  int cr_check(void)
 		ret |= check_pid_for_children_ns();
 		ret |= check_can_map_vdso();
 		ret |= check_uffd();
+		ret |= check_uffd_noncoop();
 	}
 
 	/*
@@ -1314,7 +1318,8 @@  static struct feature_list feature_list[] = {
 	{ "autofs", check_autofs },
 	{ "tcp_half_closed", check_tcp_halt_closed },
 	{ "compat_cr", check_compat_cr },
-	{ "lazy_pages", check_uffd },
+	{ "uffd", check_uffd },
+	{ "uffd-noncoop", check_uffd_noncoop },
 	{ "sk_ns", check_sk_netns },
 	{ "nsid", check_nsid },
 	{ "link_nsid", check_link_nsid},
diff --git a/criu/include/uffd.h b/criu/include/uffd.h
index e2b9be6..79abc16 100644
--- a/criu/include/uffd.h
+++ b/criu/include/uffd.h
@@ -4,6 +4,7 @@ 
 struct task_restore_args;
 
 extern int uffd_open(int flags, unsigned long *features);
+extern bool uffd_noncooperative(void);
 extern int setup_uffd(int pid, struct task_restore_args *task_args);
 extern int lazy_pages_setup_zombie(int pid);
 extern int prepare_lazy_pages_socket(void);
diff --git a/criu/uffd.c b/criu/uffd.c
index d3142ae..93c01bb 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -211,6 +211,14 @@  int lazy_pages_setup_zombie(int pid)
 	return 0;
 }
 
+bool uffd_noncooperative(void)
+{
+	unsigned long features = NEED_UFFD_API_FEATURES;
+
+	return (kdat.uffd_features & features) == features;
+
+}
+
 int uffd_open(int flags, unsigned long *features)
 {
 	struct uffdio_api uffdio_api = { 0 };