xref: /openbmc/linux/arch/x86/um/vdso/vma.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25c48b108SAl Viro /*
35c48b108SAl Viro  * Copyright (C) 2011 Richard Weinberger <richrd@nod.at>
45c48b108SAl Viro  */
55c48b108SAl Viro 
65c48b108SAl Viro #include <linux/slab.h>
75c48b108SAl Viro #include <linux/sched.h>
85c48b108SAl Viro #include <linux/mm.h>
95c48b108SAl Viro #include <asm/page.h>
109b46e212SRichard Weinberger #include <asm/elf.h>
115c48b108SAl Viro #include <linux/init.h>
125c48b108SAl Viro 
133d7ee969SAndy Lutomirski static unsigned int __read_mostly vdso_enabled = 1;
145c48b108SAl Viro unsigned long um_vdso_addr;
155c48b108SAl Viro 
165c48b108SAl Viro extern unsigned long task_size;
175c48b108SAl Viro extern char vdso_start[], vdso_end[];
185c48b108SAl Viro 
195c48b108SAl Viro static struct page **vdsop;
205c48b108SAl Viro 
init_vdso(void)215c48b108SAl Viro static int __init init_vdso(void)
225c48b108SAl Viro {
235c48b108SAl Viro 	struct page *um_vdso;
245c48b108SAl Viro 
255c48b108SAl Viro 	BUG_ON(vdso_end - vdso_start > PAGE_SIZE);
265c48b108SAl Viro 
275c48b108SAl Viro 	um_vdso_addr = task_size - PAGE_SIZE;
285c48b108SAl Viro 
290d65ede0SDave Jones 	vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL);
305c48b108SAl Viro 	if (!vdsop)
315c48b108SAl Viro 		goto oom;
325c48b108SAl Viro 
335c48b108SAl Viro 	um_vdso = alloc_page(GFP_KERNEL);
345c48b108SAl Viro 	if (!um_vdso) {
355c48b108SAl Viro 		kfree(vdsop);
365c48b108SAl Viro 
375c48b108SAl Viro 		goto oom;
385c48b108SAl Viro 	}
395c48b108SAl Viro 
405c48b108SAl Viro 	copy_page(page_address(um_vdso), vdso_start);
415c48b108SAl Viro 	*vdsop = um_vdso;
425c48b108SAl Viro 
435c48b108SAl Viro 	return 0;
445c48b108SAl Viro 
455c48b108SAl Viro oom:
465c48b108SAl Viro 	printk(KERN_ERR "Cannot allocate vdso\n");
475c48b108SAl Viro 	vdso_enabled = 0;
485c48b108SAl Viro 
495c48b108SAl Viro 	return -ENOMEM;
505c48b108SAl Viro }
515c48b108SAl Viro subsys_initcall(init_vdso);
525c48b108SAl Viro 
arch_setup_additional_pages(struct linux_binprm * bprm,int uses_interp)535c48b108SAl Viro int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
545c48b108SAl Viro {
555c48b108SAl Viro 	int err;
565c48b108SAl Viro 	struct mm_struct *mm = current->mm;
575c48b108SAl Viro 
585c48b108SAl Viro 	if (!vdso_enabled)
595c48b108SAl Viro 		return 0;
605c48b108SAl Viro 
61*d8ed45c5SMichel Lespinasse 	if (mmap_write_lock_killable(mm))
6269048176SMichal Hocko 		return -EINTR;
635c48b108SAl Viro 
645c48b108SAl Viro 	err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE,
655c48b108SAl Viro 		VM_READ|VM_EXEC|
66909af768SJason Baron 		VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
675c48b108SAl Viro 		vdsop);
685c48b108SAl Viro 
69*d8ed45c5SMichel Lespinasse 	mmap_write_unlock(mm);
705c48b108SAl Viro 
715c48b108SAl Viro 	return err;
725c48b108SAl Viro }
73