76 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			76 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2011 Richard Weinberger <richrd@nod.at>
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License version 2 as
 | |
|  * published by the Free Software Foundation.
 | |
|  */
 | |
| 
 | |
| #include <linux/slab.h>
 | |
| #include <linux/sched.h>
 | |
| #include <linux/mm.h>
 | |
| #include <asm/page.h>
 | |
| #include <asm/elf.h>
 | |
| #include <linux/init.h>
 | |
| 
 | |
| static unsigned int __read_mostly vdso_enabled = 1;
 | |
| unsigned long um_vdso_addr;
 | |
| 
 | |
| extern unsigned long task_size;
 | |
| extern char vdso_start[], vdso_end[];
 | |
| 
 | |
| static struct page **vdsop;
 | |
| 
 | |
| static int __init init_vdso(void)
 | |
| {
 | |
| 	struct page *um_vdso;
 | |
| 
 | |
| 	BUG_ON(vdso_end - vdso_start > PAGE_SIZE);
 | |
| 
 | |
| 	um_vdso_addr = task_size - PAGE_SIZE;
 | |
| 
 | |
| 	vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL);
 | |
| 	if (!vdsop)
 | |
| 		goto oom;
 | |
| 
 | |
| 	um_vdso = alloc_page(GFP_KERNEL);
 | |
| 	if (!um_vdso) {
 | |
| 		kfree(vdsop);
 | |
| 
 | |
| 		goto oom;
 | |
| 	}
 | |
| 
 | |
| 	copy_page(page_address(um_vdso), vdso_start);
 | |
| 	*vdsop = um_vdso;
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| oom:
 | |
| 	printk(KERN_ERR "Cannot allocate vdso\n");
 | |
| 	vdso_enabled = 0;
 | |
| 
 | |
| 	return -ENOMEM;
 | |
| }
 | |
| subsys_initcall(init_vdso);
 | |
| 
 | |
| int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 | |
| {
 | |
| 	int err;
 | |
| 	struct mm_struct *mm = current->mm;
 | |
| 
 | |
| 	if (!vdso_enabled)
 | |
| 		return 0;
 | |
| 
 | |
| 	if (mmap_write_lock_killable(mm))
 | |
| 		return -EINTR;
 | |
| 
 | |
| 	err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE,
 | |
| 		VM_READ|VM_EXEC|
 | |
| 		VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 | |
| 		vdsop);
 | |
| 
 | |
| 	mmap_write_unlock(mm);
 | |
| 
 | |
| 	return err;
 | |
| }
 |