Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/vdso: Use .fault for the vDSO text mapping

The old scheme for mapping the vDSO text is rather complicated.
vdso2c generates a struct vm_special_mapping and a blank .pages
array of the correct size for each vdso image. Init code in
vdso/vma.c populates the .pages array for each vDSO image, and
the mapping code selects the appropriate struct
vm_special_mapping.

With .fault, we can use a less roundabout approach: vdso_fault()
just returns the appropriate page for the selected vDSO image.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/f886954c186bafd74e1b967c8931d852ae199aa2.1451446564.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Andy Lutomirski and committed by
Ingo Molnar
05ef76b2 352b78c6

+19 -17
-7
arch/x86/entry/vdso/vdso2c.h
··· 150 150 } 151 151 fprintf(outfile, "\n};\n\n"); 152 152 153 - fprintf(outfile, "static struct page *pages[%lu];\n\n", 154 - mapping_size / 4096); 155 - 156 153 fprintf(outfile, "const struct vdso_image %s = {\n", name); 157 154 fprintf(outfile, "\t.data = raw_data,\n"); 158 155 fprintf(outfile, "\t.size = %lu,\n", mapping_size); 159 - fprintf(outfile, "\t.text_mapping = {\n"); 160 - fprintf(outfile, "\t\t.name = \"[vdso]\",\n"); 161 - fprintf(outfile, "\t\t.pages = pages,\n"); 162 - fprintf(outfile, "\t},\n"); 163 156 if (alt_sec) { 164 157 fprintf(outfile, "\t.alt = %lu,\n", 165 158 (unsigned long)GET_LE(&alt_sec->sh_offset));
+19 -7
arch/x86/entry/vdso/vma.c
··· 27 27 28 28 void __init init_vdso_image(const struct vdso_image *image) 29 29 { 30 - int i; 31 - int npages = (image->size) / PAGE_SIZE; 32 - 33 30 BUG_ON(image->size % PAGE_SIZE != 0); 34 - for (i = 0; i < npages; i++) 35 - image->text_mapping.pages[i] = 36 - virt_to_page(image->data + i*PAGE_SIZE); 37 31 38 32 apply_alternatives((struct alt_instr *)(image->data + image->alt), 39 33 (struct alt_instr *)(image->data + image->alt + ··· 84 90 #endif 85 91 } 86 92 93 + static int vdso_fault(const struct vm_special_mapping *sm, 94 + struct vm_area_struct *vma, struct vm_fault *vmf) 95 + { 96 + const struct vdso_image *image = vma->vm_mm->context.vdso_image; 97 + 98 + if (!image || (vmf->pgoff << PAGE_SHIFT) >= image->size) 99 + return VM_FAULT_SIGBUS; 100 + 101 + vmf->page = virt_to_page(image->data + (vmf->pgoff << PAGE_SHIFT)); 102 + get_page(vmf->page); 103 + return 0; 104 + } 105 + 106 + static const struct vm_special_mapping text_mapping = { 107 + .name = "[vdso]", 108 + .fault = vdso_fault, 109 + }; 110 + 87 111 static int map_vdso(const struct vdso_image *image, bool calculate_addr) 88 112 { 89 113 struct mm_struct *mm = current->mm; ··· 143 131 image->size, 144 132 VM_READ|VM_EXEC| 145 133 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 146 - &image->text_mapping); 134 + &text_mapping); 147 135 148 136 if (IS_ERR(vma)) { 149 137 ret = PTR_ERR(vma);
-3
arch/x86/include/asm/vdso.h
··· 13 13 void *data; 14 14 unsigned long size; /* Always a multiple of PAGE_SIZE */ 15 15 16 - /* text_mapping.pages is big enough for data/size page pointers */ 17 - struct vm_special_mapping text_mapping; 18 - 19 16 unsigned long alt, alt_len; 20 17 21 18 long sym_vvar_start; /* Negative offset to the vvar area */