~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sparc/vdso/vma.c

Version: ~ [ linux-5.9-rc6 ] ~ [ linux-5.8.10 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.66 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.146 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.198 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.236 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.236 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Set up the VMAs to tell the VM about the vDSO.
  3  * Copyright 2007 Andi Kleen, SUSE Labs.
  4  * Subject to the GPL, v.2
  5  */
  6 
  7 /*
  8  * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
  9  */
 10 
 11 #include <linux/mm.h>
 12 #include <linux/err.h>
 13 #include <linux/sched.h>
 14 #include <linux/slab.h>
 15 #include <linux/init.h>
 16 #include <linux/linkage.h>
 17 #include <linux/random.h>
 18 #include <linux/elf.h>
 19 #include <asm/vdso.h>
 20 #include <asm/vvar.h>
 21 #include <asm/page.h>
 22 
 23 unsigned int __read_mostly vdso_enabled = 1;
 24 
 25 static struct vm_special_mapping vvar_mapping = {
 26         .name = "[vvar]"
 27 };
 28 
 29 #ifdef  CONFIG_SPARC64
 30 static struct vm_special_mapping vdso_mapping64 = {
 31         .name = "[vdso]"
 32 };
 33 #endif
 34 
 35 #ifdef CONFIG_COMPAT
 36 static struct vm_special_mapping vdso_mapping32 = {
 37         .name = "[vdso]"
 38 };
 39 #endif
 40 
 41 struct vvar_data *vvar_data;
 42 
 43 #define SAVE_INSTR_SIZE 4
 44 
 45 /*
 46  * Allocate pages for the vdso and vvar, and copy in the vdso text from the
 47  * kernel image.
 48  */
 49 int __init init_vdso_image(const struct vdso_image *image,
 50                 struct vm_special_mapping *vdso_mapping)
 51 {
 52         int i;
 53         struct page *dp, **dpp = NULL;
 54         int dnpages = 0;
 55         struct page *cp, **cpp = NULL;
 56         int cnpages = (image->size) / PAGE_SIZE;
 57 
 58         /*
 59          * First, the vdso text.  This is initialied data, an integral number of
 60          * pages long.
 61          */
 62         if (WARN_ON(image->size % PAGE_SIZE != 0))
 63                 goto oom;
 64 
 65         cpp = kcalloc(cnpages, sizeof(struct page *), GFP_KERNEL);
 66         vdso_mapping->pages = cpp;
 67 
 68         if (!cpp)
 69                 goto oom;
 70 
 71         if (vdso_fix_stick) {
 72                 /*
 73                  * If the system uses %tick instead of %stick, patch the VDSO
 74                  * with instruction reading %tick instead of %stick.
 75                  */
 76                 unsigned int j, k = SAVE_INSTR_SIZE;
 77                 unsigned char *data = image->data;
 78 
 79                 for (j = image->sym_vread_tick_patch_start;
 80                      j < image->sym_vread_tick_patch_end; j++) {
 81 
 82                         data[image->sym_vread_tick + k] = data[j];
 83                         k++;
 84                 }
 85         }
 86 
 87         for (i = 0; i < cnpages; i++) {
 88                 cp = alloc_page(GFP_KERNEL);
 89                 if (!cp)
 90                         goto oom;
 91                 cpp[i] = cp;
 92                 copy_page(page_address(cp), image->data + i * PAGE_SIZE);
 93         }
 94 
 95         /*
 96          * Now the vvar page.  This is uninitialized data.
 97          */
 98 
 99         if (vvar_data == NULL) {
100                 dnpages = (sizeof(struct vvar_data) / PAGE_SIZE) + 1;
101                 if (WARN_ON(dnpages != 1))
102                         goto oom;
103                 dpp = kcalloc(dnpages, sizeof(struct page *), GFP_KERNEL);
104                 vvar_mapping.pages = dpp;
105 
106                 if (!dpp)
107                         goto oom;
108 
109                 dp = alloc_page(GFP_KERNEL);
110                 if (!dp)
111                         goto oom;
112 
113                 dpp[0] = dp;
114                 vvar_data = page_address(dp);
115                 memset(vvar_data, 0, PAGE_SIZE);
116 
117                 vvar_data->seq = 0;
118         }
119 
120         return 0;
121  oom:
122         if (cpp != NULL) {
123                 for (i = 0; i < cnpages; i++) {
124                         if (cpp[i] != NULL)
125                                 __free_page(cpp[i]);
126                 }
127                 kfree(cpp);
128                 vdso_mapping->pages = NULL;
129         }
130 
131         if (dpp != NULL) {
132                 for (i = 0; i < dnpages; i++) {
133                         if (dpp[i] != NULL)
134                                 __free_page(dpp[i]);
135                 }
136                 kfree(dpp);
137                 vvar_mapping.pages = NULL;
138         }
139 
140         pr_warn("Cannot allocate vdso\n");
141         vdso_enabled = 0;
142         return -ENOMEM;
143 }
144 
145 static int __init init_vdso(void)
146 {
147         int err = 0;
148 #ifdef CONFIG_SPARC64
149         err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64);
150         if (err)
151                 return err;
152 #endif
153 
154 #ifdef CONFIG_COMPAT
155         err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32);
156 #endif
157         return err;
158 
159 }
160 subsys_initcall(init_vdso);
161 
162 struct linux_binprm;
163 
164 /* Shuffle the vdso up a bit, randomly. */
165 static unsigned long vdso_addr(unsigned long start, unsigned int len)
166 {
167         unsigned int offset;
168 
169         /* This loses some more bits than a modulo, but is cheaper */
170         offset = get_random_int() & (PTRS_PER_PTE - 1);
171         return start + (offset << PAGE_SHIFT);
172 }
173 
174 static int map_vdso(const struct vdso_image *image,
175                 struct vm_special_mapping *vdso_mapping)
176 {
177         struct mm_struct *mm = current->mm;
178         struct vm_area_struct *vma;
179         unsigned long text_start, addr = 0;
180         int ret = 0;
181 
182         down_write(&mm->mmap_sem);
183 
184         /*
185          * First, get an unmapped region: then randomize it, and make sure that
186          * region is free.
187          */
188         if (current->flags & PF_RANDOMIZE) {
189                 addr = get_unmapped_area(NULL, 0,
190                                          image->size - image->sym_vvar_start,
191                                          0, 0);
192                 if (IS_ERR_VALUE(addr)) {
193                         ret = addr;
194                         goto up_fail;
195                 }
196                 addr = vdso_addr(addr, image->size - image->sym_vvar_start);
197         }
198         addr = get_unmapped_area(NULL, addr,
199                                  image->size - image->sym_vvar_start, 0, 0);
200         if (IS_ERR_VALUE(addr)) {
201                 ret = addr;
202                 goto up_fail;
203         }
204 
205         text_start = addr - image->sym_vvar_start;
206         current->mm->context.vdso = (void __user *)text_start;
207 
208         /*
209          * MAYWRITE to allow gdb to COW and set breakpoints
210          */
211         vma = _install_special_mapping(mm,
212                                        text_start,
213                                        image->size,
214                                        VM_READ|VM_EXEC|
215                                        VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
216                                        vdso_mapping);
217 
218         if (IS_ERR(vma)) {
219                 ret = PTR_ERR(vma);
220                 goto up_fail;
221         }
222 
223         vma = _install_special_mapping(mm,
224                                        addr,
225                                        -image->sym_vvar_start,
226                                        VM_READ|VM_MAYREAD,
227                                        &vvar_mapping);
228 
229         if (IS_ERR(vma)) {
230                 ret = PTR_ERR(vma);
231                 do_munmap(mm, text_start, image->size, NULL);
232         }
233 
234 up_fail:
235         if (ret)
236                 current->mm->context.vdso = NULL;
237 
238         up_write(&mm->mmap_sem);
239         return ret;
240 }
241 
242 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
243 {
244 
245         if (!vdso_enabled)
246                 return 0;
247 
248 #if defined CONFIG_COMPAT
249         if (!(is_32bit_task()))
250                 return map_vdso(&vdso_image_64_builtin, &vdso_mapping64);
251         else
252                 return map_vdso(&vdso_image_32_builtin, &vdso_mapping32);
253 #else
254         return map_vdso(&vdso_image_64_builtin, &vdso_mapping64);
255 #endif
256 
257 }
258 
259 static __init int vdso_setup(char *s)
260 {
261         int err;
262         unsigned long val;
263 
264         err = kstrtoul(s, 10, &val);
265         vdso_enabled = val;
266         return err;
267 }
268 __setup("vdso=", vdso_setup);
269 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp