]>
Commit | Line | Data |
---|---|---|
3d208c1f AM |
1 | --- linux/drivers/char/drm/ffb_drv.c.orig |
2 | +++ linux/drivers/char/drm/ffb_drv.c | |
3 | @@ -285,19 +285,19 @@ static unsigned long ffb_get_unmapped_ar | |
4 | unsigned long addr = -ENOMEM; | |
5 | ||
6 | if (!map) | |
7 | - return get_unmapped_area(NULL, hint, len, pgoff, flags); | |
8 | + return get_unmapped_area(NULL, hint, len, pgoff, flags, 0); | |
9 | ||
10 | if (map->type == _DRM_FRAME_BUFFER || | |
11 | map->type == _DRM_REGISTERS) { | |
12 | #ifdef HAVE_ARCH_FB_UNMAPPED_AREA | |
13 | addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags); | |
14 | #else | |
15 | - addr = get_unmapped_area(NULL, hint, len, pgoff, flags); | |
16 | + addr = get_unmapped_area(NULL, hint, len, pgoff, flags, 0); | |
17 | #endif | |
18 | } else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) { | |
19 | unsigned long slack = SHMLBA - PAGE_SIZE; | |
20 | ||
21 | - addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags); | |
22 | + addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags, 0); | |
23 | if (!(addr & ~PAGE_MASK)) { | |
24 | unsigned long kvirt = (unsigned long) map->handle; | |
25 | ||
26 | @@ -313,7 +313,7 @@ static unsigned long ffb_get_unmapped_ar | |
27 | } | |
28 | } | |
29 | } else { | |
30 | - addr = get_unmapped_area(NULL, hint, len, pgoff, flags); | |
31 | + addr = get_unmapped_area(NULL, hint, len, pgoff, flags, 0); | |
32 | } | |
33 | ||
34 | return addr; | |
35 | --- linux/arch/sparc64/kernel/sys_sparc.c.orig | |
36 | +++ linux/arch/sparc64/kernel/sys_sparc.c | |
37 | @@ -127,7 +127,7 @@ unsigned long get_fb_unmapped_area(struc | |
38 | ||
39 | if (flags & MAP_FIXED) { | |
40 | /* Ok, don't mess with it. */ | |
41 | - return get_unmapped_area(NULL, addr, len, pgoff, flags); | |
42 | + return get_unmapped_area(NULL, addr, len, pgoff, flags, 0); | |
43 | } | |
44 | flags &= ~MAP_SHARED; | |
45 | ||
46 | @@ -140,7 +140,7 @@ unsigned long get_fb_unmapped_area(struc | |
47 | align_goal = (64UL * 1024); | |
48 | ||
49 | do { | |
50 | - addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); | |
51 | + addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags, 0); | |
52 | if (!(addr & ~PAGE_MASK)) { | |
53 | addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL); | |
54 | break; | |
55 | @@ -158,7 +158,7 @@ unsigned long get_fb_unmapped_area(struc | |
56 | * be obtained. | |
57 | */ | |
58 | if (addr & ~PAGE_MASK) | |
59 | - addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags); | |
60 | + addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags, 0); | |
61 | ||
62 | return addr; | |
63 | } | |
64 | @@ -402,7 +402,7 @@ asmlinkage unsigned long sys64_mremap(un | |
65 | /* MREMAP_FIXED checked above. */ | |
66 | new_addr = get_unmapped_area(file, addr, new_len, | |
67 | vma ? vma->vm_pgoff : 0, | |
68 | - map_flags); | |
69 | + map_flags, vma->vm_flags & VM_EXEC); | |
70 | ret = new_addr; | |
71 | if (new_addr & ~PAGE_MASK) | |
72 | goto out_sem; | |
73 | --- linux/arch/sparc64/kernel/sys_sparc32.c.orig | |
74 | +++ linux/arch/sparc64/kernel/sys_sparc32.c | |
75 | @@ -1750,7 +1750,7 @@ asmlinkage unsigned long sys32_mremap(un | |
76 | /* MREMAP_FIXED checked above. */ | |
77 | new_addr = get_unmapped_area(file, addr, new_len, | |
78 | vma ? vma->vm_pgoff : 0, | |
79 | - map_flags); | |
80 | + map_flags, vma->vm_flags & VM_EXEC); | |
81 | ret = new_addr; | |
82 | if (new_addr & ~PAGE_MASK) | |
83 | goto out_sem; | |
84 | --- linux/arch/i386/kernel/cpu/proc.c.orig | |
85 | +++ linux/arch/i386/kernel/cpu/proc.c | |
86 | @@ -27,7 +27,7 @@ static int show_cpuinfo(struct seq_file | |
87 | /* AMD-defined */ | |
88 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | |
89 | NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, | |
90 | - NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL, | |
91 | + NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL, | |
92 | NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow", | |
93 | ||
94 | /* Transmeta-defined */ | |
95 | --- linux/arch/i386/kernel/asm-offsets.c.orig | |
96 | +++ linux/arch/i386/kernel/asm-offsets.c | |
97 | @@ -52,6 +52,7 @@ void foo(void) | |
98 | OFFSET(TI_preempt_count, thread_info, preempt_count); | |
99 | OFFSET(TI_addr_limit, thread_info, addr_limit); | |
100 | OFFSET(TI_restart_block, thread_info, restart_block); | |
101 | + OFFSET(TI_sysenter_return, thread_info, sysenter_return); | |
102 | BLANK(); | |
103 | ||
104 | OFFSET(EXEC_DOMAIN_handler, exec_domain, handler); | |
105 | --- linux/arch/i386/kernel/entry.S.orig | |
106 | +++ linux/arch/i386/kernel/entry.S | |
107 | @@ -238,8 +238,12 @@ sysenter_past_esp: | |
108 | pushl %ebp | |
109 | pushfl | |
110 | pushl $(__USER_CS) | |
111 | - pushl $SYSENTER_RETURN | |
112 | - | |
113 | + /* | |
114 | + * Push current_thread_info()->sysenter_return to the stack. | |
115 | + * A tiny bit of offset fixup is necessary - 4*4 means the 4 words | |
116 | + * pushed above, and the word being pushed now: | |
117 | + */ | |
118 | + pushl (TI_sysenter_return-THREAD_SIZE+4*4)(%esp) | |
119 | /* | |
120 | * Load the potential sixth argument from user stack. | |
121 | * Careful about security. | |
122 | --- linux/arch/i386/kernel/head.S.orig | |
123 | +++ linux/arch/i386/kernel/head.S | |
124 | @@ -153,6 +153,32 @@ ENTRY(startup_32_smp) | |
125 | orl %edx,%eax | |
126 | movl %eax,%cr4 | |
127 | ||
128 | + btl $5, %eax # check if PAE is enabled | |
129 | + jnc 6f | |
130 | + | |
131 | + /* Check if extended functions are implemented */ | |
132 | + movl $0x80000000, %eax | |
133 | + cpuid | |
134 | + cmpl $0x80000000, %eax | |
135 | + jbe 6f | |
136 | + mov $0x80000001, %eax | |
137 | + cpuid | |
138 | + /* Execute Disable bit supported? */ | |
139 | + btl $20, %edx | |
140 | + jnc 6f | |
141 | + | |
142 | + /* Setup EFER (Extended Feature Enable Register) */ | |
143 | + movl $0xc0000080, %ecx | |
144 | + rdmsr | |
145 | + | |
146 | + btsl $11, %eax | |
147 | + /* Make changes effective */ | |
148 | + wrmsr | |
149 | + | |
150 | +6: | |
151 | + /* cpuid clobbered ebx, set it up again: */ | |
152 | + xorl %ebx,%ebx | |
153 | + incl %ebx | |
154 | 3: | |
155 | #endif /* CONFIG_SMP */ | |
156 | ||
157 | --- linux/arch/i386/kernel/module.c.orig | |
158 | +++ linux/arch/i386/kernel/module.c | |
159 | @@ -32,7 +32,7 @@ void *module_alloc(unsigned long size) | |
160 | { | |
161 | if (size == 0) | |
162 | return NULL; | |
163 | - return vmalloc(size); | |
164 | + return vmalloc_exec(size); | |
165 | } | |
166 | ||
167 | ||
168 | --- linux/arch/i386/kernel/process.c.orig | |
169 | +++ linux/arch/i386/kernel/process.c | |
170 | @@ -36,6 +36,8 @@ | |
171 | #include <linux/module.h> | |
172 | #include <linux/kallsyms.h> | |
173 | #include <linux/ptrace.h> | |
174 | +#include <linux/mman.h> | |
175 | +#include <linux/random.h> | |
176 | ||
177 | #include <asm/uaccess.h> | |
178 | #include <asm/pgtable.h> | |
179 | @@ -512,6 +514,8 @@ struct task_struct fastcall * __switch_t | |
180 | /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ | |
181 | ||
182 | __unlazy_fpu(prev_p); | |
183 | + if (next_p->mm) | |
184 | + load_user_cs_desc(cpu, next_p->mm); | |
185 | ||
186 | /* | |
187 | * Reload esp0, LDT and the page table pointer: | |
188 | @@ -776,3 +780,303 @@ asmlinkage int sys_get_thread_area(struc | |
189 | return 0; | |
190 | } | |
191 | ||
192 | +/* | |
193 | + * Get a random word: | |
194 | + */ | |
195 | +static inline unsigned int get_random_int(void) | |
196 | +{ | |
197 | + unsigned int val = 0; | |
198 | + | |
199 | + if (!exec_shield_randomize) | |
200 | + return 0; | |
201 | + | |
202 | +#ifdef CONFIG_X86_HAS_TSC | |
203 | + rdtscl(val); | |
204 | +#endif | |
205 | + val += current->pid + jiffies + (int)&val; | |
206 | + | |
207 | + /* | |
208 | + * Use IP's RNG. It suits our purpose perfectly: it re-keys itself | |
209 | + * every second, from the entropy pool (and thus creates a limited | |
210 | + * drain on it), and uses halfMD4Transform within the second. We | |
211 | + * also spice it with the TSC (if available), jiffies, PID and the | |
212 | + * stack address: | |
213 | + */ | |
214 | + return secure_ip_id(val); | |
215 | +} | |
216 | + | |
217 | +unsigned long arch_align_stack(unsigned long sp) | |
218 | +{ | |
219 | + if (current->mm && !(current->mm->def_flags & VM_EXEC)) | |
220 | + sp -= ((get_random_int() % 65536) << 4); | |
221 | + return sp & ~0xf; | |
222 | +} | |
223 | + | |
224 | +#if SHLIB_BASE >= 0x01000000 | |
225 | +# error SHLIB_BASE must be under 16MB! | |
226 | +#endif | |
227 | + | |
228 | +static unsigned long | |
229 | +arch_get_unmapped_nonexecutable_area(struct mm_struct *mm, unsigned long addr, unsigned long len) | |
230 | +{ | |
231 | + struct vm_area_struct *vma, *prev_vma; | |
232 | + unsigned long stack_limit; | |
233 | + int first_time = 1; | |
234 | + | |
235 | + if (!mm->mmap_top) { | |
236 | + printk("hm, %s:%d, !mmap_top.\n", current->comm, current->pid); | |
237 | + mm->mmap_top = mmap_top(); | |
238 | + } | |
239 | + stack_limit = mm->mmap_top; | |
240 | + | |
241 | + /* requested length too big for entire address space */ | |
242 | + if (len > TASK_SIZE) | |
243 | + return -ENOMEM; | |
244 | + | |
245 | + /* dont allow allocations above current stack limit */ | |
246 | + if (mm->non_executable_cache > stack_limit) | |
247 | + mm->non_executable_cache = stack_limit; | |
248 | + | |
249 | + /* requesting a specific address */ | |
250 | + if (addr) { | |
251 | + addr = PAGE_ALIGN(addr); | |
252 | + vma = find_vma(mm, addr); | |
253 | + if (TASK_SIZE - len >= addr && | |
254 | + (!vma || addr + len <= vma->vm_start)) | |
255 | + return addr; | |
256 | + } | |
257 | + | |
258 | + /* make sure it can fit in the remaining address space */ | |
259 | + if (mm->non_executable_cache < len) | |
260 | + return -ENOMEM; | |
261 | + | |
262 | + /* either no address requested or cant fit in requested address hole */ | |
263 | +try_again: | |
264 | + addr = (mm->non_executable_cache - len)&PAGE_MASK; | |
265 | + do { | |
266 | + if (!(vma = find_vma_prev(mm, addr, &prev_vma))) | |
267 | + return -ENOMEM; | |
268 | + | |
269 | + /* new region fits between prev_vma->vm_end and vma->vm_start, use it */ | |
270 | + if (addr+len <= vma->vm_start && (!prev_vma || (addr >= prev_vma->vm_end))) { | |
271 | + /* remember the address as a hint for next time */ | |
272 | + mm->non_executable_cache = addr; | |
273 | + return addr; | |
274 | + | |
275 | + /* pull non_executable_cache down to the first hole */ | |
276 | + } else if (mm->non_executable_cache == vma->vm_end) | |
277 | + mm->non_executable_cache = vma->vm_start; | |
278 | + | |
279 | + /* try just below the current vma->vm_start */ | |
280 | + addr = vma->vm_start-len; | |
281 | + } while (len <= vma->vm_start); | |
282 | + /* if hint left us with no space for the requested mapping try again */ | |
283 | + if (first_time) { | |
284 | + first_time = 0; | |
285 | + mm->non_executable_cache = stack_limit; | |
286 | + goto try_again; | |
287 | + } | |
288 | + return -ENOMEM; | |
289 | +} | |
290 | + | |
291 | +static unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len) | |
292 | +{ | |
293 | + unsigned long range = end - len - start; | |
294 | + if (end <= start + len) | |
295 | + return 0; | |
296 | + return PAGE_ALIGN(get_random_int() % range + start); | |
297 | +} | |
298 | + | |
299 | +static inline unsigned long | |
300 | +stock_arch_get_unmapped_area(struct file *filp, unsigned long addr, | |
301 | + unsigned long len, unsigned long pgoff, unsigned long flags) | |
302 | +{ | |
303 | + struct mm_struct *mm = current->mm; | |
304 | + struct vm_area_struct *vma; | |
305 | + unsigned long start_addr; | |
306 | + | |
307 | + if (len > TASK_SIZE) | |
308 | + return -ENOMEM; | |
309 | + | |
310 | + if (addr) { | |
311 | + addr = PAGE_ALIGN(addr); | |
312 | + vma = find_vma(mm, addr); | |
313 | + if (TASK_SIZE - len >= addr && | |
314 | + (!vma || addr + len <= vma->vm_start)) | |
315 | + return addr; | |
316 | + } | |
317 | + start_addr = addr = mm->free_area_cache; | |
318 | + | |
319 | +full_search: | |
320 | + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { | |
321 | + /* At this point: (!vma || addr < vma->vm_end). */ | |
322 | + if (TASK_SIZE - len < addr) { | |
323 | + /* | |
324 | + * Start a new search - just in case we missed | |
325 | + * some holes. | |
326 | + */ | |
327 | + if (start_addr != TASK_UNMAPPED_BASE) { | |
328 | + start_addr = addr = TASK_UNMAPPED_BASE; | |
329 | + goto full_search; | |
330 | + } | |
331 | + return -ENOMEM; | |
332 | + } | |
333 | + if (!vma || addr + len <= vma->vm_start) { | |
334 | + /* | |
335 | + * Remember the place where we stopped the search: | |
336 | + */ | |
337 | + mm->free_area_cache = addr + len; | |
338 | + return addr; | |
339 | + } | |
340 | + addr = vma->vm_end; | |
341 | + } | |
342 | +} | |
343 | + | |
344 | +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr0, | |
345 | + unsigned long len0, unsigned long pgoff, unsigned long flags, | |
346 | + unsigned long prot) | |
347 | +{ | |
348 | + unsigned long addr = addr0, len = len0; | |
349 | + struct mm_struct *mm = current->mm; | |
350 | + struct vm_area_struct *vma; | |
351 | + int ascii_shield = 0; | |
352 | + unsigned long tmp; | |
353 | + | |
354 | + /* | |
355 | + * Fall back to the old layout: | |
356 | + */ | |
357 | + if (current->mm->def_flags & VM_EXEC) | |
358 | + return stock_arch_get_unmapped_area(filp, addr0, len0, pgoff, flags); | |
359 | + if (len > TASK_SIZE) | |
360 | + return -ENOMEM; | |
361 | + | |
362 | + if (!addr && (prot & PROT_EXEC) && !(flags & MAP_FIXED)) | |
363 | + addr = randomize_range(SHLIB_BASE, 0x01000000, len); | |
364 | + | |
365 | + if (addr) { | |
366 | + addr = PAGE_ALIGN(addr); | |
367 | + vma = find_vma(mm, addr); | |
368 | + if (TASK_SIZE - len >= addr && | |
369 | + (!vma || addr + len <= vma->vm_start)) { | |
370 | + return addr; | |
371 | + } | |
372 | + } | |
373 | + | |
374 | + if (prot & PROT_EXEC) { | |
375 | + ascii_shield = 1; | |
376 | + addr = SHLIB_BASE; | |
377 | + } else { | |
378 | + /* this can fail if the stack was unlimited */ | |
379 | + if ((tmp = arch_get_unmapped_nonexecutable_area(mm, addr, len)) != -ENOMEM) | |
380 | + return tmp; | |
381 | +search_upper: | |
382 | + addr = PAGE_ALIGN(arch_align_stack(TASK_UNMAPPED_BASE)); | |
383 | + } | |
384 | + | |
385 | + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { | |
386 | + /* At this point: (!vma || addr < vma->vm_end). */ | |
387 | + if (TASK_SIZE - len < addr) { | |
388 | + return -ENOMEM; | |
389 | + } | |
390 | + if (!vma || addr + len <= vma->vm_start) { | |
391 | + /* | |
392 | + * Must not let a PROT_EXEC mapping get into the | |
393 | + * brk area: | |
394 | + */ | |
395 | + if (ascii_shield && (addr + len > mm->brk)) { | |
396 | + ascii_shield = 0; | |
397 | + goto search_upper; | |
398 | + } | |
399 | + /* | |
400 | + * Up until the brk area we randomize addresses | |
401 | + * as much as possible: | |
402 | + */ | |
403 | + if (ascii_shield && (addr >= 0x01000000)) { | |
404 | + tmp = randomize_range(0x01000000, mm->brk, len); | |
405 | + vma = find_vma(mm, tmp); | |
406 | + if (TASK_SIZE - len >= tmp && | |
407 | + (!vma || tmp + len <= vma->vm_start)) | |
408 | + return tmp; | |
409 | + } | |
410 | + /* | |
411 | + * Ok, randomization didnt work out - return | |
412 | + * the result of the linear search: | |
413 | + */ | |
414 | + return addr; | |
415 | + } | |
416 | + addr = vma->vm_end; | |
417 | + } | |
418 | +} | |
419 | + | |
420 | +void arch_add_exec_range(struct mm_struct *mm, unsigned long limit) | |
421 | +{ | |
422 | + if (limit > mm->context.exec_limit) { | |
423 | + mm->context.exec_limit = limit; | |
424 | + set_user_cs(&mm->context.user_cs, limit); | |
425 | + if (mm == current->mm) | |
426 | + load_user_cs_desc(smp_processor_id(), mm); | |
427 | + } | |
428 | +} | |
429 | + | |
430 | +void arch_remove_exec_range(struct mm_struct *mm, unsigned long old_end) | |
431 | +{ | |
432 | + struct vm_area_struct *vma; | |
433 | + unsigned long limit = 0; | |
434 | + | |
435 | + if (old_end == mm->context.exec_limit) { | |
436 | + for (vma = mm->mmap; vma; vma = vma->vm_next) | |
437 | + if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) | |
438 | + limit = vma->vm_end; | |
439 | + | |
440 | + mm->context.exec_limit = limit; | |
441 | + set_user_cs(&mm->context.user_cs, limit); | |
442 | + if (mm == current->mm) | |
443 | + load_user_cs_desc(smp_processor_id(), mm); | |
444 | + } | |
445 | +} | |
446 | + | |
447 | +void arch_flush_exec_range(struct mm_struct *mm) | |
448 | +{ | |
449 | + mm->context.exec_limit = 0; | |
450 | + set_user_cs(&mm->context.user_cs, 0); | |
451 | +} | |
452 | + | |
453 | +/* | |
454 | + * Generate random brk address between 128MB and 196MB. (if the layout | |
455 | + * allows it.) | |
456 | + */ | |
457 | +void randomize_brk(unsigned long old_brk) | |
458 | +{ | |
459 | + unsigned long new_brk, range_start, range_end; | |
460 | + | |
461 | + range_start = 0x08000000; | |
462 | + if (current->mm->brk >= range_start) | |
463 | + range_start = current->mm->brk; | |
464 | + range_end = range_start + 0x02000000; | |
465 | + new_brk = randomize_range(range_start, range_end, 0); | |
466 | + if (new_brk) | |
467 | + current->mm->brk = new_brk; | |
468 | +} | |
469 | + | |
470 | +/* | |
471 | + * Top of mmap area (just below the process stack). | |
472 | + * leave an at least ~128 MB hole. Randomize it. | |
473 | + */ | |
474 | +#define MIN_GAP (128*1024*1024) | |
475 | +#define MAX_GAP (TASK_SIZE/6*5) | |
476 | + | |
477 | +unsigned long mmap_top(void) | |
478 | +{ | |
479 | + unsigned long gap = 0; | |
480 | + | |
481 | + gap = current->rlim[RLIMIT_STACK].rlim_cur; | |
482 | + if (gap < MIN_GAP) | |
483 | + gap = MIN_GAP; | |
484 | + else if (gap > MAX_GAP) | |
485 | + gap = MAX_GAP; | |
486 | + | |
487 | + gap = arch_align_stack(gap) & PAGE_MASK; | |
488 | + | |
489 | + return TASK_SIZE - gap; | |
490 | +} | |
491 | + | |
492 | --- linux/arch/i386/kernel/signal.c.orig | |
493 | +++ linux/arch/i386/kernel/signal.c | |
494 | @@ -333,7 +333,7 @@ get_sigframe(struct k_sigaction *ka, str | |
495 | ||
496 | /* These symbols are defined with the addresses in the vsyscall page. | |
497 | See vsyscall-sigreturn.S. */ | |
498 | -extern void __kernel_sigreturn, __kernel_rt_sigreturn; | |
499 | +extern char __kernel_sigreturn, __kernel_rt_sigreturn, SYSENTER_RETURN; | |
500 | ||
501 | static void setup_frame(int sig, struct k_sigaction *ka, | |
502 | sigset_t *set, struct pt_regs * regs) | |
503 | @@ -367,7 +367,7 @@ static void setup_frame(int sig, struct | |
504 | if (err) | |
505 | goto give_sigsegv; | |
506 | ||
507 | - restorer = &__kernel_sigreturn; | |
508 | + restorer = current->mm->context.vdso + (long)&__kernel_sigreturn; | |
509 | if (ka->sa.sa_flags & SA_RESTORER) | |
510 | restorer = ka->sa.sa_restorer; | |
511 | ||
512 | @@ -450,9 +450,10 @@ static void setup_rt_frame(int sig, stru | |
513 | goto give_sigsegv; | |
514 | ||
515 | /* Set up to return from userspace. */ | |
516 | - restorer = &__kernel_rt_sigreturn; | |
517 | + restorer = current->mm->context.vdso + (long)&__kernel_rt_sigreturn; | |
518 | if (ka->sa.sa_flags & SA_RESTORER) | |
519 | restorer = ka->sa.sa_restorer; | |
520 | + | |
521 | err |= __put_user(restorer, &frame->pretcode); | |
522 | ||
523 | /* | |
524 | --- linux/arch/i386/kernel/sysenter.c.orig | |
525 | +++ linux/arch/i386/kernel/sysenter.c | |
526 | @@ -13,6 +13,7 @@ | |
527 | #include <linux/gfp.h> | |
528 | #include <linux/string.h> | |
529 | #include <linux/elf.h> | |
530 | +#include <linux/mman.h> | |
531 | ||
532 | #include <asm/cpufeature.h> | |
533 | #include <asm/msr.h> | |
534 | @@ -41,11 +42,14 @@ void enable_sep_cpu(void *info) | |
535 | extern const char vsyscall_int80_start, vsyscall_int80_end; | |
536 | extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; | |
537 | ||
538 | +struct page *sysenter_page; | |
539 | + | |
540 | static int __init sysenter_setup(void) | |
541 | { | |
542 | unsigned long page = get_zeroed_page(GFP_ATOMIC); | |
543 | ||
544 | - __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY); | |
545 | + __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_KERNEL_RO); | |
546 | + sysenter_page = virt_to_page(page); | |
547 | ||
548 | if (!boot_cpu_has(X86_FEATURE_SEP)) { | |
549 | memcpy((void *) page, | |
550 | @@ -59,7 +63,51 @@ static int __init sysenter_setup(void) | |
551 | &vsyscall_sysenter_end - &vsyscall_sysenter_start); | |
552 | ||
553 | on_each_cpu(enable_sep_cpu, NULL, 1, 1); | |
554 | + | |
555 | return 0; | |
556 | } | |
557 | ||
558 | __initcall(sysenter_setup); | |
559 | + | |
560 | +extern void SYSENTER_RETURN_OFFSET; | |
561 | + | |
562 | +unsigned int vdso_enabled = 1; | |
563 | + | |
564 | +void map_vsyscall(void) | |
565 | +{ | |
566 | + struct thread_info *ti = current_thread_info(); | |
567 | + struct vm_area_struct *vma; | |
568 | + unsigned long addr; | |
569 | + | |
570 | + if (unlikely(!vdso_enabled)) { | |
571 | + current->mm->context.vdso = NULL; | |
572 | + return; | |
573 | + } | |
574 | + | |
575 | + /* | |
576 | + * Map the vDSO (it will be randomized): | |
577 | + */ | |
578 | + down_write(¤t->mm->mmap_sem); | |
579 | + addr = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, 0); | |
580 | + current->mm->context.vdso = (void *)addr; | |
581 | + ti->sysenter_return = (void *)addr + (long)&SYSENTER_RETURN_OFFSET; | |
582 | + if (addr != -1) { | |
583 | + vma = find_vma(current->mm, addr); | |
584 | + if (vma) { | |
585 | + pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; | |
586 | + get_page(sysenter_page); | |
587 | + install_page(current->mm, vma, addr, | |
588 | + sysenter_page, vma->vm_page_prot); | |
589 | + | |
590 | + } | |
591 | + } | |
592 | + up_write(¤t->mm->mmap_sem); | |
593 | +} | |
594 | + | |
595 | +static int __init vdso_setup(char *str) | |
596 | +{ | |
597 | + vdso_enabled = simple_strtoul(str, NULL, 0); | |
598 | + return 1; | |
599 | +} | |
600 | +__setup("vdso=", vdso_setup); | |
601 | + | |
602 | --- linux/arch/i386/kernel/traps.c.orig | |
603 | +++ linux/arch/i386/kernel/traps.c | |
604 | @@ -428,6 +428,10 @@ DO_ERROR(11, SIGBUS, "segment not prese | |
605 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | |
606 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) | |
607 | ||
608 | +/* | |
609 | + * the original non-exec stack patch was written by | |
610 | + * Solar Designer <solar at openwall.com>. Thanks! | |
611 | + */ | |
612 | asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) | |
613 | { | |
614 | if (regs->eflags & X86_EFLAGS_IF) | |
615 | @@ -439,6 +443,46 @@ asmlinkage void do_general_protection(st | |
616 | if (!(regs->xcs & 3)) | |
617 | goto gp_in_kernel; | |
618 | ||
619 | + /* | |
620 | + * lazy-check for CS validity on exec-shield binaries: | |
621 | + */ | |
622 | + if (current->mm) { | |
623 | + int cpu = smp_processor_id(); | |
624 | + struct desc_struct *desc1, *desc2; | |
625 | + struct vm_area_struct *vma; | |
626 | + unsigned long limit = 0; | |
627 | + | |
628 | + spin_lock(¤t->mm->page_table_lock); | |
629 | + for (vma = current->mm->mmap; vma; vma = vma->vm_next) | |
630 | + if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) | |
631 | + limit = vma->vm_end; | |
632 | + spin_unlock(¤t->mm->page_table_lock); | |
633 | + | |
634 | + current->mm->context.exec_limit = limit; | |
635 | + set_user_cs(¤t->mm->context.user_cs, limit); | |
636 | + | |
637 | + desc1 = ¤t->mm->context.user_cs; | |
638 | + desc2 = cpu_gdt_table[cpu] + GDT_ENTRY_DEFAULT_USER_CS; | |
639 | + | |
640 | + /* | |
641 | + * The CS was not in sync - reload it and retry the | |
642 | + * instruction. If the instruction still faults then | |
643 | + * we wont hit this branch next time around. | |
644 | + */ | |
645 | + if (desc1->a != desc2->a || desc1->b != desc2->b) { | |
646 | + if (print_fatal_signals >= 2) { | |
647 | + printk("#GPF fixup (%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->eip, smp_processor_id()); | |
648 | + printk(" exec_limit: %08lx, user_cs: %08lx/%08lx, CPU_cs: %08lx/%08lx.\n", current->mm->context.exec_limit, desc1->a, desc1->b, desc2->a, desc2->b); | |
649 | + } | |
650 | + load_user_cs_desc(cpu, current->mm); | |
651 | + return; | |
652 | + } | |
653 | + } | |
654 | + if (print_fatal_signals) { | |
655 | + printk("#GPF(%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->eip, smp_processor_id()); | |
656 | + printk(" exec_limit: %08lx, user_cs: %08lx/%08lx.\n", current->mm->context.exec_limit, current->mm->context.user_cs.a, current->mm->context.user_cs.b); | |
657 | + } | |
658 | + | |
659 | current->thread.error_code = error_code; | |
660 | current->thread.trap_no = 13; | |
661 | force_sig(SIGSEGV, current); | |
662 | --- linux/arch/i386/kernel/vsyscall-sysenter.S.orig | |
663 | +++ linux/arch/i386/kernel/vsyscall-sysenter.S | |
664 | @@ -24,11 +24,11 @@ __kernel_vsyscall: | |
665 | /* 7: align return point with nop's to make disassembly easier */ | |
666 | .space 7,0x90 | |
667 | ||
668 | - /* 14: System call restart point is here! (SYSENTER_RETURN - 2) */ | |
669 | + /* 14: System call restart point is here! (SYSENTER_RETURN_OFFSET-2) */ | |
670 | jmp .Lenter_kernel | |
671 | /* 16: System call normal return point is here! */ | |
672 | - .globl SYSENTER_RETURN /* Symbol used by entry.S. */ | |
673 | -SYSENTER_RETURN: | |
674 | + .globl SYSENTER_RETURN_OFFSET /* Symbol used by sysenter.c */ | |
675 | +SYSENTER_RETURN_OFFSET: | |
676 | pop %ebp | |
677 | .Lpop_ebp: | |
678 | pop %edx | |
679 | --- linux/arch/i386/kernel/vsyscall.lds.orig | |
680 | +++ linux/arch/i386/kernel/vsyscall.lds | |
681 | @@ -1,15 +1,12 @@ | |
682 | /* | |
683 | * Linker script for vsyscall DSO. The vsyscall page is an ELF shared | |
684 | - * object prelinked to its virtual address, and with only one read-only | |
685 | - * segment (that fits in one page). This script controls its layout. | |
686 | + * object with only one read-only segment (that fits in one page). | |
687 | + * This script controls its layout. | |
688 | */ | |
689 | ||
690 | -/* This must match <asm/fixmap.h>. */ | |
691 | -VSYSCALL_BASE = 0xffffe000; | |
692 | - | |
693 | SECTIONS | |
694 | { | |
695 | - . = VSYSCALL_BASE + SIZEOF_HEADERS; | |
696 | + . = SIZEOF_HEADERS; | |
697 | ||
698 | .hash : { *(.hash) } :text | |
699 | .dynsym : { *(.dynsym) } | |
700 | @@ -22,7 +19,7 @@ SECTIONS | |
701 | For the layouts to match, we need to skip more than enough | |
702 | space for the dynamic symbol table et al. If this amount | |
703 | is insufficient, ld -shared will barf. Just increase it here. */ | |
704 | - . = VSYSCALL_BASE + 0x400; | |
705 | + . = 0x400; | |
706 | ||
707 | .text : { *(.text) } :text =0x90909090 | |
708 | ||
709 | --- linux/arch/i386/mm/fault.c.orig | |
710 | +++ linux/arch/i386/mm/fault.c | |
711 | @@ -405,6 +405,21 @@ no_context: | |
712 | ||
713 | bust_spinlocks(1); | |
714 | ||
715 | +#ifdef CONFIG_X86_PAE | |
716 | + { | |
717 | + pgd_t *pgd; | |
718 | + pmd_t *pmd; | |
719 | + | |
720 | + | |
721 | + | |
722 | + pgd = init_mm.pgd + pgd_index(address); | |
723 | + if (pgd_present(*pgd)) { | |
724 | + pmd = pmd_offset(pgd, address); | |
725 | + if (pmd_val(*pmd) & _PAGE_NX) | |
726 | + printk(KERN_CRIT "kernel tried to access NX-protected page - exploit attempt? (uid: %d)\n", current->uid); | |
727 | + } | |
728 | + } | |
729 | +#endif | |
730 | if (address < PAGE_SIZE) | |
731 | printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); | |
732 | else | |
733 | --- linux/arch/i386/mm/init.c.orig | |
734 | +++ linux/arch/i386/mm/init.c | |
735 | @@ -122,6 +122,13 @@ static void __init page_table_range_init | |
736 | } | |
737 | } | |
738 | ||
739 | +static inline int is_kernel_text(unsigned long addr) | |
740 | +{ | |
741 | + if (addr >= (unsigned long)_stext && addr <= (unsigned long)__init_end) | |
742 | + return 1; | |
743 | + return 0; | |
744 | +} | |
745 | + | |
746 | /* | |
747 | * This maps the physical memory to kernel virtual address space, a total | |
748 | * of max_low_pfn pages, by creating page tables starting from address | |
749 | @@ -144,18 +151,29 @@ static void __init kernel_physical_mappi | |
750 | if (pfn >= max_low_pfn) | |
751 | continue; | |
752 | for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { | |
753 | + unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET; | |
754 | + | |
755 | /* Map with big pages if possible, otherwise create normal page tables. */ | |
756 | if (cpu_has_pse) { | |
757 | - set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); | |
758 | + unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; | |
759 | + | |
760 | + if (is_kernel_text(address) || is_kernel_text(address2)) | |
761 | + set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); | |
762 | + else | |
763 | + set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); | |
764 | pfn += PTRS_PER_PTE; | |
765 | } else { | |
766 | pte = one_page_table_init(pmd); | |
767 | ||
768 | - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) | |
769 | - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); | |
770 | + for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) { | |
771 | + if (is_kernel_text(address)) | |
772 | + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); | |
773 | + else | |
774 | + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); | |
775 | + } | |
776 | } | |
777 | } | |
778 | - } | |
779 | + } | |
780 | } | |
781 | ||
782 | static inline int page_kills_ppro(unsigned long pagenr) | |
783 | @@ -272,7 +290,8 @@ extern void set_highmem_pages_init(int); | |
784 | #define set_highmem_pages_init(bad_ppro) do { } while (0) | |
785 | #endif /* CONFIG_HIGHMEM */ | |
786 | ||
787 | -unsigned long __PAGE_KERNEL = _PAGE_KERNEL; | |
788 | +unsigned long long __PAGE_KERNEL = _PAGE_KERNEL; | |
789 | +unsigned long long __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC; | |
790 | ||
791 | #ifndef CONFIG_DISCONTIGMEM | |
792 | #define remap_numa_kva() do {} while (0) | |
793 | @@ -301,6 +320,7 @@ static void __init pagetable_init (void) | |
794 | if (cpu_has_pge) { | |
795 | set_in_cr4(X86_CR4_PGE); | |
796 | __PAGE_KERNEL |= _PAGE_GLOBAL; | |
797 | + __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL; | |
798 | } | |
799 | ||
800 | kernel_physical_mapping_init(pgd_base); | |
801 | @@ -391,6 +411,53 @@ void __init zone_sizes_init(void) | |
802 | extern void zone_sizes_init(void); | |
803 | #endif /* !CONFIG_DISCONTIGMEM */ | |
804 | ||
805 | +static int disable_nx __initdata = 0; | |
806 | +u64 __supported_pte_mask = ~_PAGE_NX; | |
807 | +int use_nx = 0; | |
808 | + | |
809 | +/* | |
810 | + * noexec = on|off | |
811 | + * | |
812 | + * Control non executable mappings. | |
813 | + * | |
814 | + * on Enable | |
815 | + * off Disable (disables exec-shield too) | |
816 | + */ | |
817 | +static int __init noexec_setup(char *str) | |
818 | +{ | |
819 | + if (!strncmp(str, "on",2) && cpu_has_nx) { | |
820 | + __supported_pte_mask |= _PAGE_NX; | |
821 | + disable_nx = 0; | |
822 | + } else if (!strncmp(str,"off",3)) { | |
823 | + disable_nx = 1; | |
824 | + __supported_pte_mask &= ~_PAGE_NX; | |
825 | + exec_shield = 0; | |
826 | + } | |
827 | + return 1; | |
828 | +} | |
829 | + | |
830 | +__setup("noexec=", noexec_setup); | |
831 | + | |
832 | +#ifdef CONFIG_X86_PAE | |
833 | + | |
834 | +static void __init set_nx(void) | |
835 | +{ | |
836 | + unsigned int v[4], l, h; | |
837 | + | |
838 | + if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { | |
839 | + cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); | |
840 | + if ((v[3] & (1 << 20)) && !disable_nx) { | |
841 | + rdmsr(MSR_EFER, l, h); | |
842 | + l |= EFER_NX; | |
843 | + wrmsr(MSR_EFER, l, h); | |
844 | + use_nx = 1; | |
845 | + __supported_pte_mask |= _PAGE_NX; | |
846 | + } | |
847 | + } | |
848 | +} | |
849 | + | |
850 | +#endif | |
851 | + | |
852 | /* | |
853 | * paging_init() sets up the page tables - note that the first 8MB are | |
854 | * already mapped by head.S. | |
855 | @@ -400,6 +467,14 @@ extern void zone_sizes_init(void); | |
856 | */ | |
857 | void __init paging_init(void) | |
858 | { | |
859 | +#ifdef CONFIG_X86_PAE | |
860 | + set_nx(); | |
861 | + if (use_nx) | |
862 | + printk("NX (Execute Disable) protection: active\n"); | |
863 | + else if (exec_shield) | |
864 | + printk("Using x86 segment limits to approximate NX (Execute Disable) protection\n"); | |
865 | +#endif | |
866 | + | |
867 | pagetable_init(); | |
868 | ||
869 | load_cr3(swapper_pg_dir); | |
870 | --- linux/arch/sparc/kernel/sys_sparc.c.orig | |
871 | +++ linux/arch/sparc/kernel/sys_sparc.c | |
872 | @@ -332,7 +332,7 @@ asmlinkage unsigned long sparc_mremap(un | |
873 | ||
874 | new_addr = get_unmapped_area(file, addr, new_len, | |
875 | vma ? vma->vm_pgoff : 0, | |
876 | - map_flags); | |
877 | + map_flags, vma->vm_flags & VM_EXEC); | |
878 | ret = new_addr; | |
879 | if (new_addr & ~PAGE_MASK) | |
880 | goto out_sem; | |
881 | --- linux/arch/ia64/kernel/perfmon.c.orig | |
882 | +++ linux/arch/ia64/kernel/perfmon.c | |
883 | @@ -600,7 +600,7 @@ pfm_do_munmap(struct mm_struct *mm, unsi | |
884 | static inline unsigned long | |
885 | pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec) | |
886 | { | |
887 | - return get_unmapped_area(file, addr, len, pgoff, flags); | |
888 | + return get_unmapped_area(file, addr, len, pgoff, flags, 0); | |
889 | } | |
890 | ||
891 | ||
892 | --- linux/arch/ia64/ia32/binfmt_elf32.c.orig | |
893 | +++ linux/arch/ia64/ia32/binfmt_elf32.c | |
894 | @@ -215,7 +215,7 @@ elf32_set_personality (void) | |
895 | } | |
896 | ||
897 | static unsigned long | |
898 | -elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) | |
899 | +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused) | |
900 | { | |
901 | unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK; | |
902 | ||
903 | --- linux/arch/x86_64/kernel/module.c.orig | |
904 | +++ linux/arch/x86_64/kernel/module.c | |
905 | @@ -121,7 +121,7 @@ void *module_alloc(unsigned long size) | |
906 | goto fail; | |
907 | } | |
908 | ||
909 | - if (map_vm_area(area, PAGE_KERNEL_EXECUTABLE, &pages)) | |
910 | + if (map_vm_area(area, PAGE_KERNEL_EXEC, &pages)) | |
911 | goto fail; | |
912 | ||
913 | memset(addr, 0, size); | |
914 | --- linux/arch/x86_64/mm/pageattr.c.orig | |
915 | +++ linux/arch/x86_64/mm/pageattr.c | |
916 | @@ -180,7 +180,7 @@ int change_page_attr(struct page *page, | |
917 | unsigned long addr2; | |
918 | addr2 = __START_KERNEL_map + page_to_phys(page); | |
919 | err = __change_page_attr(addr2, page, prot, | |
920 | - PAGE_KERNEL_EXECUTABLE); | |
921 | + PAGE_KERNEL_EXEC); | |
922 | } | |
923 | } | |
924 | up_write(&init_mm.mmap_sem); | |
925 | --- linux/arch/x86_64/ia32/ia32_binfmt.c.orig | |
926 | +++ linux/arch/x86_64/ia32/ia32_binfmt.c | |
927 | @@ -382,7 +382,7 @@ int setup_arg_pages(struct linux_binprm | |
928 | } | |
929 | ||
930 | static unsigned long | |
931 | -elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) | |
932 | +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused) | |
933 | { | |
934 | unsigned long map_addr; | |
935 | struct task_struct *me = current; | |
936 | --- linux/include/asm-x86_64/pgalloc.h.orig | |
937 | +++ linux/include/asm-x86_64/pgalloc.h | |
938 | @@ -7,6 +7,11 @@ | |
939 | #include <linux/threads.h> | |
940 | #include <linux/mm.h> | |
941 | ||
942 | +#define arch_add_exec_range(mm, limit) do { ; } while (0) | |
943 | +#define arch_flush_exec_range(mm) do { ; } while (0) | |
944 | +#define arch_remove_exec_range(mm, limit) do { ; } while (0) | |
945 | + | |
946 | + | |
947 | #define pmd_populate_kernel(mm, pmd, pte) \ | |
948 | set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte))) | |
949 | #define pgd_populate(mm, pgd, pmd) \ | |
950 | --- linux/include/asm-x86_64/pgtable.h.orig | |
951 | +++ linux/include/asm-x86_64/pgtable.h | |
952 | @@ -172,7 +172,7 @@ static inline void set_pml4(pml4_t *dst, | |
953 | #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) | |
954 | #define __PAGE_KERNEL \ | |
955 | (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX) | |
956 | -#define __PAGE_KERNEL_EXECUTABLE \ | |
957 | +#define __PAGE_KERNEL_EXEC \ | |
958 | (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) | |
959 | #define __PAGE_KERNEL_NOCACHE \ | |
960 | (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX) | |
961 | @@ -188,7 +188,7 @@ static inline void set_pml4(pml4_t *dst, | |
962 | #define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL) | |
963 | ||
964 | #define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL) | |
965 | -#define PAGE_KERNEL_EXECUTABLE MAKE_GLOBAL(__PAGE_KERNEL_EXECUTABLE) | |
966 | +#define PAGE_KERNEL_EXEC MAKE_GLOBAL(__PAGE_KERNEL_EXEC) | |
967 | #define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO) | |
968 | #define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE) | |
969 | #define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL) | |
970 | --- linux/include/linux/mm.h.orig | |
971 | +++ linux/include/linux/mm.h | |
972 | @@ -630,7 +630,7 @@ extern struct vm_area_struct *copy_vma(s | |
973 | unsigned long addr, unsigned long len, pgoff_t pgoff); | |
974 | extern void exit_mmap(struct mm_struct *); | |
975 | ||
976 | -extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); | |
977 | +extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); | |
978 | ||
979 | extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, | |
980 | unsigned long len, unsigned long prot, | |
981 | --- linux/include/linux/resource.h.orig | |
982 | +++ linux/include/linux/resource.h | |
983 | @@ -52,8 +52,11 @@ struct rlimit { | |
984 | /* | |
985 | * Limit the stack by to some sane default: root can always | |
986 | * increase this limit if needed.. 8MB seems reasonable. | |
987 | + * | |
988 | + * (2MB more to cover randomization effects.) | |
989 | */ | |
990 | -#define _STK_LIM (8*1024*1024) | |
991 | +#define _STK_LIM (10*1024*1024) | |
992 | +#define EXEC_STACK_BIAS (2*1024*1024) | |
993 | ||
994 | /* | |
995 | * Due to binary compatibility, the actual resource numbers | |
996 | --- linux/include/linux/sched.h.orig | |
997 | +++ linux/include/linux/sched.h | |
998 | @@ -31,6 +31,9 @@ | |
999 | #include <linux/percpu.h> | |
1000 | ||
1001 | struct exec_domain; | |
1002 | +extern int exec_shield; | |
1003 | +extern int exec_shield_randomize; | |
1004 | +extern int print_fatal_signals; | |
1005 | ||
1006 | /* | |
1007 | * cloning flags: | |
1008 | @@ -194,6 +197,8 @@ struct mm_struct { | |
1009 | struct rb_root mm_rb; | |
1010 | struct vm_area_struct * mmap_cache; /* last find_vma result */ | |
1011 | unsigned long free_area_cache; /* first hole */ | |
1012 | + unsigned long non_executable_cache; /* last hole top */ | |
1013 | + unsigned long mmap_top; /* top of mmap area */ | |
1014 | pgd_t * pgd; | |
1015 | atomic_t mm_users; /* How many users with user space? */ | |
1016 | atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ | |
1017 | --- linux/include/linux/vmalloc.h.orig | |
1018 | +++ linux/include/linux/vmalloc.h | |
1019 | @@ -23,6 +23,7 @@ struct vm_struct { | |
1020 | * Highlevel APIs for driver use | |
1021 | */ | |
1022 | extern void *vmalloc(unsigned long size); | |
1023 | +extern void *vmalloc_exec(unsigned long size); | |
1024 | extern void *vmalloc_32(unsigned long size); | |
1025 | extern void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot); | |
1026 | extern void vfree(void *addr); | |
1027 | --- linux/include/asm-ppc64/pgalloc.h.orig | |
1028 | +++ linux/include/asm-ppc64/pgalloc.h | |
1029 | @@ -10,6 +10,11 @@ | |
1030 | ||
1031 | extern kmem_cache_t *zero_cache; | |
1032 | ||
1033 | +/* Dummy functions since we don't support execshield on ppc */ | |
1034 | +#define arch_add_exec_range(mm, limit) do { ; } while (0) | |
1035 | +#define arch_flush_exec_range(mm) do { ; } while (0) | |
1036 | +#define arch_remove_exec_range(mm, limit) do { ; } while (0) | |
1037 | + | |
1038 | /* | |
1039 | * This program is free software; you can redistribute it and/or | |
1040 | * modify it under the terms of the GNU General Public License | |
1041 | --- linux/include/asm-ia64/pgalloc.h.orig | |
1042 | +++ linux/include/asm-ia64/pgalloc.h | |
1043 | @@ -23,6 +23,10 @@ | |
1044 | #include <asm/mmu_context.h> | |
1045 | #include <asm/processor.h> | |
1046 | ||
1047 | +#define arch_add_exec_range(mm, limit) do { ; } while (0) | |
1048 | +#define arch_flush_exec_range(mm) do { ; } while (0) | |
1049 | +#define arch_remove_exec_range(mm, limit) do { ; } while (0) | |
1050 | + | |
1051 | /* | |
1052 | * Very stupidly, we used to get new pgd's and pmd's, init their contents | |
1053 | * to point to the NULL versions of the next level page table, later on | |
1054 | --- linux/include/asm-ppc/pgalloc.h.orig | |
1055 | +++ linux/include/asm-ppc/pgalloc.h | |
1056 | @@ -40,5 +40,10 @@ extern void pte_free(struct page *pte); | |
1057 | ||
1058 | #define check_pgt_cache() do { } while (0) | |
1059 | ||
1060 | +#define arch_add_exec_range(mm, limit) do { ; } while (0) | |
1061 | +#define arch_flush_exec_range(mm) do { ; } while (0) | |
1062 | +#define arch_remove_exec_range(mm, limit) do { ; } while (0) | |
1063 | + | |
1064 | + | |
1065 | #endif /* _PPC_PGALLOC_H */ | |
1066 | #endif /* __KERNEL__ */ | |
1067 | --- linux/include/asm-sparc/pgalloc.h.orig | |
1068 | +++ linux/include/asm-sparc/pgalloc.h | |
1069 | @@ -66,4 +66,8 @@ BTFIXUPDEF_CALL(void, pte_free, struct p | |
1070 | #define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) | |
1071 | #define __pte_free_tlb(tlb, pte) pte_free(pte) | |
1072 | ||
1073 | +#define arch_add_exec_range(mm, limit) do { ; } while (0) | |
1074 | +#define arch_flush_exec_range(mm) do { ; } while (0) | |
1075 | +#define arch_remove_exec_range(mm, limit) do { ; } while (0) | |
1076 | + | |
1077 | #endif /* _SPARC_PGALLOC_H */ | |
1078 | --- linux/include/asm-s390/pgalloc.h.orig | |
1079 | +++ linux/include/asm-s390/pgalloc.h | |
1080 | @@ -19,6 +19,10 @@ | |
1081 | #include <linux/gfp.h> | |
1082 | #include <linux/mm.h> | |
1083 | ||
1084 | +#define arch_add_exec_range(mm, limit) do { ; } while (0) | |
1085 | +#define arch_flush_exec_range(mm) do { ; } while (0) | |
1086 | +#define arch_remove_exec_range(mm, limit) do { ; } while (0) | |
1087 | + | |
1088 | #define check_pgt_cache() do {} while (0) | |
1089 | ||
1090 | extern void diag10(unsigned long addr); | |
1091 | --- linux/include/asm-i386/desc.h.orig | |
1092 | +++ linux/include/asm-i386/desc.h | |
1093 | @@ -123,6 +123,20 @@ static inline void load_LDT(mm_context_t | |
1094 | put_cpu(); | |
1095 | } | |
1096 | ||
1097 | +static inline void set_user_cs(struct desc_struct *desc, unsigned long limit) | |
1098 | +{ | |
1099 | + limit = (limit - 1) / PAGE_SIZE; | |
1100 | + desc->a = limit & 0xffff; | |
1101 | + desc->b = (limit & 0xf0000) | 0x00c0fb00; | |
1102 | +} | |
1103 | + | |
1104 | +#define load_user_cs_desc(cpu, mm) \ | |
1105 | + cpu_gdt_table[(cpu)][GDT_ENTRY_DEFAULT_USER_CS] = (mm)->context.user_cs | |
1106 | + | |
1107 | +extern void arch_add_exec_range(struct mm_struct *mm, unsigned long limit); | |
1108 | +extern void arch_remove_exec_range(struct mm_struct *mm, unsigned long limit); | |
1109 | +extern void arch_flush_exec_range(struct mm_struct *mm); | |
1110 | + | |
1111 | #endif /* !__ASSEMBLY__ */ | |
1112 | ||
1113 | #endif | |
1114 | --- linux/include/asm-i386/cpufeature.h.orig | |
1115 | +++ linux/include/asm-i386/cpufeature.h | |
1116 | @@ -47,6 +47,7 @@ | |
1117 | /* Don't duplicate feature flags which are redundant with Intel! */ | |
1118 | #define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */ | |
1119 | #define X86_FEATURE_MP (1*32+19) /* MP Capable. */ | |
1120 | +#define X86_FEATURE_NX (1*32+20) /* Execute Disable */ | |
1121 | #define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ | |
1122 | #define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */ | |
1123 | #define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */ | |
1124 | @@ -100,6 +101,7 @@ | |
1125 | #define cpu_has_xmm boot_cpu_has(X86_FEATURE_XMM) | |
1126 | #define cpu_has_ht boot_cpu_has(X86_FEATURE_HT) | |
1127 | #define cpu_has_mp boot_cpu_has(X86_FEATURE_MP) | |
1128 | +#define cpu_has_nx boot_cpu_has(X86_FEATURE_NX) | |
1129 | #define cpu_has_k6_mtrr boot_cpu_has(X86_FEATURE_K6_MTRR) | |
1130 | #define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR) | |
1131 | #define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR) | |
1132 | --- linux/include/asm-i386/elf.h.orig | |
1133 | +++ linux/include/asm-i386/elf.h | |
1134 | @@ -9,6 +9,7 @@ | |
1135 | #include <asm/user.h> | |
1136 | #include <asm/processor.h> | |
1137 | #include <asm/system.h> /* for savesegment */ | |
1138 | +#include <asm/desc.h> | |
1139 | ||
1140 | #include <linux/utsname.h> | |
1141 | ||
1142 | @@ -117,7 +118,8 @@ typedef struct user_fxsr_struct elf_fpxr | |
1143 | #define AT_SYSINFO_EHDR 33 | |
1144 | ||
1145 | #ifdef __KERNEL__ | |
1146 | -#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) | |
1147 | +/* child inherits the personality of the parent */ | |
1148 | +#define SET_PERSONALITY(ex, ibcs2) do { } while (0) | |
1149 | ||
1150 | extern int dump_task_regs (struct task_struct *, elf_gregset_t *); | |
1151 | extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); | |
1152 | @@ -127,15 +129,22 @@ extern int dump_task_extended_fpu (struc | |
1153 | #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) | |
1154 | #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs) | |
1155 | ||
1156 | -#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) | |
1157 | -#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) | |
1158 | -#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall) | |
1159 | extern void __kernel_vsyscall; | |
1160 | +#define VSYSCALL_BASE ((unsigned long)current->mm->context.vdso) | |
1161 | +#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) | |
1162 | +#define VSYSCALL_OFFSET ((unsigned long) &__kernel_vsyscall) | |
1163 | +#define VSYSCALL_ENTRY (VSYSCALL_BASE + VSYSCALL_OFFSET) | |
1164 | ||
1165 | -#define ARCH_DLINFO \ | |
1166 | -do { \ | |
1167 | - NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ | |
1168 | - NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ | |
1169 | +/* kernel-internal fixmap address: */ | |
1170 | +#define __VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) | |
1171 | +#define __VSYSCALL_EHDR ((const struct elfhdr *) __VSYSCALL_BASE) | |
1172 | + | |
1173 | +#define ARCH_DLINFO \ | |
1174 | +do { \ | |
1175 | + if (VSYSCALL_BASE) { \ | |
1176 | + NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ | |
1177 | + NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ | |
1178 | + } \ | |
1179 | } while (0) | |
1180 | ||
1181 | /* | |
1182 | @@ -146,15 +155,15 @@ do { \ | |
1183 | * Dumping its extra ELF program headers includes all the other information | |
1184 | * a debugger needs to easily find how the vsyscall DSO was being used. | |
1185 | */ | |
1186 | -#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum) | |
1187 | +#define ELF_CORE_EXTRA_PHDRS (__VSYSCALL_EHDR->e_phnum) | |
1188 | #define ELF_CORE_WRITE_EXTRA_PHDRS \ | |
1189 | do { \ | |
1190 | const struct elf_phdr *const vsyscall_phdrs = \ | |
1191 | - (const struct elf_phdr *) (VSYSCALL_BASE \ | |
1192 | - + VSYSCALL_EHDR->e_phoff); \ | |
1193 | + (const struct elf_phdr *) (__VSYSCALL_BASE \ | |
1194 | + + __VSYSCALL_EHDR->e_phoff); \ | |
1195 | int i; \ | |
1196 | Elf32_Off ofs = 0; \ | |
1197 | - for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ | |
1198 | + for (i = 0; i < __VSYSCALL_EHDR->e_phnum; ++i) { \ | |
1199 | struct elf_phdr phdr = vsyscall_phdrs[i]; \ | |
1200 | if (phdr.p_type == PT_LOAD) { \ | |
1201 | BUG_ON(ofs != 0); \ | |
1202 | @@ -172,10 +181,10 @@ do { \ | |
1203 | #define ELF_CORE_WRITE_EXTRA_DATA \ | |
1204 | do { \ | |
1205 | const struct elf_phdr *const vsyscall_phdrs = \ | |
1206 | - (const struct elf_phdr *) (VSYSCALL_BASE \ | |
1207 | - + VSYSCALL_EHDR->e_phoff); \ | |
1208 | + (const struct elf_phdr *) (__VSYSCALL_BASE \ | |
1209 | + + __VSYSCALL_EHDR->e_phoff); \ | |
1210 | int i; \ | |
1211 | - for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ | |
1212 | + for (i = 0; i < __VSYSCALL_EHDR->e_phnum; ++i) { \ | |
1213 | if (vsyscall_phdrs[i].p_type == PT_LOAD) \ | |
1214 | DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \ | |
1215 | PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \ | |
1216 | @@ -184,4 +193,10 @@ do { \ | |
1217 | ||
1218 | #endif | |
1219 | ||
1220 | +#define __HAVE_ARCH_RANDOMIZE_BRK | |
1221 | +extern void randomize_brk(unsigned long old_brk); | |
1222 | + | |
1223 | +#define __HAVE_ARCH_VSYSCALL | |
1224 | +extern void map_vsyscall(void); | |
1225 | + | |
1226 | #endif | |
1227 | --- linux/include/asm-i386/mmu.h.orig | |
1228 | +++ linux/include/asm-i386/mmu.h | |
1229 | @@ -7,11 +7,17 @@ | |
1230 | * we put the segment information here. | |
1231 | * | |
1232 | * cpu_vm_mask is used to optimize ldt flushing. | |
1233 | + * | |
1234 | + * exec_limit is used to track the range PROT_EXEC | |
1235 | + * mappings span. | |
1236 | */ | |
1237 | typedef struct { | |
1238 | int size; | |
1239 | struct semaphore sem; | |
1240 | void *ldt; | |
1241 | + struct desc_struct user_cs; | |
1242 | + unsigned long exec_limit; | |
1243 | + void *vdso; | |
1244 | } mm_context_t; | |
1245 | ||
1246 | #endif | |
1247 | --- linux/include/asm-i386/msr.h.orig | |
1248 | +++ linux/include/asm-i386/msr.h | |
1249 | @@ -217,6 +217,15 @@ static inline void wrmsrl (unsigned long | |
1250 | #define MSR_K7_FID_VID_CTL 0xC0010041 | |
1251 | #define MSR_K7_FID_VID_STATUS 0xC0010042 | |
1252 | ||
1253 | +/* extended feature register */ | |
1254 | +#define MSR_EFER 0xc0000080 | |
1255 | + | |
1256 | +/* EFER bits: */ | |
1257 | + | |
1258 | +/* Execute Disable enable */ | |
1259 | +#define _EFER_NX 11 | |
1260 | +#define EFER_NX (1<<_EFER_NX) | |
1261 | + | |
1262 | /* Centaur-Hauls/IDT defined MSRs. */ | |
1263 | #define MSR_IDT_FCR1 0x107 | |
1264 | #define MSR_IDT_FCR2 0x108 | |
1265 | --- linux/include/asm-i386/page.h.orig | |
1266 | +++ linux/include/asm-i386/page.h | |
1267 | @@ -40,15 +40,18 @@ | |
1268 | * These are used to make use of C type-checking.. | |
1269 | */ | |
1270 | #ifdef CONFIG_X86_PAE | |
1271 | +extern unsigned long long __supported_pte_mask; | |
1272 | typedef struct { unsigned long pte_low, pte_high; } pte_t; | |
1273 | typedef struct { unsigned long long pmd; } pmd_t; | |
1274 | typedef struct { unsigned long long pgd; } pgd_t; | |
1275 | +typedef struct { unsigned long long pgprot; } pgprot_t; | |
1276 | #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) | |
1277 | #define HPAGE_SHIFT 21 | |
1278 | #else | |
1279 | typedef struct { unsigned long pte_low; } pte_t; | |
1280 | typedef struct { unsigned long pmd; } pmd_t; | |
1281 | typedef struct { unsigned long pgd; } pgd_t; | |
1282 | +typedef struct { unsigned long pgprot; } pgprot_t; | |
1283 | #define boot_pte_t pte_t /* or would you rather have a typedef */ | |
1284 | #define pte_val(x) ((x).pte_low) | |
1285 | #define HPAGE_SHIFT 22 | |
1286 | @@ -61,7 +64,6 @@ typedef struct { unsigned long pgd; } pg | |
1287 | #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) | |
1288 | #endif | |
1289 | ||
1290 | -typedef struct { unsigned long pgprot; } pgprot_t; | |
1291 | ||
1292 | #define pmd_val(x) ((x).pmd) | |
1293 | #define pgd_val(x) ((x).pgd) | |
1294 | @@ -136,7 +138,7 @@ static __inline__ int get_order(unsigned | |
1295 | ||
1296 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) | |
1297 | ||
1298 | -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ | |
1299 | +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ | |
1300 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | |
1301 | ||
1302 | #endif /* __KERNEL__ */ | |
1303 | --- linux/include/asm-i386/pgalloc.h.orig | |
1304 | +++ linux/include/asm-i386/pgalloc.h | |
1305 | @@ -4,6 +4,7 @@ | |
1306 | #include <linux/config.h> | |
1307 | #include <asm/processor.h> | |
1308 | #include <asm/fixmap.h> | |
1309 | +#include <asm/desc.h> | |
1310 | #include <linux/threads.h> | |
1311 | #include <linux/mm.h> /* for struct page */ | |
1312 | ||
1313 | @@ -52,4 +53,6 @@ static inline void pte_free(struct page | |
1314 | ||
1315 | #define check_pgt_cache() do { } while (0) | |
1316 | ||
1317 | +#define HAVE_ARCH_UNMAPPED_AREA 1 | |
1318 | + | |
1319 | #endif /* _I386_PGALLOC_H */ | |
1320 | --- linux/include/asm-i386/pgtable-3level.h.orig | |
1321 | +++ linux/include/asm-i386/pgtable-3level.h | |
1322 | @@ -101,18 +101,24 @@ static inline unsigned long pte_pfn(pte_ | |
1323 | (pte.pte_high << (32 - PAGE_SHIFT)); | |
1324 | } | |
1325 | ||
1326 | +extern unsigned long long __supported_pte_mask; | |
1327 | + | |
1328 | static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) | |
1329 | { | |
1330 | pte_t pte; | |
1331 | ||
1332 | - pte.pte_high = page_nr >> (32 - PAGE_SHIFT); | |
1333 | - pte.pte_low = (page_nr << PAGE_SHIFT) | pgprot_val(pgprot); | |
1334 | + pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) | \ | |
1335 | + (pgprot_val(pgprot) >> 32); | |
1336 | + pte.pte_high &= (__supported_pte_mask >> 32); | |
1337 | + pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)) & \ | |
1338 | + __supported_pte_mask; | |
1339 | return pte; | |
1340 | } | |
1341 | ||
1342 | static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) | |
1343 | { | |
1344 | - return __pmd(((unsigned long long)page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); | |
1345 | + return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | \ | |
1346 | + pgprot_val(pgprot)) & __supported_pte_mask); | |
1347 | } | |
1348 | ||
1349 | /* | |
1350 | --- linux/include/asm-i386/pgtable.h.orig | |
1351 | +++ linux/include/asm-i386/pgtable.h | |
1352 | @@ -110,6 +110,7 @@ void paging_init(void); | |
1353 | #define _PAGE_BIT_UNUSED1 9 /* available for programmer */ | |
1354 | #define _PAGE_BIT_UNUSED2 10 | |
1355 | #define _PAGE_BIT_UNUSED3 11 | |
1356 | +#define _PAGE_BIT_NX 63 | |
1357 | ||
1358 | #define _PAGE_PRESENT 0x001 | |
1359 | #define _PAGE_RW 0x002 | |
1360 | @@ -126,28 +127,51 @@ void paging_init(void); | |
1361 | ||
1362 | #define _PAGE_FILE 0x040 /* set:pagecache unset:swap */ | |
1363 | #define _PAGE_PROTNONE 0x080 /* If not present */ | |
1364 | +#ifdef CONFIG_X86_PAE | |
1365 | +#define _PAGE_NX (1ULL<<_PAGE_BIT_NX) | |
1366 | +#else | |
1367 | +#define _PAGE_NX 0 | |
1368 | +#endif | |
1369 | ||
1370 | #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) | |
1371 | #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) | |
1372 | #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) | |
1373 | ||
1374 | -#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) | |
1375 | -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) | |
1376 | -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) | |
1377 | -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) | |
1378 | +#define PAGE_NONE \ | |
1379 | + __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) | |
1380 | +#define PAGE_SHARED \ | |
1381 | + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) | |
1382 | + | |
1383 | +#define PAGE_SHARED_EXEC \ | |
1384 | + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) | |
1385 | +#define PAGE_COPY_NOEXEC \ | |
1386 | + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) | |
1387 | +#define PAGE_COPY_EXEC \ | |
1388 | + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) | |
1389 | +#define PAGE_COPY \ | |
1390 | + PAGE_COPY_NOEXEC | |
1391 | +#define PAGE_READONLY \ | |
1392 | + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) | |
1393 | +#define PAGE_READONLY_EXEC \ | |
1394 | + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) | |
1395 | ||
1396 | #define _PAGE_KERNEL \ | |
1397 | + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX) | |
1398 | +#define _PAGE_KERNEL_EXEC \ | |
1399 | (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) | |
1400 | ||
1401 | -extern unsigned long __PAGE_KERNEL; | |
1402 | -#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) | |
1403 | -#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) | |
1404 | -#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) | |
1405 | +extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; | |
1406 | +#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) | |
1407 | +#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) | |
1408 | +#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) | |
1409 | +#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) | |
1410 | ||
1411 | #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) | |
1412 | #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) | |
1413 | +#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) | |
1414 | #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) | |
1415 | #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) | |
1416 | +#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) | |
1417 | ||
1418 | /* | |
1419 | * The i386 can't do page protection for execute, and considers that | |
1420 | @@ -158,19 +182,19 @@ extern unsigned long __PAGE_KERNEL; | |
1421 | #define __P001 PAGE_READONLY | |
1422 | #define __P010 PAGE_COPY | |
1423 | #define __P011 PAGE_COPY | |
1424 | -#define __P100 PAGE_READONLY | |
1425 | -#define __P101 PAGE_READONLY | |
1426 | -#define __P110 PAGE_COPY | |
1427 | -#define __P111 PAGE_COPY | |
1428 | +#define __P100 PAGE_READONLY_EXEC | |
1429 | +#define __P101 PAGE_READONLY_EXEC | |
1430 | +#define __P110 PAGE_COPY_EXEC | |
1431 | +#define __P111 PAGE_COPY_EXEC | |
1432 | ||
1433 | #define __S000 PAGE_NONE | |
1434 | #define __S001 PAGE_READONLY | |
1435 | #define __S010 PAGE_SHARED | |
1436 | #define __S011 PAGE_SHARED | |
1437 | -#define __S100 PAGE_READONLY | |
1438 | -#define __S101 PAGE_READONLY | |
1439 | -#define __S110 PAGE_SHARED | |
1440 | -#define __S111 PAGE_SHARED | |
1441 | +#define __S100 PAGE_READONLY_EXEC | |
1442 | +#define __S101 PAGE_READONLY_EXEC | |
1443 | +#define __S110 PAGE_SHARED_EXEC | |
1444 | +#define __S111 PAGE_SHARED_EXEC | |
1445 | ||
1446 | /* | |
1447 | * Define this if things work differently on an i386 and an i486: | |
1448 | @@ -256,6 +280,15 @@ static inline pte_t pte_modify(pte_t pte | |
1449 | { | |
1450 | pte.pte_low &= _PAGE_CHG_MASK; | |
1451 | pte.pte_low |= pgprot_val(newprot); | |
1452 | +#ifdef CONFIG_X86_PAE | |
1453 | + /* | |
1454 | + * Chop off the NX bit (if present), and add the NX portion of | |
1455 | + * the newprot (if present): | |
1456 | + */ | |
1457 | + pte.pte_high &= -1 ^ (1 << (_PAGE_BIT_NX - 32)); | |
1458 | + pte.pte_high |= (pgprot_val(newprot) >> 32) & \ | |
1459 | + (__supported_pte_mask >> 32); | |
1460 | +#endif | |
1461 | return pte; | |
1462 | } | |
1463 | ||
1464 | --- linux/include/asm-i386/processor.h.orig | |
1465 | +++ linux/include/asm-i386/processor.h | |
1466 | @@ -294,7 +294,15 @@ extern unsigned int mca_pentium_flag; | |
1467 | /* This decides where the kernel will search for a free chunk of vm | |
1468 | * space during mmap's. | |
1469 | */ | |
1470 | -#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) | |
1471 | +#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE/3) | |
1472 | + | |
1473 | +#define SHLIB_BASE 0x00111000 | |
1474 | + | |
1475 | +#define __HAVE_ARCH_ALIGN_STACK | |
1476 | +extern unsigned long arch_align_stack(unsigned long sp); | |
1477 | + | |
1478 | +#define __HAVE_ARCH_MMAP_TOP | |
1479 | +extern unsigned long mmap_top(void); | |
1480 | ||
1481 | /* | |
1482 | * Size of io_bitmap, covering ports 0 to 0x3ff. | |
1483 | @@ -456,6 +464,8 @@ static inline void load_esp0(struct tss_ | |
1484 | } | |
1485 | } | |
1486 | ||
1487 | +extern int use_nx; | |
1488 | + | |
1489 | #define start_thread(regs, new_eip, new_esp) do { \ | |
1490 | __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \ | |
1491 | set_fs(USER_DS); \ | |
1492 | @@ -465,6 +475,7 @@ static inline void load_esp0(struct tss_ | |
1493 | regs->xcs = __USER_CS; \ | |
1494 | regs->eip = new_eip; \ | |
1495 | regs->esp = new_esp; \ | |
1496 | + load_user_cs_desc(smp_processor_id(), current->mm); \ | |
1497 | } while (0) | |
1498 | ||
1499 | /* Forward declaration, a strange C thing */ | |
1500 | --- linux/include/asm-i386/thread_info.h.orig | |
1501 | +++ linux/include/asm-i386/thread_info.h | |
1502 | @@ -37,6 +37,7 @@ struct thread_info { | |
1503 | 0-0xBFFFFFFF for user-thead | |
1504 | 0-0xFFFFFFFF for kernel-thread | |
1505 | */ | |
1506 | + void *sysenter_return; | |
1507 | struct restart_block restart_block; | |
1508 | ||
1509 | unsigned long previous_esp; /* ESP of the previous stack in case | |
1510 | --- linux/include/asm-sparc64/pgalloc.h.orig | |
1511 | +++ linux/include/asm-sparc64/pgalloc.h | |
1512 | @@ -236,4 +236,8 @@ static __inline__ void free_pte_slow(pte | |
1513 | #define pgd_free(pgd) free_pgd_fast(pgd) | |
1514 | #define pgd_alloc(mm) get_pgd_fast() | |
1515 | ||
1516 | +#define arch_add_exec_range(mm, limit) do { ; } while (0) | |
1517 | +#define arch_flush_exec_range(mm) do { ; } while (0) | |
1518 | +#define arch_remove_exec_range(mm, limit) do { ; } while (0) | |
1519 | + | |
1520 | #endif /* _SPARC64_PGALLOC_H */ | |
1521 | --- linux/fs/proc/array.c.orig | |
1522 | +++ linux/fs/proc/array.c | |
1523 | @@ -324,7 +324,10 @@ int proc_pid_stat(struct task_struct *ta | |
1524 | up_read(&mm->mmap_sem); | |
1525 | } | |
1526 | ||
1527 | - wchan = get_wchan(task); | |
1528 | + wchan = 0; | |
1529 | + if (current->uid == task->uid || current->euid == task->uid || | |
1530 | + capable(CAP_SYS_NICE)) | |
1531 | + wchan = get_wchan(task); | |
1532 | ||
1533 | sigemptyset(&sigign); | |
1534 | sigemptyset(&sigcatch); | |
1535 | --- linux/fs/proc/base.c.orig | |
1536 | +++ linux/fs/proc/base.c | |
1537 | @@ -111,7 +111,7 @@ static struct pid_entry tgid_base_stuff[ | |
1538 | E(PROC_TGID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), | |
1539 | E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), | |
1540 | E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), | |
1541 | - E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), | |
1542 | + E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUSR), | |
1543 | E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | |
1544 | E(PROC_TGID_CWD, "cwd", S_IFLNK|S_IRWXUGO), | |
1545 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), | |
1546 | @@ -133,7 +133,7 @@ static struct pid_entry tid_base_stuff[] | |
1547 | E(PROC_TID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), | |
1548 | E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), | |
1549 | E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), | |
1550 | - E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), | |
1551 | + E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUSR), | |
1552 | E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | |
1553 | E(PROC_TID_CWD, "cwd", S_IFLNK|S_IRWXUGO), | |
1554 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), | |
1555 | --- linux/fs/proc/task_mmu.c.orig | |
1556 | +++ linux/fs/proc/task_mmu.c | |
1557 | @@ -34,12 +34,23 @@ char *task_mem(struct mm_struct *mm, cha | |
1558 | "VmData:\t%8lu kB\n" | |
1559 | "VmStk:\t%8lu kB\n" | |
1560 | "VmExe:\t%8lu kB\n" | |
1561 | - "VmLib:\t%8lu kB\n", | |
1562 | + "VmLib:\t%8lu kB\n" | |
1563 | + "StaBrk:\t%08lx kB\n" | |
1564 | + "Brk:\t%08lx kB\n" | |
1565 | + "StaStk:\t%08lx kB\n" | |
1566 | +#if __i386__ | |
1567 | + "ExecLim:\t%08lx\n" | |
1568 | +#endif | |
1569 | + , | |
1570 | mm->total_vm << (PAGE_SHIFT-10), | |
1571 | mm->locked_vm << (PAGE_SHIFT-10), | |
1572 | mm->rss << (PAGE_SHIFT-10), | |
1573 | data - stack, stack, | |
1574 | - exec - lib, lib); | |
1575 | + exec - lib, lib, mm->start_brk, mm->brk, mm->start_stack | |
1576 | +#if __i386__ | |
1577 | + , mm->context.exec_limit | |
1578 | +#endif | |
1579 | + ); | |
1580 | up_read(&mm->mmap_sem); | |
1581 | return buffer; | |
1582 | } | |
1583 | --- linux/fs/binfmt_aout.c.orig | |
1584 | +++ linux/fs/binfmt_aout.c | |
1585 | @@ -308,7 +308,8 @@ static int load_aout_binary(struct linux | |
1586 | current->mm->brk = ex.a_bss + | |
1587 | (current->mm->start_brk = N_BSSADDR(ex)); | |
1588 | current->mm->free_area_cache = TASK_UNMAPPED_BASE; | |
1589 | - | |
1590 | + /* unlimited stack is larger than TASK_SIZE */ | |
1591 | + current->mm->non_executable_cache = current->mm->mmap_top; | |
1592 | current->mm->rss = 0; | |
1593 | current->mm->mmap = NULL; | |
1594 | compute_creds(bprm); | |
1595 | --- linux/fs/binfmt_elf.c.orig | |
1596 | +++ linux/fs/binfmt_elf.c | |
1597 | @@ -45,7 +45,7 @@ | |
1598 | ||
1599 | static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); | |
1600 | static int load_elf_library(struct file*); | |
1601 | -static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); | |
1602 | +static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long); | |
1603 | extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); | |
1604 | ||
1605 | #ifndef elf_addr_t | |
1606 | @@ -155,20 +155,8 @@ create_elf_tables(struct linux_binprm *b | |
1607 | if (k_platform) { | |
1608 | size_t len = strlen(k_platform) + 1; | |
1609 | ||
1610 | -#ifdef CONFIG_X86_HT | |
1611 | - /* | |
1612 | - * In some cases (e.g. Hyper-Threading), we want to avoid L1 | |
1613 | - * evictions by the processes running on the same package. One | |
1614 | - * thing we can do is to shuffle the initial stack for them. | |
1615 | - * | |
1616 | - * The conditionals here are unneeded, but kept in to make the | |
1617 | - * code behaviour the same as pre change unless we have | |
1618 | - * hyperthreaded processors. This should be cleaned up | |
1619 | - * before 2.6 | |
1620 | - */ | |
1621 | - | |
1622 | - if (smp_num_siblings > 1) | |
1623 | - STACK_ALLOC(p, ((current->pid % 64) << 7)); | |
1624 | +#ifdef __HAVE_ARCH_ALIGN_STACK | |
1625 | + p = (unsigned long)arch_align_stack((unsigned long)p); | |
1626 | #endif | |
1627 | u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); | |
1628 | __copy_to_user(u_platform, k_platform, len); | |
1629 | @@ -272,20 +260,59 @@ create_elf_tables(struct linux_binprm *b | |
1630 | #ifndef elf_map | |
1631 | ||
1632 | static unsigned long elf_map(struct file *filep, unsigned long addr, | |
1633 | - struct elf_phdr *eppnt, int prot, int type) | |
1634 | + struct elf_phdr *eppnt, int prot, int type, | |
1635 | + unsigned long total_size) | |
1636 | { | |
1637 | unsigned long map_addr; | |
1638 | + unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); | |
1639 | + unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); | |
1640 | + | |
1641 | + addr = ELF_PAGESTART(addr); | |
1642 | + size = ELF_PAGEALIGN(size); | |
1643 | ||
1644 | down_write(¤t->mm->mmap_sem); | |
1645 | - map_addr = do_mmap(filep, ELF_PAGESTART(addr), | |
1646 | - eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, | |
1647 | - eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); | |
1648 | + | |
1649 | + /* | |
1650 | + * total_size is the size of the ELF (interpreter) image. | |
1651 | + * The _first_ mmap needs to know the full size, otherwise | |
1652 | + * randomization might put this image into an overlapping | |
1653 | + * position with the ELF binary image. (since size < total_size) | |
1654 | + * So we first map the 'big' image - and unmap the remainder at | |
1655 | + * the end. (which unmap is needed for ELF images with holes.) | |
1656 | + */ | |
1657 | + if (total_size) { | |
1658 | + total_size = ELF_PAGEALIGN(total_size); | |
1659 | + map_addr = do_mmap(filep, addr, total_size, prot, type, off); | |
1660 | + if (!BAD_ADDR(map_addr)) | |
1661 | + do_munmap(current->mm, map_addr+size, total_size-size); | |
1662 | + } else | |
1663 | + map_addr = do_mmap(filep, addr, size, prot, type, off); | |
1664 | + | |
1665 | up_write(¤t->mm->mmap_sem); | |
1666 | - return(map_addr); | |
1667 | + | |
1668 | + return map_addr; | |
1669 | } | |
1670 | ||
1671 | #endif /* !elf_map */ | |
1672 | ||
1673 | +static inline unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) | |
1674 | +{ | |
1675 | + int i, first_idx = -1, last_idx = -1; | |
1676 | + | |
1677 | + for (i = 0; i < nr; i++) | |
1678 | + if (cmds[i].p_type == PT_LOAD) { | |
1679 | + last_idx = i; | |
1680 | + if (first_idx == -1) | |
1681 | + first_idx = i; | |
1682 | + } | |
1683 | + | |
1684 | + if (first_idx == -1) | |
1685 | + return 0; | |
1686 | + | |
1687 | + return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - | |
1688 | + ELF_PAGESTART(cmds[first_idx].p_vaddr); | |
1689 | +} | |
1690 | + | |
1691 | /* This is much more generalized than the library routine read function, | |
1692 | so we keep this separate. Technically the library read function | |
1693 | is only provided so that we can read a.out libraries that have | |
1694 | @@ -293,7 +320,8 @@ static unsigned long elf_map(struct file | |
1695 | ||
1696 | static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | |
1697 | struct file * interpreter, | |
1698 | - unsigned long *interp_load_addr) | |
1699 | + unsigned long *interp_load_addr, | |
1700 | + unsigned long no_base) | |
1701 | { | |
1702 | struct elf_phdr *elf_phdata; | |
1703 | struct elf_phdr *eppnt; | |
1704 | @@ -301,6 +329,7 @@ static unsigned long load_elf_interp(str | |
1705 | int load_addr_set = 0; | |
1706 | unsigned long last_bss = 0, elf_bss = 0; | |
1707 | unsigned long error = ~0UL; | |
1708 | + unsigned long total_size; | |
1709 | int retval, i, size; | |
1710 | ||
1711 | /* First of all, some simple consistency checks */ | |
1712 | @@ -335,6 +364,10 @@ static unsigned long load_elf_interp(str | |
1713 | if (retval < 0) | |
1714 | goto out_close; | |
1715 | ||
1716 | + total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); | |
1717 | + if (!total_size) | |
1718 | + goto out_close; | |
1719 | + | |
1720 | eppnt = elf_phdata; | |
1721 | for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { | |
1722 | if (eppnt->p_type == PT_LOAD) { | |
1723 | @@ -349,8 +382,11 @@ static unsigned long load_elf_interp(str | |
1724 | vaddr = eppnt->p_vaddr; | |
1725 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) | |
1726 | elf_type |= MAP_FIXED; | |
1727 | + else if (no_base && interp_elf_ex->e_type == ET_DYN) | |
1728 | + load_addr = -vaddr; | |
1729 | ||
1730 | - map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); | |
1731 | + map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type, total_size); | |
1732 | + total_size = 0; | |
1733 | error = map_addr; | |
1734 | if (BAD_ADDR(map_addr)) | |
1735 | goto out_close; | |
1736 | @@ -490,6 +526,7 @@ static int load_elf_binary(struct linux_ | |
1737 | char passed_fileno[6]; | |
1738 | struct files_struct *files; | |
1739 | int executable_stack = EXSTACK_DEFAULT; | |
1740 | + unsigned long def_flags = 0; | |
1741 | ||
1742 | /* Get the exec-header */ | |
1743 | elf_ex = *((struct elfhdr *) bprm->buf); | |
1744 | @@ -621,7 +658,18 @@ static int load_elf_binary(struct linux_ | |
1745 | executable_stack = EXSTACK_ENABLE_X; | |
1746 | else | |
1747 | executable_stack = EXSTACK_DISABLE_X; | |
1748 | + break; | |
1749 | } | |
1750 | + if (i == elf_ex.e_phnum) | |
1751 | + def_flags |= VM_EXEC | VM_MAYEXEC; | |
1752 | + | |
1753 | + if (current->personality == PER_LINUX) | |
1754 | + switch (exec_shield) { | |
1755 | + case 2: | |
1756 | + executable_stack = EXSTACK_DISABLE_X; | |
1757 | + def_flags &= ~(VM_EXEC | VM_MAYEXEC); | |
1758 | + break; | |
1759 | + } | |
1760 | ||
1761 | /* Some simple consistency checks for the interpreter */ | |
1762 | if (elf_interpreter) { | |
1763 | @@ -676,6 +724,15 @@ static int load_elf_binary(struct linux_ | |
1764 | if (retval) | |
1765 | goto out_free_dentry; | |
1766 | ||
1767 | +#ifdef __i386__ | |
1768 | + /* | |
1769 | + * Turn off the CS limit completely if exec-shield disabled or | |
1770 | + * NX active: | |
1771 | + */ | |
1772 | + if (!exec_shield || use_nx) | |
1773 | + arch_add_exec_range(current->mm, -1); | |
1774 | +#endif | |
1775 | + | |
1776 | /* Discard our unneeded old files struct */ | |
1777 | if (files) { | |
1778 | steal_locks(files); | |
1779 | @@ -688,7 +745,11 @@ static int load_elf_binary(struct linux_ | |
1780 | current->mm->end_data = 0; | |
1781 | current->mm->end_code = 0; | |
1782 | current->mm->mmap = NULL; | |
1783 | +#ifdef __HAVE_ARCH_MMAP_TOP | |
1784 | + current->mm->mmap_top = mmap_top(); | |
1785 | +#endif | |
1786 | current->flags &= ~PF_FORKNOEXEC; | |
1787 | + current->mm->def_flags = def_flags; | |
1788 | ||
1789 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages | |
1790 | may depend on the personality. */ | |
1791 | @@ -698,6 +759,7 @@ static int load_elf_binary(struct linux_ | |
1792 | change some of these later */ | |
1793 | current->mm->rss = 0; | |
1794 | current->mm->free_area_cache = TASK_UNMAPPED_BASE; | |
1795 | + current->mm->non_executable_cache = current->mm->mmap_top; | |
1796 | retval = setup_arg_pages(bprm, executable_stack); | |
1797 | if (retval < 0) { | |
1798 | send_sig(SIGKILL, current, 0); | |
1799 | @@ -706,10 +768,10 @@ static int load_elf_binary(struct linux_ | |
1800 | ||
1801 | current->mm->start_stack = bprm->p; | |
1802 | ||
1803 | + | |
1804 | /* Now we do a little grungy work by mmaping the ELF image into | |
1805 | - the correct location in memory. At this point, we assume that | |
1806 | - the image should be loaded at fixed address, not at a variable | |
1807 | - address. */ | |
1808 | + the correct location in memory. | |
1809 | + */ | |
1810 | ||
1811 | for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { | |
1812 | int elf_prot = 0, elf_flags; | |
1813 | @@ -746,16 +808,16 @@ static int load_elf_binary(struct linux_ | |
1814 | elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; | |
1815 | ||
1816 | vaddr = elf_ppnt->p_vaddr; | |
1817 | - if (elf_ex.e_type == ET_EXEC || load_addr_set) { | |
1818 | + if (elf_ex.e_type == ET_EXEC || load_addr_set) | |
1819 | elf_flags |= MAP_FIXED; | |
1820 | - } else if (elf_ex.e_type == ET_DYN) { | |
1821 | - /* Try and get dynamic programs out of the way of the default mmap | |
1822 | - base, as well as whatever program they might try to exec. This | |
1823 | - is because the brk will follow the loader, and is not movable. */ | |
1824 | + else if (elf_ex.e_type == ET_DYN) | |
1825 | +#ifdef __i386__ | |
1826 | + load_bias = 0; | |
1827 | +#else | |
1828 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); | |
1829 | - } | |
1830 | +#endif | |
1831 | ||
1832 | - error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); | |
1833 | + error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags, 0); | |
1834 | if (BAD_ADDR(error)) | |
1835 | continue; | |
1836 | ||
1837 | @@ -826,7 +888,8 @@ static int load_elf_binary(struct linux_ | |
1838 | else | |
1839 | elf_entry = load_elf_interp(&interp_elf_ex, | |
1840 | interpreter, | |
1841 | - &interp_load_addr); | |
1842 | + &interp_load_addr, | |
1843 | + load_bias); | |
1844 | if (BAD_ADDR(elf_entry)) { | |
1845 | printk(KERN_ERR "Unable to load interpreter\n"); | |
1846 | send_sig(SIGSEGV, current, 0); | |
1847 | @@ -849,6 +912,14 @@ static int load_elf_binary(struct linux_ | |
1848 | ||
1849 | set_binfmt(&elf_format); | |
1850 | ||
1851 | + /* | |
1852 | + * Map the vsyscall trampoline. This address is then passed via | |
1853 | + * AT_SYSINFO. | |
1854 | + */ | |
1855 | +#ifdef __HAVE_ARCH_VSYSCALL | |
1856 | + map_vsyscall(); | |
1857 | +#endif | |
1858 | + | |
1859 | compute_creds(bprm); | |
1860 | current->flags &= ~PF_FORKNOEXEC; | |
1861 | create_elf_tables(bprm, &elf_ex, (interpreter_type == INTERPRETER_AOUT), | |
1862 | @@ -862,6 +933,10 @@ static int load_elf_binary(struct linux_ | |
1863 | current->mm->end_data = end_data; | |
1864 | current->mm->start_stack = bprm->p; | |
1865 | ||
1866 | +#ifdef __HAVE_ARCH_RANDOMIZE_BRK | |
1867 | + if (!(current->mm->def_flags & VM_EXEC)) | |
1868 | + randomize_brk(elf_brk); | |
1869 | +#endif | |
1870 | if (current->personality & MMAP_PAGE_ZERO) { | |
1871 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, | |
1872 | and some applications "depend" upon this behavior. | |
1873 | --- linux/fs/exec.c.orig | |
1874 | +++ linux/fs/exec.c | |
1875 | @@ -389,7 +389,12 @@ int setup_arg_pages(struct linux_binprm | |
1876 | while (i < MAX_ARG_PAGES) | |
1877 | bprm->page[i++] = NULL; | |
1878 | #else | |
1879 | +#ifdef __HAVE_ARCH_ALIGN_STACK | |
1880 | + stack_base = arch_align_stack(STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE); | |
1881 | + stack_base = PAGE_ALIGN(stack_base); | |
1882 | +#else | |
1883 | stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE; | |
1884 | +#endif | |
1885 | mm->arg_start = bprm->p + stack_base; | |
1886 | arg_size = STACK_TOP - (PAGE_MASK & (unsigned long) mm->arg_start); | |
1887 | #endif | |
1888 | @@ -430,6 +435,7 @@ int setup_arg_pages(struct linux_binprm | |
1889 | mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC; | |
1890 | else | |
1891 | mpnt->vm_flags = VM_STACK_FLAGS; | |
1892 | + mpnt->vm_flags |= mm->def_flags; | |
1893 | mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7]; | |
1894 | insert_vm_struct(mm, mpnt); | |
1895 | mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; | |
1896 | @@ -886,8 +892,13 @@ int prepare_binprm(struct linux_binprm * | |
1897 | ||
1898 | if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { | |
1899 | /* Set-uid? */ | |
1900 | - if (mode & S_ISUID) | |
1901 | + if (mode & S_ISUID) { | |
1902 | bprm->e_uid = inode->i_uid; | |
1903 | +#ifdef __i386__ | |
1904 | + /* reset personality */ | |
1905 | + current->personality = PER_LINUX; | |
1906 | +#endif | |
1907 | + } | |
1908 | ||
1909 | /* Set-gid? */ | |
1910 | /* | |
1911 | @@ -895,8 +906,13 @@ int prepare_binprm(struct linux_binprm * | |
1912 | * is a candidate for mandatory locking, not a setgid | |
1913 | * executable. | |
1914 | */ | |
1915 | - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) | |
1916 | + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | |
1917 | bprm->e_gid = inode->i_gid; | |
1918 | +#ifdef __i386__ | |
1919 | + /* reset personality */ | |
1920 | + current->personality = PER_LINUX; | |
1921 | +#endif | |
1922 | + } | |
1923 | } | |
1924 | ||
1925 | /* fill in binprm security blob */ | |
1926 | --- linux/kernel/fork.c.orig | |
1927 | +++ linux/kernel/fork.c | |
1928 | @@ -417,6 +417,9 @@ static struct mm_struct * mm_init(struct | |
1929 | ||
1930 | if (likely(!mm_alloc_pgd(mm))) { | |
1931 | mm->def_flags = 0; | |
1932 | +#ifdef __HAVE_ARCH_MMAP_TOP | |
1933 | + mm->mmap_top = mmap_top(); | |
1934 | +#endif | |
1935 | return mm; | |
1936 | } | |
1937 | free_mm(mm); | |
1938 | --- linux/kernel/signal.c.orig | |
1939 | +++ linux/kernel/signal.c | |
1940 | @@ -1552,6 +1552,34 @@ do_notify_parent_cldstop(struct task_str | |
1941 | spin_unlock_irqrestore(&sighand->siglock, flags); | |
1942 | } | |
1943 | ||
1944 | +int print_fatal_signals = 0; | |
1945 | + | |
1946 | +static void print_fatal_signal(struct pt_regs *regs, int signr) | |
1947 | +{ | |
1948 | + int i; | |
1949 | + unsigned char insn; | |
1950 | + printk("%s/%d: potentially unexpected fatal signal %d.\n", | |
1951 | + current->comm, current->pid, signr); | |
1952 | + | |
1953 | +#ifdef __i386__ | |
1954 | + printk("code at %08lx: ", regs->eip); | |
1955 | + for (i = 0; i < 16; i++) { | |
1956 | + __get_user(insn, (unsigned char *)(regs->eip + i)); | |
1957 | + printk("%02x ", insn); | |
1958 | + } | |
1959 | +#endif | |
1960 | + printk("\n"); | |
1961 | + show_regs(regs); | |
1962 | +} | |
1963 | + | |
1964 | +static int __init setup_print_fatal_signals(char *str) | |
1965 | +{ | |
1966 | + get_option (&str, &print_fatal_signals); | |
1967 | + | |
1968 | + return 1; | |
1969 | +} | |
1970 | + | |
1971 | +__setup("print-fatal-signals=", setup_print_fatal_signals); | |
1972 | ||
1973 | #ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER | |
1974 | ||
1975 | @@ -1743,6 +1771,11 @@ relock: | |
1976 | if (!signr) | |
1977 | break; /* will return 0 */ | |
1978 | ||
1979 | + if ((signr == SIGSEGV) && print_fatal_signals) { | |
1980 | + spin_unlock_irq(¤t->sighand->siglock); | |
1981 | + print_fatal_signal(regs, signr); | |
1982 | + spin_lock_irq(¤t->sighand->siglock); | |
1983 | + } | |
1984 | if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { | |
1985 | ptrace_signal_deliver(regs, cookie); | |
1986 | ||
1987 | @@ -1847,6 +1880,8 @@ relock: | |
1988 | * Anything else is fatal, maybe with a core dump. | |
1989 | */ | |
1990 | current->flags |= PF_SIGNALED; | |
1991 | + if (print_fatal_signals) | |
1992 | + print_fatal_signal(regs, signr); | |
1993 | if (sig_kernel_coredump(signr) && | |
1994 | do_coredump((long)signr, signr, regs)) { | |
1995 | /* | |
1996 | --- linux/kernel/sysctl.c.orig | |
1997 | +++ linux/kernel/sysctl.c | |
1998 | @@ -63,6 +63,29 @@ extern int min_free_kbytes; | |
1999 | extern int printk_ratelimit_jiffies; | |
2000 | extern int printk_ratelimit_burst; | |
2001 | ||
2002 | +extern unsigned int vdso_enabled; | |
2003 | + | |
2004 | +int exec_shield = 2; | |
2005 | +int exec_shield_randomize = 1; | |
2006 | + | |
2007 | +static int __init setup_exec_shield(char *str) | |
2008 | +{ | |
2009 | + get_option (&str, &exec_shield); | |
2010 | + | |
2011 | + return 1; | |
2012 | +} | |
2013 | + | |
2014 | +__setup("exec-shield=", setup_exec_shield); | |
2015 | + | |
2016 | +static int __init setup_exec_shield_randomize(char *str) | |
2017 | +{ | |
2018 | + get_option (&str, &exec_shield_randomize); | |
2019 | + | |
2020 | + return 1; | |
2021 | +} | |
2022 | + | |
2023 | +__setup("exec-shield-randomize=", setup_exec_shield_randomize); | |
2024 | + | |
2025 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ | |
2026 | static int maxolduid = 65535; | |
2027 | static int minolduid; | |
2028 | @@ -266,6 +289,40 @@ static ctl_table kern_table[] = { | |
2029 | .proc_handler = &proc_dointvec, | |
2030 | }, | |
2031 | { | |
2032 | + .ctl_name = KERN_PANIC, | |
2033 | + .procname = "exec-shield", | |
2034 | + .data = &exec_shield, | |
2035 | + .maxlen = sizeof(int), | |
2036 | + .mode = 0644, | |
2037 | + .proc_handler = &proc_dointvec, | |
2038 | + }, | |
2039 | + { | |
2040 | + .ctl_name = KERN_PANIC, | |
2041 | + .procname = "exec-shield-randomize", | |
2042 | + .data = &exec_shield_randomize, | |
2043 | + .maxlen = sizeof(int), | |
2044 | + .mode = 0644, | |
2045 | + .proc_handler = &proc_dointvec, | |
2046 | + }, | |
2047 | + { | |
2048 | + .ctl_name = KERN_PANIC, | |
2049 | + .procname = "print-fatal-signals", | |
2050 | + .data = &print_fatal_signals, | |
2051 | + .maxlen = sizeof(int), | |
2052 | + .mode = 0644, | |
2053 | + .proc_handler = &proc_dointvec, | |
2054 | + }, | |
2055 | +#if __i386__ | |
2056 | + { | |
2057 | + .ctl_name = KERN_PANIC, | |
2058 | + .procname = "vdso", | |
2059 | + .data = &vdso_enabled, | |
2060 | + .maxlen = sizeof(int), | |
2061 | + .mode = 0644, | |
2062 | + .proc_handler = &proc_dointvec, | |
2063 | + }, | |
2064 | +#endif | |
2065 | + { | |
2066 | .ctl_name = KERN_CORE_USES_PID, | |
2067 | .procname = "core_uses_pid", | |
2068 | .data = &core_uses_pid, | |
2069 | --- linux/mm/fremap.c.orig | |
2070 | +++ linux/mm/fremap.c | |
2071 | @@ -61,12 +61,6 @@ int install_page(struct mm_struct *mm, s | |
2072 | pmd_t *pmd; | |
2073 | pte_t pte_val; | |
2074 | ||
2075 | - /* | |
2076 | - * We use page_add_file_rmap below: if install_page is | |
2077 | - * ever extended to anonymous pages, this will warn us. | |
2078 | - */ | |
2079 | - BUG_ON(!page_mapping(page)); | |
2080 | - | |
2081 | pgd = pgd_offset(mm, addr); | |
2082 | spin_lock(&mm->page_table_lock); | |
2083 | ||
2084 | --- linux/mm/mmap.c.orig | |
2085 | +++ linux/mm/mmap.c | |
2086 | @@ -244,6 +244,8 @@ static inline void | |
2087 | __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, | |
2088 | struct vm_area_struct *prev, struct rb_node *rb_parent) | |
2089 | { | |
2090 | + if (vma->vm_flags & VM_EXEC) | |
2091 | + arch_add_exec_range(mm, vma->vm_end); | |
2092 | if (prev) { | |
2093 | vma->vm_next = prev->vm_next; | |
2094 | prev->vm_next = vma; | |
2095 | @@ -348,6 +350,8 @@ __vma_unlink(struct mm_struct *mm, struc | |
2096 | rb_erase(&vma->vm_rb, &mm->mm_rb); | |
2097 | if (mm->mmap_cache == vma) | |
2098 | mm->mmap_cache = prev; | |
2099 | + if (vma->vm_flags & VM_EXEC) | |
2100 | + arch_remove_exec_range(mm, vma->vm_end); | |
2101 | } | |
2102 | ||
2103 | /* | |
2104 | @@ -646,6 +650,8 @@ struct vm_area_struct *vma_merge(struct | |
2105 | } else /* cases 2, 5, 7 */ | |
2106 | vma_adjust(prev, prev->vm_start, | |
2107 | end, prev->vm_pgoff, NULL); | |
2108 | + if (prev->vm_flags & VM_EXEC) | |
2109 | + arch_add_exec_range(mm, prev->vm_end); | |
2110 | return prev; | |
2111 | } | |
2112 | ||
2113 | @@ -782,7 +788,7 @@ unsigned long do_mmap_pgoff(struct file | |
2114 | /* Obtain the address to map to. we verify (or select) it and ensure | |
2115 | * that it represents a valid section of the address space. | |
2116 | */ | |
2117 | - addr = get_unmapped_area(file, addr, len, pgoff, flags); | |
2118 | + addr = get_unmapped_area(file, addr, len, pgoff, flags, prot & PROT_EXEC); | |
2119 | if (addr & ~PAGE_MASK) | |
2120 | return addr; | |
2121 | ||
2122 | @@ -1016,7 +1022,7 @@ EXPORT_SYMBOL(do_mmap_pgoff); | |
2123 | #ifndef HAVE_ARCH_UNMAPPED_AREA | |
2124 | static inline unsigned long | |
2125 | arch_get_unmapped_area(struct file *filp, unsigned long addr, | |
2126 | - unsigned long len, unsigned long pgoff, unsigned long flags) | |
2127 | + unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec) | |
2128 | { | |
2129 | struct mm_struct *mm = current->mm; | |
2130 | struct vm_area_struct *vma; | |
2131 | @@ -1061,12 +1067,12 @@ full_search: | |
2132 | #else | |
2133 | extern unsigned long | |
2134 | arch_get_unmapped_area(struct file *, unsigned long, unsigned long, | |
2135 | - unsigned long, unsigned long); | |
2136 | + unsigned long, unsigned long, unsigned long); | |
2137 | #endif | |
2138 | ||
2139 | unsigned long | |
2140 | get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, | |
2141 | - unsigned long pgoff, unsigned long flags) | |
2142 | + unsigned long pgoff, unsigned long flags, unsigned long exec) | |
2143 | { | |
2144 | if (flags & MAP_FIXED) { | |
2145 | unsigned long ret; | |
2146 | @@ -1098,7 +1104,7 @@ get_unmapped_area(struct file *file, uns | |
2147 | return file->f_op->get_unmapped_area(file, addr, len, | |
2148 | pgoff, flags); | |
2149 | ||
2150 | - return arch_get_unmapped_area(file, addr, len, pgoff, flags); | |
2151 | + return arch_get_unmapped_area(file, addr, len, pgoff, flags, exec); | |
2152 | } | |
2153 | ||
2154 | EXPORT_SYMBOL(get_unmapped_area); | |
2155 | @@ -1176,6 +1182,14 @@ out: | |
2156 | return prev ? prev->vm_next : vma; | |
2157 | } | |
2158 | ||
2159 | + | |
2160 | +static int over_stack_limit(unsigned long sz) | |
2161 | +{ | |
2162 | + if (sz < EXEC_STACK_BIAS) | |
2163 | + return 0; | |
2164 | + return (sz - EXEC_STACK_BIAS) > current->rlim[RLIMIT_STACK].rlim_cur; | |
2165 | +} | |
2166 | + | |
2167 | #ifdef CONFIG_STACK_GROWSUP | |
2168 | /* | |
2169 | * vma is the first one with address > vma->vm_end. Have to extend vma. | |
2170 | @@ -1210,7 +1224,7 @@ int expand_stack(struct vm_area_struct * | |
2171 | return -ENOMEM; | |
2172 | } | |
2173 | ||
2174 | - if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || | |
2175 | + if (over_stack_limit(address - vma->vm_start) || | |
2176 | ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > | |
2177 | current->rlim[RLIMIT_AS].rlim_cur) { | |
2178 | anon_vma_unlock(vma); | |
2179 | @@ -1271,7 +1285,7 @@ int expand_stack(struct vm_area_struct * | |
2180 | return -ENOMEM; | |
2181 | } | |
2182 | ||
2183 | - if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || | |
2184 | + if (over_stack_limit(vma->vm_end - address) || | |
2185 | ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > | |
2186 | current->rlim[RLIMIT_AS].rlim_cur) { | |
2187 | anon_vma_unlock(vma); | |
2188 | @@ -1384,6 +1398,7 @@ no_mmaps: | |
2189 | static void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area) | |
2190 | { | |
2191 | size_t len = area->vm_end - area->vm_start; | |
2192 | + unsigned long old_end = area->vm_end; | |
2193 | ||
2194 | area->vm_mm->total_vm -= len >> PAGE_SHIFT; | |
2195 | if (area->vm_flags & VM_LOCKED) | |
2196 | @@ -1394,8 +1409,14 @@ static void unmap_vma(struct mm_struct * | |
2197 | if (area->vm_start >= TASK_UNMAPPED_BASE && | |
2198 | area->vm_start < area->vm_mm->free_area_cache) | |
2199 | area->vm_mm->free_area_cache = area->vm_start; | |
2200 | - | |
2201 | + /* | |
2202 | + * Is this a new hole at the highest possible address? | |
2203 | + */ | |
2204 | + if (area->vm_start > area->vm_mm->non_executable_cache) | |
2205 | + area->vm_mm->non_executable_cache = area->vm_start; | |
2206 | remove_vm_struct(area); | |
2207 | + if (unlikely(area->vm_flags & VM_EXEC)) | |
2208 | + arch_remove_exec_range(mm, old_end); | |
2209 | } | |
2210 | ||
2211 | /* | |
2212 | @@ -1505,10 +1526,14 @@ int split_vma(struct mm_struct * mm, str | |
2213 | if (new->vm_ops && new->vm_ops->open) | |
2214 | new->vm_ops->open(new); | |
2215 | ||
2216 | - if (new_below) | |
2217 | + if (new_below) { | |
2218 | + unsigned long old_end = vma->vm_end; | |
2219 | + | |
2220 | vma_adjust(vma, addr, vma->vm_end, vma->vm_pgoff + | |
2221 | ((addr - new->vm_start) >> PAGE_SHIFT), new); | |
2222 | - else | |
2223 | + if (vma->vm_flags & VM_EXEC) | |
2224 | + arch_remove_exec_range(mm, old_end); | |
2225 | + } else | |
2226 | vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new); | |
2227 | ||
2228 | return 0; | |
2229 | @@ -1716,6 +1741,7 @@ void exit_mmap(struct mm_struct *mm) | |
2230 | mm->rss = 0; | |
2231 | mm->total_vm = 0; | |
2232 | mm->locked_vm = 0; | |
2233 | + arch_flush_exec_range(mm); | |
2234 | ||
2235 | spin_unlock(&mm->page_table_lock); | |
2236 | ||
2237 | --- linux/mm/mprotect.c.orig | |
2238 | +++ linux/mm/mprotect.c | |
2239 | @@ -20,6 +20,7 @@ | |
2240 | ||
2241 | #include <asm/uaccess.h> | |
2242 | #include <asm/pgtable.h> | |
2243 | +#include <asm/pgalloc.h> | |
2244 | #include <asm/cacheflush.h> | |
2245 | #include <asm/tlbflush.h> | |
2246 | ||
2247 | @@ -112,8 +113,9 @@ mprotect_fixup(struct vm_area_struct *vm | |
2248 | unsigned long start, unsigned long end, unsigned int newflags) | |
2249 | { | |
2250 | struct mm_struct * mm = vma->vm_mm; | |
2251 | - unsigned long charged = 0; | |
2252 | + unsigned long charged = 0, old_end = vma->vm_end; | |
2253 | pgprot_t newprot; | |
2254 | + unsigned int oldflags; | |
2255 | pgoff_t pgoff; | |
2256 | int error; | |
2257 | ||
2258 | @@ -174,8 +176,11 @@ success: | |
2259 | * vm_flags and vm_page_prot are protected by the mmap_sem | |
2260 | * held in write mode. | |
2261 | */ | |
2262 | + oldflags = vma->vm_flags; | |
2263 | vma->vm_flags = newflags; | |
2264 | vma->vm_page_prot = newprot; | |
2265 | + if (oldflags & VM_EXEC) | |
2266 | + arch_remove_exec_range(current->mm, old_end); | |
2267 | change_protection(vma, start, end, newprot); | |
2268 | return 0; | |
2269 | ||
2270 | --- linux/mm/mremap.c.orig | |
2271 | +++ linux/mm/mremap.c | |
2272 | @@ -380,7 +380,8 @@ unsigned long do_mremap(unsigned long ad | |
2273 | map_flags |= MAP_SHARED; | |
2274 | ||
2275 | new_addr = get_unmapped_area(vma->vm_file, 0, new_len, | |
2276 | - vma->vm_pgoff, map_flags); | |
2277 | + vma->vm_pgoff, map_flags, | |
2278 | + vma->vm_flags & VM_EXEC); | |
2279 | ret = new_addr; | |
2280 | if (new_addr & ~PAGE_MASK) | |
2281 | goto out; | |
2282 | --- linux/mm/vmalloc.c.orig | |
2283 | +++ linux/mm/vmalloc.c | |
2284 | @@ -455,6 +455,28 @@ void *vmalloc(unsigned long size) | |
2285 | EXPORT_SYMBOL(vmalloc); | |
2286 | ||
2287 | /** | |
2288 | + * vmalloc_exec - allocate virtually contiguous, executable memory | |
2289 | + * | |
2290 | + * @size: allocation size | |
2291 | + * | |
2292 | + * Kernel-internal function to allocate enough pages to cover @size | |
2293 | + * the page level allocator and map them into contiguous and | |
2294 | + * executable kernel virtual space. | |
2295 | + * | |
2296 | + * For tight cotrol over page level allocator and protection flags | |
2297 | + * use __vmalloc() instead. | |
2298 | + */ | |
2299 | + | |
2300 | +#ifndef PAGE_KERNEL_EXEC | |
2301 | +# define PAGE_KERNEL_EXEC PAGE_KERNEL | |
2302 | +#endif | |
2303 | + | |
2304 | +void *vmalloc_exec(unsigned long size) | |
2305 | +{ | |
2306 | + return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC); | |
2307 | +} | |
2308 | + | |
2309 | +/** | |
2310 | * vmalloc_32 - allocate virtually contiguous memory (32bit addressable) | |
2311 | * | |
2312 | * @size: allocation size |