@@ -37,54 +37,6 @@ void __init init_vdso_image(const struct vdso_image *image)
3737
3838struct linux_binprm ;
3939
40- /*
41- * Put the vdso above the (randomized) stack with another randomized
42- * offset. This way there is no hole in the middle of address space.
43- * To save memory make sure it is still in the same PTE as the stack
44- * top. This doesn't give that many random bits.
45- *
46- * Note that this algorithm is imperfect: the distribution of the vdso
47- * start address within a PMD is biased toward the end.
48- *
49- * Only used for the 64-bit and x32 vdsos.
50- */
51- static unsigned long vdso_addr (unsigned long start , unsigned len )
52- {
53- #ifdef CONFIG_X86_32
54- return 0 ;
55- #else
56- unsigned long addr , end ;
57- unsigned offset ;
58-
59- /*
60- * Round up the start address. It can start out unaligned as a result
61- * of stack start randomization.
62- */
63- start = PAGE_ALIGN (start );
64-
65- /* Round the lowest possible end address up to a PMD boundary. */
66- end = (start + len + PMD_SIZE - 1 ) & PMD_MASK ;
67- if (end >= TASK_SIZE_MAX )
68- end = TASK_SIZE_MAX ;
69- end -= len ;
70-
71- if (end > start ) {
72- offset = get_random_int () % (((end - start ) >> PAGE_SHIFT ) + 1 );
73- addr = start + (offset << PAGE_SHIFT );
74- } else {
75- addr = start ;
76- }
77-
78- /*
79- * Forcibly align the final address in case we have a hardware
80- * issue that requires alignment for performance reasons.
81- */
82- addr = align_vdso_addr (addr );
83-
84- return addr ;
85- #endif
86- }
87-
8840static int vdso_fault (const struct vm_special_mapping * sm ,
8941 struct vm_area_struct * vma , struct vm_fault * vmf )
9042{
@@ -176,30 +128,28 @@ static int vvar_fault(const struct vm_special_mapping *sm,
176128 return VM_FAULT_SIGBUS ;
177129}
178130
179- static int map_vdso (const struct vdso_image * image , bool calculate_addr )
131+ static const struct vm_special_mapping vdso_mapping = {
132+ .name = "[vdso]" ,
133+ .fault = vdso_fault ,
134+ .mremap = vdso_mremap ,
135+ };
136+ static const struct vm_special_mapping vvar_mapping = {
137+ .name = "[vvar]" ,
138+ .fault = vvar_fault ,
139+ };
140+
141+ /*
142+ * Add vdso and vvar mappings to current process.
143+ * @image - blob to map
144+ * @addr - request a specific address (zero to map at free addr)
145+ */
146+ static int map_vdso (const struct vdso_image * image , unsigned long addr )
180147{
181148 struct mm_struct * mm = current -> mm ;
182149 struct vm_area_struct * vma ;
183- unsigned long addr , text_start ;
150+ unsigned long text_start ;
184151 int ret = 0 ;
185152
186- static const struct vm_special_mapping vdso_mapping = {
187- .name = "[vdso]" ,
188- .fault = vdso_fault ,
189- .mremap = vdso_mremap ,
190- };
191- static const struct vm_special_mapping vvar_mapping = {
192- .name = "[vvar]" ,
193- .fault = vvar_fault ,
194- };
195-
196- if (calculate_addr ) {
197- addr = vdso_addr (current -> mm -> start_stack ,
198- image -> size - image -> sym_vvar_start );
199- } else {
200- addr = 0 ;
201- }
202-
203153 if (down_write_killable (& mm -> mmap_sem ))
204154 return - EINTR ;
205155
@@ -238,24 +188,104 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
238188
239189 if (IS_ERR (vma )) {
240190 ret = PTR_ERR (vma );
241- goto up_fail ;
191+ do_munmap ( mm , text_start , image -> size ) ;
242192 }
243193
244194up_fail :
245- if (ret )
195+ if (ret ) {
246196 current -> mm -> context .vdso = NULL ;
197+ current -> mm -> context .vdso_image = NULL ;
198+ }
247199
248200 up_write (& mm -> mmap_sem );
249201 return ret ;
250202}
251203
204+ #ifdef CONFIG_X86_64
205+ /*
206+ * Put the vdso above the (randomized) stack with another randomized
207+ * offset. This way there is no hole in the middle of address space.
208+ * To save memory make sure it is still in the same PTE as the stack
209+ * top. This doesn't give that many random bits.
210+ *
211+ * Note that this algorithm is imperfect: the distribution of the vdso
212+ * start address within a PMD is biased toward the end.
213+ *
214+ * Only used for the 64-bit and x32 vdsos.
215+ */
216+ static unsigned long vdso_addr (unsigned long start , unsigned len )
217+ {
218+ unsigned long addr , end ;
219+ unsigned offset ;
220+
221+ /*
222+ * Round up the start address. It can start out unaligned as a result
223+ * of stack start randomization.
224+ */
225+ start = PAGE_ALIGN (start );
226+
227+ /* Round the lowest possible end address up to a PMD boundary. */
228+ end = (start + len + PMD_SIZE - 1 ) & PMD_MASK ;
229+ if (end >= TASK_SIZE_MAX )
230+ end = TASK_SIZE_MAX ;
231+ end -= len ;
232+
233+ if (end > start ) {
234+ offset = get_random_int () % (((end - start ) >> PAGE_SHIFT ) + 1 );
235+ addr = start + (offset << PAGE_SHIFT );
236+ } else {
237+ addr = start ;
238+ }
239+
240+ /*
241+ * Forcibly align the final address in case we have a hardware
242+ * issue that requires alignment for performance reasons.
243+ */
244+ addr = align_vdso_addr (addr );
245+
246+ return addr ;
247+ }
248+
249+ static int map_vdso_randomized (const struct vdso_image * image )
250+ {
251+ unsigned long addr = vdso_addr (current -> mm -> start_stack , image -> size - image -> sym_vvar_start );
252+
253+ return map_vdso (image , addr );
254+ }
255+ #endif
256+
257+ int map_vdso_once (const struct vdso_image * image , unsigned long addr )
258+ {
259+ struct mm_struct * mm = current -> mm ;
260+ struct vm_area_struct * vma ;
261+
262+ down_write (& mm -> mmap_sem );
263+ /*
264+ * Check if we have already mapped vdso blob - fail to prevent
265+ * abusing from userspace install_speciall_mapping, which may
266+ * not do accounting and rlimit right.
267+ * We could search vma near context.vdso, but it's a slowpath,
268+ * so let's explicitely check all VMAs to be completely sure.
269+ */
270+ for (vma = mm -> mmap ; vma ; vma = vma -> vm_next ) {
271+ if (vma_is_special_mapping (vma , & vdso_mapping ) ||
272+ vma_is_special_mapping (vma , & vvar_mapping )) {
273+ up_write (& mm -> mmap_sem );
274+ return - EEXIST ;
275+ }
276+ }
277+ up_write (& mm -> mmap_sem );
278+
279+ return map_vdso (image , addr );
280+ }
281+
252282#if defined(CONFIG_X86_32 ) || defined(CONFIG_IA32_EMULATION )
253283static int load_vdso32 (void )
254284{
255285 if (vdso32_enabled != 1 ) /* Other values all mean "disabled" */
256286 return 0 ;
257287
258- return map_vdso (& vdso_image_32 , false );
288+ return map_vdso (& vdso_image_32 , 0 );
259289}
260290#endif
261291
@@ -265,7 +295,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
265295 if (!vdso64_enabled )
266296 return 0 ;
267297
268- return map_vdso (& vdso_image_64 , true );
298+ return map_vdso_randomized (& vdso_image_64 );
269299}
270300
271301#ifdef CONFIG_COMPAT
@@ -276,8 +306,7 @@ int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
276306 if (test_thread_flag (TIF_X32 )) {
277307 if (!vdso64_enabled )
278308 return 0 ;
279-
280- return map_vdso (& vdso_image_x32 , true);
309+ return map_vdso_randomized (& vdso_image_x32 );
281310 }
282311#endif
283312#ifdef CONFIG_IA32_EMULATION
0 commit comments