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/i386 | |
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/i386')
-rw-r--r-- | sys/i386/linux/linux.h | 7 | ||||
-rw-r--r-- | sys/i386/linux/linux_machdep.c | 188 |
2 files changed, 3 insertions, 192 deletions
diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h index 36b2084..42e836c 100644 --- a/sys/i386/linux/linux.h +++ b/sys/i386/linux/linux.h @@ -140,13 +140,6 @@ struct l_rlimit { l_ulong rlim_max; }; -/* mmap options */ -#define LINUX_MAP_SHARED 0x0001 -#define LINUX_MAP_PRIVATE 0x0002 -#define LINUX_MAP_FIXED 0x0010 -#define LINUX_MAP_ANON 0x0020 -#define LINUX_MAP_GROWSDOWN 0x0100 - struct l_mmap_argv { l_uintptr_t addr; l_size_t len; diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c index 4fb5785..4b4b886 100644 --- a/sys/i386/linux/linux_machdep.c +++ b/sys/i386/linux/linux_machdep.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <i386/linux/linux_proto.h> #include <compat/linux/linux_ipc.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> @@ -95,10 +96,6 @@ struct l_old_select_argv { struct l_timeval *timeout; }; -static int linux_mmap_common(struct thread *td, l_uintptr_t addr, - l_size_t len, l_int prot, l_int flags, l_int fd, - l_loff_t pos); - int linux_execve(struct thread *td, struct linux_execve_args *args) @@ -340,9 +337,6 @@ 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) { @@ -381,187 +375,11 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args) (uint32_t)linux_args.pgoff)); } -static int -linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot, - l_int flags, l_int fd, l_loff_t pos) -{ - 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; - - error = 0; - bsd_args.flags = 0; - fp = NULL; - - /* - * Linux mmap(2): - * You must specify exactly one of MAP_SHARED and MAP_PRIVATE - */ - if (!((flags & LINUX_MAP_SHARED) ^ (flags & LINUX_MAP_PRIVATE))) - return (EINVAL); - - if (flags & LINUX_MAP_SHARED) - bsd_args.flags |= MAP_SHARED; - if (flags & LINUX_MAP_PRIVATE) - bsd_args.flags |= MAP_PRIVATE; - if (flags & LINUX_MAP_FIXED) - bsd_args.flags |= MAP_FIXED; - if (flags & LINUX_MAP_ANON) { - /* Enforce pos to be on page boundary, then ignore. */ - if ((pos & PAGE_MASK) != 0) - return (EINVAL); - pos = 0; - bsd_args.flags |= MAP_ANON; - } else - bsd_args.flags |= MAP_NOSYNC; - if (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 = 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 : 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. - * - * Checking just CAP_MMAP is fine here, since the real work - * is done in the FreeBSD mmap(). - */ - - 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 (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 inital 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 them 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(addr) + 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 (len > STACK_SIZE - GUARD_SIZE) { - bsd_args.addr = (caddr_t)PTRIN(addr); - bsd_args.len = len; - } else { - bsd_args.addr = (caddr_t)PTRIN(addr) - - (STACK_SIZE - GUARD_SIZE - len); - bsd_args.len = STACK_SIZE - GUARD_SIZE; - } - } else { - bsd_args.addr = (caddr_t)PTRIN(addr); - bsd_args.len = len; - } - bsd_args.pos = pos; - -#ifdef DEBUG - if (ldebug(mmap)) - printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n", - __func__, - (void *)bsd_args.addr, bsd_args.len, bsd_args.prot, - bsd_args.flags, bsd_args.fd, (int)bsd_args.pos); -#endif - error = sys_mmap(td, &bsd_args); -#ifdef DEBUG - if (ldebug(mmap)) - printf("-> %s() return: 0x%x (0x%08x)\n", - __func__, error, (u_int)td->td_retval[0]); -#endif - return (error); -} - int linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) { - struct mprotect_args bsd_args; - - 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 |