76 строки
1.4 KiB
C
76 строки
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 (down_write_killable(&mm->mmap_sem))
|
|
return -EINTR;
|
|
|
|
err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE,
|
|
VM_READ|VM_EXEC|
|
|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
|
|
vdsop);
|
|
|
|
up_write(&mm->mmap_sem);
|
|
|
|
return err;
|
|
}
|