X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fx86_64%2Fia32%2Fsyscall32.c;h=d8ea6d9fcb2976ae8fbb16ea459cf8a831ad5eea;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=01d8db1a1c09c7bff982a740bf5222735e996893;hpb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;p=linux-2.6.git diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c index 01d8db1a1..d8ea6d9fc 100644 --- a/arch/x86_64/ia32/syscall32.c +++ b/arch/x86_64/ia32/syscall32.c @@ -10,26 +10,22 @@ #include #include #include +#include #include #include #include -/* 32bit VDSOs mapped into user space. */ -asm(".section \".init.data\",\"aw\"\n" - "syscall32_syscall:\n" - ".incbin \"arch/x86_64/ia32/vsyscall-syscall.so\"\n" - "syscall32_syscall_end:\n" - "syscall32_sysenter:\n" - ".incbin \"arch/x86_64/ia32/vsyscall-sysenter.so\"\n" - "syscall32_sysenter_end:\n" - ".previous"); - +#ifdef USE_INT80 +extern unsigned char syscall32_int80[], syscall32_int80_end[]; +#endif extern unsigned char syscall32_syscall[], syscall32_syscall_end[]; extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[]; extern int sysctl_vsyscall32; char *syscall32_page; +#ifndef USE_INT80 static int use_sysenter = -1; +#endif static struct page * syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type) @@ -52,43 +48,69 @@ static struct vm_operations_struct syscall32_vm_ops = { struct linux_binprm; /* Setup a VMA at program startup for the vsyscall page */ -int syscall32_setup_pages(struct linux_binprm *bprm, int exstack) +int syscall32_setup_pages(struct linux_binprm *bprm, int exstack, + unsigned long start_code, + unsigned long interp_map_address) { int npages = (VSYSCALL32_END - VSYSCALL32_BASE) >> PAGE_SHIFT; struct vm_area_struct *vma; struct mm_struct *mm = current->mm; + int ret; - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!vma) return -ENOMEM; - if (security_vm_enough_memory(npages)) { - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } memset(vma, 0, sizeof(struct vm_area_struct)); /* Could randomize here */ vma->vm_start = VSYSCALL32_BASE; vma->vm_end = VSYSCALL32_END; /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYEXEC|VM_MAYWRITE; + vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; + /* + * Make sure the vDSO gets into every core dump. + * Dumping its contents makes post-mortem fully interpretable later + * without matching up the same kernel and hardware config to see + * what PC values meant. + */ + vma->vm_flags |= VM_ALWAYSDUMP; vma->vm_flags |= mm->def_flags; vma->vm_page_prot = protection_map[vma->vm_flags & 7]; vma->vm_ops = &syscall32_vm_ops; vma->vm_mm = mm; down_write(&mm->mmap_sem); - insert_vm_struct(mm, vma); - mm->total_vm += npages; + if ((ret = insert_vm_struct(mm, vma))) { + up_write(&mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return ret; + } + vx_vmpages_add(mm, npages); up_write(&mm->mmap_sem); return 0; } +const char *arch_vma_name(struct vm_area_struct *vma) +{ + if (vma->vm_start == VSYSCALL32_BASE && + vma->vm_mm && vma->vm_mm->task_size == IA32_PAGE_OFFSET) + return "[vdso]"; + return NULL; +} + static int __init init_syscall32(void) { syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); if (!syscall32_page) panic("Cannot allocate syscall32 page"); + +#ifdef USE_INT80 + /* + * At this point we use int 0x80. + */ + memcpy(syscall32_page, syscall32_int80, + syscall32_int80_end - syscall32_int80); +#else if (use_sysenter > 0) { memcpy(syscall32_page, syscall32_sysenter, syscall32_sysenter_end - syscall32_sysenter); @@ -96,14 +118,20 @@ static int __init init_syscall32(void) memcpy(syscall32_page, syscall32_syscall, syscall32_syscall_end - syscall32_syscall); } +#endif return 0; } - -__initcall(init_syscall32); + +/* + * This must be done early in case we have an initrd containing 32-bit + * binaries (e.g., hotplug). This could be pushed upstream to arch/x86_64. + */ +core_initcall(init_syscall32); /* May not be __init: called during resume */ void syscall32_cpu_init(void) { +#ifndef USE_INT80 if (use_sysenter < 0) use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL); @@ -114,4 +142,5 @@ void syscall32_cpu_init(void) checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target); wrmsrl(MSR_CSTAR, ia32_cstar_target); +#endif }