2020-01-14 05:14:57

by Guoyun Sun

[permalink] [raw]
Subject: [PATCH] mips/vdso: Support mremap() for vDSO

vDSO VMA address is saved in mm_context for the purpose of using
restorer from vDSO page to return to userspace after signal handling.

In Checkpoint Restore in Userspace (CRIU) project we place vDSO VMA
on restore back to the place where it was on the dump.

Make vDSO code track the VMA address by supplying .mremap() fops
the same way it's done for x86 and arm by:
commit b059a453b1cf ("x86/vdso: Add mremap hook to vm_special_mapping")
commit 739586951b8a ("arm64/vdso: Support mremap() for vDSO").

Signed-off-by: Guoyun Sun <[email protected]>
---
arch/mips/kernel/vdso.c | 22 ++++++++++++++++++++++
arch/mips/vdso/genvdso.c | 5 +++++
2 files changed, 27 insertions(+)

diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
index bc35f84..eac3982 100644
--- a/arch/mips/kernel/vdso.c
+++ b/arch/mips/kernel/vdso.c
@@ -38,6 +38,28 @@ static struct vm_special_mapping vdso_vvar_mapping = {
.pages = no_pages,
};

+int vdso_mremap(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma)
+{
+ unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
+
+#ifdef CONFIG_MIPS32_O32
+ if (vdso_image_o32.size != new_size)
+ return -EINVAL;
+#endif
+
+#ifdef CONFIG_MIPS32_N32
+ if (vdso_image_n32.size != new_size)
+ return -EINVAL;
+#endif
+
+ if (vdso_image.size != new_size)
+ return -EINVAL;
+
+ current->mm->context.vdso = (void __user *)(new_vma->vm_start);
+ return 0;
+}
+
static void __init init_vdso_image(struct mips_vdso_image *image)
{
unsigned long num_pages, i;
diff --git a/arch/mips/vdso/genvdso.c b/arch/mips/vdso/genvdso.c
index b66b6b1..50ea516 100644
--- a/arch/mips/vdso/genvdso.c
+++ b/arch/mips/vdso/genvdso.c
@@ -251,6 +251,10 @@ int main(int argc, char **argv)
fprintf(out_file, "#include <linux/linkage.h>\n");
fprintf(out_file, "#include <linux/mm.h>\n");
fprintf(out_file, "#include <asm/vdso.h>\n");
+ fprintf(out_file, "\n");
+ fprintf(out_file, "extern int vdso_mremap(\n");
+ fprintf(out_file, " const struct vm_special_mapping *sm,\n");
+ fprintf(out_file, " struct vm_area_struct *new_vma);\n\n");

/* Write out the stripped VDSO data. */
fprintf(out_file,
@@ -275,6 +279,7 @@ int main(int argc, char **argv)
fprintf(out_file, "\t.mapping = {\n");
fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
fprintf(out_file, "\t\t.pages = vdso_pages,\n");
+ fprintf(out_file, "\t\t.mremap = vdso_mremap,\n");
fprintf(out_file, "\t},\n");

/* Calculate and write symbol offsets to <output file> */
--
2.1.0


2020-01-15 00:09:20

by Paul Burton

[permalink] [raw]
Subject: Re: [PATCH] mips/vdso: Support mremap() for vDSO

Hi Guoyun,

On Tue, Jan 14, 2020 at 01:13:28PM +0800, Guoyun Sun wrote:
> diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
> index bc35f84..eac3982 100644
> --- a/arch/mips/kernel/vdso.c
> +++ b/arch/mips/kernel/vdso.c
> @@ -38,6 +38,28 @@ static struct vm_special_mapping vdso_vvar_mapping = {
> .pages = no_pages,
> };
>
> +int vdso_mremap(const struct vm_special_mapping *sm,
> + struct vm_area_struct *new_vma)
> +{
> + unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
> +
> +#ifdef CONFIG_MIPS32_O32
> + if (vdso_image_o32.size != new_size)
> + return -EINVAL;
> +#endif
> +
> +#ifdef CONFIG_MIPS32_N32
> + if (vdso_image_n32.size != new_size)
> + return -EINVAL;
> +#endif
> +
> + if (vdso_image.size != new_size)
> + return -EINVAL;
> +
> + current->mm->context.vdso = (void __user *)(new_vma->vm_start);
> + return 0;
> +}
> +

Thanks for the patch; this bit doesn't seem right though. It requires
that all the VDSOs be the same size, which seems questionable. I think
we probably need separate mremap callbacks for each VDSO, so that we can
check the appropriate VDSO size.

Thanks,
Paul