diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index 942f5bd5657..a378c22272d 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -34,6 +34,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include @@ -728,9 +730,20 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) off_t pos; } */ bsd_args; int error; + struct file *fp; error = 0; bsd_args.flags = 0; + fp = NULL; + + /* + * Linux mmap(2): + * You must specify exactly one of MAP_SHARED and MAP_PRIVATE + */ + if (! ((linux_args->flags & LINUX_MAP_SHARED) ^ + (linux_args->flags & LINUX_MAP_PRIVATE))) + return (EINVAL); + if (linux_args->flags & LINUX_MAP_SHARED) bsd_args.flags |= MAP_SHARED; if (linux_args->flags & LINUX_MAP_PRIVATE) @@ -813,17 +826,44 @@ linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) bsd_args.addr = (caddr_t)PTRIN(linux_args->addr); bsd_args.len = linux_args->len; } + /* - * XXX i386 Linux always emulator forces PROT_READ on (why?) - * so we do the same. 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. + * 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 | PROT_READ; + bsd_args.prot = linux_args->prot | PROT_EXEC; if (linux_args->flags & LINUX_MAP_ANON) bsd_args.fd = -1; - else + 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;