[CRIU] [PATCH 01/12] x86: cpu -- Save xsave frame sizes in image

Cyrill Gorcunov gorcunov at gmail.com
Thu Aug 30 14:00:16 MSK 2018


Keep xsave sizes in image to be sure that on restore the application
won't override memory out of xsave frame size if been calling xsave
instruction directly.

Here are some details: while been testing vz7 containers migration
we've noticed that sometime applications do crash after restore,
what is worse such execution abort may happen not immediately
after the restore but after passing some time. After spending
a lot of time we discovered that it is due to the fact that
the migration is directed from an old cpu to a modern one
which has extensions such as mpx. In result libc has cached
small xsave size and then after restore any direct call to
xsave instruction overwrite memory which is allocated with
size less than needed.

Thus we save xsave frame size in image and require it to
match to prevent such situation.

Signed-off-by: Cyrill Gorcunov <gorcunov at gmail.com>
Reviewed-by: Dmitry Safonov <0x7f454c46 at gmaill.com>
---
 criu/arch/x86/cpu.c  | 33 ++++++++++++++++++++++++++++++---
 images/cpuinfo.proto |  2 ++
 2 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c
index 60b3b9e2128e..fb377215b289 100644
--- a/criu/arch/x86/cpu.c
+++ b/criu/arch/x86/cpu.c
@@ -92,6 +92,10 @@ int cpu_dump_cpuinfo(void)
 	cpu_x86_info.capability = (void *)rt_cpu_info.x86_capability;
 	cpu_x86_info.has_xfeatures_mask = true;
 	cpu_x86_info.xfeatures_mask = rt_cpu_info.xfeatures_mask;
+	cpu_x86_info.has_xsave_size = true;
+	cpu_x86_info.xsave_size = rt_cpu_info.xsave_size;
+	cpu_x86_info.has_xsave_size_max = true;
+	cpu_x86_info.xsave_size_max = rt_cpu_info.xsave_size_max;
 
 	if (rt_cpu_info.x86_model_id[0])
 		cpu_x86_info.model_id = rt_cpu_info.x86_model_id;
@@ -259,14 +263,25 @@ static int cpu_validate_features(compel_cpuinfo_t *cpu_info)
 	}
 
 	/*
-	 * Make sure the xsave features are at least not less
-	 * than current cpu supports.
+	 * Make sure the xsave features are compatible. We already hit the
+	 * issue with libc where we've checkpointed the container on old
+	 * machine but restored on more modern one and libc fetched new
+	 * xsave frame size directly by xsave instruction with greedy
+	 * feature mask causing programs to misbehave.
 	 */
-	if (cpu_info->xfeatures_mask > rt_cpu_info.xfeatures_mask) {
+	if (cpu_info->xfeatures_mask != rt_cpu_info.xfeatures_mask) {
 		uint64_t m = cpu_info->xfeatures_mask & ~rt_cpu_info.xfeatures_mask;
 		pr_err("CPU xfeatures has unsupported bits (%#llx)\n",
 		       (unsigned long long)m);
 		return -1;
+	} else if (cpu_info->xsave_size != rt_cpu_info.xsave_size) {
+		pr_err("CPU xsave size mismatch (%u/%u)\n",
+		       cpu_info->xsave_size, rt_cpu_info.xsave_size);
+		return -1;
+	} else if (cpu_info->xsave_size_max != rt_cpu_info.xsave_size_max) {
+		pr_err("CPU xsave max size mismatch (%u/%u)\n",
+		       cpu_info->xsave_size_max, rt_cpu_info.xsave_size_max);
+		return -1;
 	}
 
 	/*
@@ -370,6 +385,18 @@ static compel_cpuinfo_t *img_to_cpuinfo(CpuinfoX86Entry *img_x86_entry)
 	} else
 		cpu_info->xfeatures_mask = img_x86_entry->xfeatures_mask;
 
+	/*
+	 * Same for other fields.
+	 */
+	if (!img_x86_entry->has_xsave_size)
+		cpu_info->xsave_size = rt_cpu_info.xsave_size;
+	else
+		cpu_info->xsave_size = img_x86_entry->xsave_size;
+	if (!img_x86_entry->has_xsave_size_max)
+		cpu_info->xsave_size_max = rt_cpu_info.xsave_size_max;
+	else
+		cpu_info->xsave_size_max = img_x86_entry->xsave_size_max;
+
 	return cpu_info;
 }
 
diff --git a/images/cpuinfo.proto b/images/cpuinfo.proto
index b399503bdb48..8ee629c2c912 100644
--- a/images/cpuinfo.proto
+++ b/images/cpuinfo.proto
@@ -17,6 +17,8 @@ message cpuinfo_x86_entry {
 	optional string			model_id	= 7;
 
 	optional uint64			xfeatures_mask	= 8;
+	optional uint32			xsave_size	= 9;
+	optional uint32			xsave_size_max	= 10;
 }
 
 message cpuinfo_ppc64_entry {
-- 
2.17.1



More information about the CRIU mailing list