diff options
author | dchagin <dchagin@FreeBSD.org> | 2016-07-18 16:38:06 +0000 |
---|---|---|
committer | dchagin <dchagin@FreeBSD.org> | 2016-07-18 16:38:06 +0000 |
commit | 4188ab5f11c8ca7f88ef10c16a0142b825be793a (patch) | |
tree | a181e54bb5eb81dd5dda106d3c87c3b757cc8c20 /sys/amd64/linux/linux_machdep.c | |
parent | 899ae9ac6c6805c6f984f338c9f4d3b3f3b0375b (diff) | |
download | FreeBSD-src-4188ab5f11c8ca7f88ef10c16a0142b825be793a.zip FreeBSD-src-4188ab5f11c8ca7f88ef10c16a0142b825be793a.tar.gz |
MFC r302517:
Fix a copy/paste bug introduced during X86_64 Linuxulator work.
FreeBSD support NX bit on X86_64 processors out of the box, for i386 emulation
use READ_IMPLIES_EXEC flag, introduced in r302515.
While here move common part of mmap() and mprotect() code to the files in compat/linux
to reduce code dupcliation between Linuxulator's
Approved by: re (gjb)
Diffstat (limited to 'sys/amd64/linux/linux_machdep.c')
-rw-r--r-- | sys/amd64/linux/linux_machdep.c | 169 |
1 files changed, 4 insertions, 165 deletions
diff --git a/sys/amd64/linux/linux_machdep.c b/sys/amd64/linux/linux_machdep.c index 0459ba7..80c48aa 100644 --- a/sys/amd64/linux/linux_machdep.c +++ b/sys/amd64/linux/linux_machdep.c @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$"); #include <compat/linux/linux_ipc.h> #include <compat/linux/linux_file.h> #include <compat/linux/linux_misc.h> +#include <compat/linux/linux_mmap.h> #include <compat/linux/linux_signal.h> #include <compat/linux/linux_util.h> #include <compat/linux/linux_emul.h> @@ -122,181 +123,19 @@ linux_set_upcall_kse(struct thread *td, register_t stack) return (0); } -#define STACK_SIZE (2 * 1024 * 1024) -#define GUARD_SIZE (4 * PAGE_SIZE) - int linux_mmap2(struct thread *td, struct linux_mmap2_args *args) { - struct proc *p = td->td_proc; - struct mmap_args /* { - caddr_t addr; - size_t len; - int prot; - int flags; - int fd; - long pad; - off_t pos; - } */ bsd_args; - int error; - struct file *fp; - cap_rights_t rights; - - LINUX_CTR6(mmap2, "0x%lx, %ld, %ld, 0x%08lx, %ld, 0x%lx", - args->addr, args->len, args->prot, - args->flags, args->fd, args->pgoff); - - error = 0; - bsd_args.flags = 0; - fp = NULL; - - /* - * Linux mmap(2): - * You must specify exactly one of MAP_SHARED and MAP_PRIVATE - */ - if (! ((args->flags & LINUX_MAP_SHARED) ^ - (args->flags & LINUX_MAP_PRIVATE))) - return (EINVAL); - - if (args->flags & LINUX_MAP_SHARED) - bsd_args.flags |= MAP_SHARED; - if (args->flags & LINUX_MAP_PRIVATE) - bsd_args.flags |= MAP_PRIVATE; - if (args->flags & LINUX_MAP_FIXED) - bsd_args.flags |= MAP_FIXED; - if (args->flags & LINUX_MAP_ANON) - bsd_args.flags |= MAP_ANON; - else - bsd_args.flags |= MAP_NOSYNC; - if (args->flags & LINUX_MAP_GROWSDOWN) - bsd_args.flags |= MAP_STACK; - /* - * PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC - * on Linux/i386. We do this to ensure maximum compatibility. - * Linux/ia64 does the same in i386 emulation mode. - */ - bsd_args.prot = args->prot; - if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) - bsd_args.prot |= PROT_READ | PROT_EXEC; - - /* Linux does not check file descriptor when MAP_ANONYMOUS is set. */ - bsd_args.fd = (bsd_args.flags & MAP_ANON) ? -1 : args->fd; - if (bsd_args.fd != -1) { - /* - * Linux follows Solaris mmap(2) description: - * The file descriptor fildes is opened with - * read permission, regardless of the - * protection options specified. - */ - - error = fget(td, bsd_args.fd, - cap_rights_init(&rights, CAP_MMAP), &fp); - if (error != 0 ) - return (error); - if (fp->f_type != DTYPE_VNODE) { - fdrop(fp, td); - return (EINVAL); - } - - /* Linux mmap() just fails for O_WRONLY files */ - if (!(fp->f_flag & FREAD)) { - fdrop(fp, td); - return (EACCES); - } - - fdrop(fp, td); - } - - if (args->flags & LINUX_MAP_GROWSDOWN) { - /* - * The Linux MAP_GROWSDOWN option does not limit auto - * growth of the region. Linux mmap with this option - * takes as addr the initial BOS, and as len, the initial - * region size. It can then grow down from addr without - * limit. However, Linux threads has an implicit internal - * limit to stack size of STACK_SIZE. Its just not - * enforced explicitly in Linux. But, here we impose - * a limit of (STACK_SIZE - GUARD_SIZE) on the stack - * region, since we can do this with our mmap. - * - * Our mmap with MAP_STACK takes addr as the maximum - * downsize limit on BOS, and as len the max size of - * the region. It then maps the top SGROWSIZ bytes, - * and auto grows the region down, up to the limit - * in addr. - * - * If we don't use the MAP_STACK option, the effect - * of this code is to allocate a stack region of a - * fixed size of (STACK_SIZE - GUARD_SIZE). - */ - - if ((caddr_t)PTRIN(args->addr) + args->len > - p->p_vmspace->vm_maxsaddr) { - /* - * Some Linux apps will attempt to mmap - * thread stacks near the top of their - * address space. If their TOS is greater - * than vm_maxsaddr, vm_map_growstack() - * will confuse the thread stack with the - * process stack and deliver a SEGV if they - * attempt to grow the thread stack past their - * current stacksize rlimit. To avoid this, - * adjust vm_maxsaddr upwards to reflect - * the current stacksize rlimit rather - * than the maximum possible stacksize. - * It would be better to adjust the - * mmap'ed region, but some apps do not check - * mmap's return value. - */ - PROC_LOCK(p); - p->p_vmspace->vm_maxsaddr = (char *)USRSTACK - - lim_cur_proc(p, RLIMIT_STACK); - PROC_UNLOCK(p); - } - - /* - * This gives us our maximum stack size and a new BOS. - * If we're using VM_STACK, then mmap will just map - * the top SGROWSIZ bytes, and let the stack grow down - * to the limit at BOS. If we're not using VM_STACK - * we map the full stack, since we don't have a way - * to autogrow it. - */ - if (args->len > STACK_SIZE - GUARD_SIZE) { - bsd_args.addr = (caddr_t)PTRIN(args->addr); - bsd_args.len = args->len; - } else { - bsd_args.addr = (caddr_t)PTRIN(args->addr) - - (STACK_SIZE - GUARD_SIZE - args->len); - bsd_args.len = STACK_SIZE - GUARD_SIZE; - } - } else { - bsd_args.addr = (caddr_t)PTRIN(args->addr); - bsd_args.len = args->len; - } - bsd_args.pos = (off_t)args->pgoff; - - error = sys_mmap(td, &bsd_args); - - LINUX_CTR2(mmap2, "return: %d (%p)", - error, td->td_retval[0]); - return (error); + return (linux_mmap_common(td, PTROUT(args->addr), args->len, args->prot, + args->flags, args->fd, args->pgoff)); } int linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) { - struct mprotect_args bsd_args; - - LINUX_CTR(mprotect); - bsd_args.addr = uap->addr; - bsd_args.len = uap->len; - bsd_args.prot = uap->prot; - if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) - bsd_args.prot |= PROT_READ | PROT_EXEC; - return (sys_mprotect(td, &bsd_args)); + return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len, uap->prot)); } int |