summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2007-02-15 00:54:40 +0000
committerjkim <jkim@FreeBSD.org>2007-02-15 00:54:40 +0000
commitdf99d574b5108aba65b940cbb910d8f6dae0b05f (patch)
tree7ac3a3ba87c37bfd781cdcc61e412702c7f93cc9
parent494959a002ebd44883ca0f80a6ab843faa66893b (diff)
downloadFreeBSD-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.h9
-rw-r--r--sys/amd64/linux32/linux32_machdep.c102
-rw-r--r--sys/i386/linux/linux.h9
-rw-r--r--sys/i386/linux/linux_machdep.c112
-rw-r--r--sys/i386/linux/syscalls.master2
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); }
OpenPOWER on IntegriCloud