diff options
author | jkim <jkim@FreeBSD.org> | 2007-02-15 00:54:40 +0000 |
---|---|---|
committer | jkim <jkim@FreeBSD.org> | 2007-02-15 00:54:40 +0000 |
commit | df99d574b5108aba65b940cbb910d8f6dae0b05f (patch) | |
tree | 7ac3a3ba87c37bfd781cdcc61e412702c7f93cc9 | |
parent | 494959a002ebd44883ca0f80a6ab843faa66893b (diff) | |
download | FreeBSD-src-df99d574b5108aba65b940cbb910d8f6dae0b05f.zip FreeBSD-src-df99d574b5108aba65b940cbb910d8f6dae0b05f.tar.gz |
MFP4: 113025, 113146, 113177, 113203, 113500, 113546, 113570
- PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC.
Linux/ia64's i386 emulation layer does this and it complies with Linux
header files. This fixes mmap05 LTP test case on amd64.
- Do not adjust stack size when failure has occurred.
- Synchronize i386 mmap/mprotect with amd64.
-rw-r--r-- | sys/amd64/linux32/linux.h | 9 | ||||
-rw-r--r-- | sys/amd64/linux32/linux32_machdep.c | 102 | ||||
-rw-r--r-- | sys/i386/linux/linux.h | 9 | ||||
-rw-r--r-- | sys/i386/linux/linux_machdep.c | 112 | ||||
-rw-r--r-- | sys/i386/linux/syscalls.master | 2 |
5 files changed, 119 insertions, 115 deletions
diff --git a/sys/amd64/linux32/linux.h b/sys/amd64/linux32/linux.h index ff8680ae..b7d071e 100644 --- a/sys/amd64/linux32/linux.h +++ b/sys/amd64/linux32/linux.h @@ -167,6 +167,15 @@ struct l_rusage { #define LINUX_MAP_ANON 0x0020 #define LINUX_MAP_GROWSDOWN 0x0100 +struct l_mmap_argv { + l_uintptr_t addr; + l_size_t len; + l_int prot; + l_int flags; + l_int fd; + l_off_t pgoff; +} __packed; + /* * stat family of syscalls */ diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index 1f49458..53ad3d4 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -690,16 +690,6 @@ linux_clone(struct thread *td, struct linux_clone_args *args) return (0); } -/* XXX move */ -struct l_mmap_argv { - l_ulong addr; - l_ulong len; - l_ulong prot; - l_ulong flags; - l_ulong fd; - l_ulong pgoff; -}; - #define STACK_SIZE (2 * 1024 * 1024) #define GUARD_SIZE (4 * PAGE_SIZE) @@ -789,9 +779,44 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) bsd_args.flags |= MAP_ANON; else bsd_args.flags |= MAP_NOSYNC; - if (linux_args->flags & LINUX_MAP_GROWSDOWN) { + if (linux_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 = linux_args->prot; + if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) + bsd_args.prot |= PROT_READ | PROT_EXEC; + + if (linux_args->fd != -1) { + /* + * Linux follows Solaris mmap(2) description: + * The file descriptor fildes is opened with + * read permission, regardless of the + * protection options specified. + */ + + if ((error = fget(td, linux_args->fd, &fp)) != 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); + } + bsd_args.fd = linux_args->fd; + + if (linux_args->flags & LINUX_MAP_GROWSDOWN) { /* * The linux MAP_GROWSDOWN option does not limit auto * growth of the region. Linux mmap with this option @@ -814,11 +839,7 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) * fixed size of (STACK_SIZE - GUARD_SIZE). */ - /* This gives us TOS */ - bsd_args.addr = (caddr_t)PTRIN(linux_args->addr) + - linux_args->len; - - if ((caddr_t)PTRIN(bsd_args.addr) > + if ((caddr_t)PTRIN(linux_args->addr) + linux_args->len > p->p_vmspace->vm_maxsaddr) { /* * Some linux apps will attempt to mmap @@ -837,8 +858,7 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) * mmap's return value. */ PROC_LOCK(p); - p->p_vmspace->vm_maxsaddr = - (char *)LINUX32_USRSTACK - + p->p_vmspace->vm_maxsaddr = (char *)LINUX32_USRSTACK - lim_cur(p, RLIMIT_STACK); PROC_UNLOCK(p); } @@ -856,49 +876,12 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) * not using VM_STACK we map the full stack, since we * don't have a way to autogrow it. */ - bsd_args.addr -= bsd_args.len; + bsd_args.addr = (caddr_t)PTRIN(linux_args->addr) - + bsd_args.len; } else { bsd_args.addr = (caddr_t)PTRIN(linux_args->addr); bsd_args.len = linux_args->len; } - - /* - * We add PROT_EXEC to work around buggy applications (e.g. Java) - * that take advantage of the fact that execute permissions are not - * enforced by x86 CPUs. - */ - bsd_args.prot = linux_args->prot | PROT_EXEC; - if (linux_args->flags & LINUX_MAP_ANON) - bsd_args.fd = -1; - else { - /* - * Linux follows Solaris mmap(2) description: - * The file descriptor fildes is opened with - * read permission, regardless of the - * protection options specified. - * If PROT_WRITE is specified, the application - * must have opened the file descriptor - * fildes with write permission unless - * MAP_PRIVATE is specified in the flag - * argument as described below. - */ - - if ((error = fget(td, linux_args->fd, &fp)) != 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); - } - - bsd_args.fd = linux_args->fd; - fdrop(fp, td); - } bsd_args.pos = (off_t)linux_args->pgoff * PAGE_SIZE; bsd_args.pad = 0; @@ -1181,8 +1164,7 @@ linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) bsd_args.addr = uap->addr; bsd_args.len = uap->len; bsd_args.prot = uap->prot; - /* XXX PROT_READ implies PROT_EXEC; see linux_mmap_common(). */ - if ((bsd_args.prot & PROT_READ) != 0) - bsd_args.prot |= PROT_EXEC; + if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) + bsd_args.prot |= PROT_READ | PROT_EXEC; return (mprotect(td, &bsd_args)); } diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h index efc67ce..012a1f0 100644 --- a/sys/i386/linux/linux.h +++ b/sys/i386/linux/linux.h @@ -142,6 +142,15 @@ struct l_rlimit { #define LINUX_MAP_ANON 0x0020 #define LINUX_MAP_GROWSDOWN 0x0100 +struct l_mmap_argv { + l_uintptr_t addr; + l_size_t len; + l_int prot; + l_int flags; + l_int fd; + l_off_t pgoff; +} __packed; + /* * stat family of syscalls */ diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c index d07cbd5..e909d51 100644 --- a/sys/i386/linux/linux_machdep.c +++ b/sys/i386/linux/linux_machdep.c @@ -584,16 +584,6 @@ linux_clone(struct thread *td, struct linux_clone_args *args) return (0); } -/* XXX move */ -struct l_mmap_argv { - l_caddr_t addr; - l_int len; - l_int prot; - l_int flags; - l_int fd; - l_int pos; -}; - #define STACK_SIZE (2 * 1024 * 1024) #define GUARD_SIZE (4 * PAGE_SIZE) @@ -611,12 +601,12 @@ linux_mmap2(struct thread *td, struct linux_mmap2_args *args) args->flags, args->fd, args->pgoff); #endif - linux_args.addr = (l_caddr_t)args->addr; + linux_args.addr = args->addr; linux_args.len = args->len; linux_args.prot = args->prot; linux_args.flags = args->flags; linux_args.fd = args->fd; - linux_args.pos = args->pgoff * PAGE_SIZE; + linux_args.pgoff = args->pgoff * PAGE_SIZE; return (linux_mmap_common(td, &linux_args)); } @@ -635,7 +625,7 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args) if (ldebug(mmap)) printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"), (void *)linux_args.addr, linux_args.len, linux_args.prot, - linux_args.flags, linux_args.fd, linux_args.pos); + linux_args.flags, linux_args.fd, linux_args.pgoff); #endif return (linux_mmap_common(td, &linux_args)); @@ -679,9 +669,44 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) bsd_args.flags |= MAP_ANON; else bsd_args.flags |= MAP_NOSYNC; - if (linux_args->flags & LINUX_MAP_GROWSDOWN) { + if (linux_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 = linux_args->prot; + if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) + bsd_args.prot |= PROT_READ | PROT_EXEC; + + if (linux_args->fd != -1) { + /* + * Linux follows Solaris mmap(2) description: + * The file descriptor fildes is opened with + * read permission, regardless of the + * protection options specified. + */ + + if ((error = fget(td, linux_args->fd, &fp)) != 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); + } + bsd_args.fd = linux_args->fd; + + if (linux_args->flags & LINUX_MAP_GROWSDOWN) { /* * The linux MAP_GROWSDOWN option does not limit auto * growth of the region. Linux mmap with this option @@ -704,10 +729,8 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) * fixed size of (STACK_SIZE - GUARD_SIZE). */ - /* This gives us TOS */ - bsd_args.addr = linux_args->addr + linux_args->len; - - if (bsd_args.addr > p->p_vmspace->vm_maxsaddr) { + if ((caddr_t)PTRIN(linux_args->addr) + linux_args->len > + p->p_vmspace->vm_maxsaddr) { /* * Some linux apps will attempt to mmap * thread stacks near the top of their @@ -743,45 +766,13 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) * not using VM_STACK we map the full stack, since we * don't have a way to autogrow it. */ - bsd_args.addr -= bsd_args.len; + bsd_args.addr = (caddr_t)PTRIN(linux_args->addr) - + bsd_args.len; } else { - bsd_args.addr = linux_args->addr; + bsd_args.addr = (caddr_t)PTRIN(linux_args->addr); bsd_args.len = linux_args->len; } - - bsd_args.prot = linux_args->prot; - if (linux_args->flags & LINUX_MAP_ANON) - bsd_args.fd = -1; - else { - /* - * Linux follows Solaris mmap(2) description: - * The file descriptor fildes is opened with - * read permission, regardless of the - * protection options specified. - * If PROT_WRITE is specified, the application - * must have opened the file descriptor - * fildes with write permission unless - * MAP_PRIVATE is specified in the flag - * argument as described below. - */ - - if ((error = fget(td, linux_args->fd, &fp)) != 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); - } - - bsd_args.fd = linux_args->fd; - fdrop(fp, td); - } - bsd_args.pos = linux_args->pos; + bsd_args.pos = linux_args->pgoff; bsd_args.pad = 0; #ifdef DEBUG @@ -801,6 +792,19 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) } 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 (mprotect(td, &bsd_args)); +} + +int linux_pipe(struct thread *td, struct linux_pipe_args *args) { int error; diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master index fea81d3..fa9d444 100644 --- a/sys/i386/linux/syscalls.master +++ b/sys/i386/linux/syscalls.master @@ -224,7 +224,7 @@ 123 AUE_NULL STD { int linux_modify_ldt(l_int func, \ void *ptr, l_ulong bytecount); } 124 AUE_ADJTIME STD { int linux_adjtimex(void); } -125 AUE_MPROTECT NOPROTO { int mprotect(caddr_t addr, int len, \ +125 AUE_MPROTECT STD { int linux_mprotect(caddr_t addr, int len, \ int prot); } 126 AUE_SIGPROCMASK STD { int linux_sigprocmask(l_int how, \ l_osigset_t *mask, l_osigset_t *omask); } |