xref: /kernel/linux/linux-6.6/arch/x86/um/vdso/vma.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011 Richard Weinberger <richrd@nod.at>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/sched.h>
862306a36Sopenharmony_ci#include <linux/mm.h>
962306a36Sopenharmony_ci#include <asm/page.h>
1062306a36Sopenharmony_ci#include <asm/elf.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic unsigned int __read_mostly vdso_enabled = 1;
1462306a36Sopenharmony_ciunsigned long um_vdso_addr;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciextern unsigned long task_size;
1762306a36Sopenharmony_ciextern char vdso_start[], vdso_end[];
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic struct page **vdsop;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic int __init init_vdso(void)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct page *um_vdso;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	BUG_ON(vdso_end - vdso_start > PAGE_SIZE);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	um_vdso_addr = task_size - PAGE_SIZE;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL);
3062306a36Sopenharmony_ci	if (!vdsop)
3162306a36Sopenharmony_ci		goto oom;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	um_vdso = alloc_page(GFP_KERNEL);
3462306a36Sopenharmony_ci	if (!um_vdso) {
3562306a36Sopenharmony_ci		kfree(vdsop);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci		goto oom;
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	copy_page(page_address(um_vdso), vdso_start);
4162306a36Sopenharmony_ci	*vdsop = um_vdso;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return 0;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cioom:
4662306a36Sopenharmony_ci	printk(KERN_ERR "Cannot allocate vdso\n");
4762306a36Sopenharmony_ci	vdso_enabled = 0;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return -ENOMEM;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_cisubsys_initcall(init_vdso);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciint arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	int err;
5662306a36Sopenharmony_ci	struct mm_struct *mm = current->mm;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (!vdso_enabled)
5962306a36Sopenharmony_ci		return 0;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (mmap_write_lock_killable(mm))
6262306a36Sopenharmony_ci		return -EINTR;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE,
6562306a36Sopenharmony_ci		VM_READ|VM_EXEC|
6662306a36Sopenharmony_ci		VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
6762306a36Sopenharmony_ci		vdsop);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	mmap_write_unlock(mm);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return err;
7262306a36Sopenharmony_ci}
73