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

ARM: add a vma entry for the user accessible vector page

The kernel makes the high vector page visible to user space. This page
contains (amongst others) small code segments that can be executed in
user space. Make this page visible through ptrace and /proc/<pid>/mem
in order to let gdb perform code parsing needed for proper unwinding.

For example, the ERESTART_RESTARTBLOCK handler actually has a stack
frame -- it returns to a PC value stored on the user's stack. To
unwind after a "sleep" system call was interrupted twice, GDB would
have to recognize this situation and understand that stack frame
layout -- which it currently cannot do.

We could fix this by hard-coding addresses in the vector page range into
GDB, but that isn't really portable as not all of those addresses are
guaranteed to remain stable across kernel releases. And having the gdb
process make an exception for this page and get content from its own
address space for it looks strange, and it is not future proof either.

Being located above PAGE_OFFSET, this vma cannot be deleted by
user space code.

Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>

authored by

Nicolas Pitre and committed by
Nicolas Pitre
ec706dab 70c70d97

+53 -1
+4
arch/arm/include/asm/elf.h
··· 127 127 extern unsigned long arch_randomize_brk(struct mm_struct *mm); 128 128 #define arch_randomize_brk arch_randomize_brk 129 129 130 + extern int vectors_user_mapping(void); 131 + #define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping() 132 + #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 133 + 130 134 #endif
+28 -1
arch/arm/include/asm/mmu_context.h
··· 18 18 #include <asm/cacheflush.h> 19 19 #include <asm/cachetype.h> 20 20 #include <asm/proc-fns.h> 21 - #include <asm-generic/mm_hooks.h> 22 21 23 22 void __check_kvm_seq(struct mm_struct *mm); 24 23 ··· 132 133 133 134 #define deactivate_mm(tsk,mm) do { } while (0) 134 135 #define activate_mm(prev,next) switch_mm(prev, next, NULL) 136 + 137 + /* 138 + * We are inserting a "fake" vma for the user-accessible vector page so 139 + * gdb and friends can get to it through ptrace and /proc/<pid>/mem. 140 + * But we also want to remove it before the generic code gets to see it 141 + * during process exit or the unmapping of it would cause total havoc. 142 + * (the macro is used as remove_vma() is static to mm/mmap.c) 143 + */ 144 + #define arch_exit_mmap(mm) \ 145 + do { \ 146 + struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \ 147 + if (high_vma) { \ 148 + BUG_ON(high_vma->vm_next); /* it should be last */ \ 149 + if (high_vma->vm_prev) \ 150 + high_vma->vm_prev->vm_next = NULL; \ 151 + else \ 152 + mm->mmap = NULL; \ 153 + rb_erase(&high_vma->vm_rb, &mm->mm_rb); \ 154 + mm->mmap_cache = NULL; \ 155 + mm->map_count--; \ 156 + remove_vma(high_vma); \ 157 + } \ 158 + } while (0) 159 + 160 + static inline void arch_dup_mmap(struct mm_struct *oldmm, 161 + struct mm_struct *mm) 162 + { 163 + } 135 164 136 165 #endif
+21
arch/arm/kernel/process.c
··· 458 458 unsigned long range_end = mm->brk + 0x02000000; 459 459 return randomize_range(mm->brk, range_end, 0) ? : mm->brk; 460 460 } 461 + 462 + /* 463 + * The vectors page is always readable from user space for the 464 + * atomic helpers and the signal restart code. Let's declare a mapping 465 + * for it so it is visible through ptrace and /proc/<pid>/mem. 466 + */ 467 + 468 + int vectors_user_mapping(void) 469 + { 470 + struct mm_struct *mm = current->mm; 471 + return install_special_mapping(mm, 0xffff0000, PAGE_SIZE, 472 + VM_READ | VM_EXEC | 473 + VM_MAYREAD | VM_MAYEXEC | 474 + VM_ALWAYSDUMP | VM_RESERVED, 475 + NULL); 476 + } 477 + 478 + const char *arch_vma_name(struct vm_area_struct *vma) 479 + { 480 + return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL; 481 + }