> As it turns out, this bug in compat_linux was encountered in NetBSD in > 2005 and then fixed. The NetBSD patches are
I have successfully ported the relevant material from the NetBSD patches http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/compat/linux/common/linux_misc.c.diff?r1=1.140&r2=1.141 http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/compat/linux/common/linux_mmap.h.diff?r1=1.16&r2=1.17 http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/compat/linux/arch/i386/syscalls.master.diff?r1=1.61&r2=1.62 to OpenBSD. The OpenBSD patch is given at the end of this message. Be sure to run the make file at /usr/src/sys/compat/linux/ after applying the patch. The make file will update some important files. This patch allows OpenBSD to use the PROT_GROWSUP and PROT_GROWSDOWN flags to mprotect under Linux emulation. I have tested this new functionality with the Linux version of the Mathematica 6.0 Kernel, which now runs successfully. Presumably, OpenBSD will also be able to run other Linux applications that use these flags, such as Adobe Acrobat Reader (for which the NetBSD patches were originally intended). What steps need to be taken to ensure that this fix is merged into the official OpenBSD source code? *** /usr/src/sys/compat/linux/linux_misc.c.orig Wed Feb 14 18:07:51 2007 --- /usr/src/sys/compat/linux/linux_misc.c Mon Jun 25 00:13:42 2007 *************** *** 718,723 **** --- 718,787 ---- } + int + linux_sys_mprotect(p, v, retval) + struct proc *p; + void *v; + register_t *retval; + { + struct linux_sys_mprotect_args /* { + syscallarg(const void *) start; + syscallarg(unsigned long) len; + syscallarg(int) prot; + } */ *uap = v; + struct vm_map_entry *entry; + struct vm_map *map; + vaddr_t end, start, len, stacklim; + int prot, grows; + + start = (vaddr_t)SCARG(uap, start); + len = round_page(SCARG(uap, len)); + prot = SCARG(uap, prot); + grows = prot & (LINUX_PROT_GROWSDOWN | LINUX_PROT_GROWSUP); + prot &= ~grows; + end = start + len; + + if (start & PAGE_MASK) + return EINVAL; + if (end < start) + return EINVAL; + if (end == start) + return 0; + + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return EINVAL; + if (grows == (LINUX_PROT_GROWSDOWN | LINUX_PROT_GROWSUP)) + return EINVAL; + + map = &p->p_vmspace->vm_map; + vm_map_lock(map); + if (!uvm_map_lookup_entry(map, start, &entry) || entry->start > start) { + vm_map_unlock(map); + return ENOMEM; + } + + /* + * Approximate the behaviour of PROT_GROWS{DOWN,UP}. + */ + + stacklim = (vaddr_t)p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_cur; + if (grows & LINUX_PROT_GROWSDOWN) { + if (USRSTACK - stacklim <= start && start < USRSTACK) { + start = USRSTACK - stacklim; + } else { + start = entry->start; + } + } else if (grows & LINUX_PROT_GROWSUP) { + if (USRSTACK <= end && end < USRSTACK + stacklim) { + end = USRSTACK + stacklim; + } else { + end = entry->end; + } + } + vm_map_unlock(map); + return uvm_map_protect(map, start, end, prot, FALSE); + } + /* * This code is partly stolen from src/lib/libc/gen/times.c * XXX - CLK_TCK isn't declared in /sys, just in <time.h>, done here *** /usr/src/sys/compat/linux/linux_mmap.h.orig Wed Apr 17 05:23:56 1996 --- /usr/src/sys/compat/linux/linux_mmap.h Mon Jun 25 00:13:42 2007 *************** *** 38,43 **** --- 38,45 ---- #define LINUX_PROT_READ 0x01 #define LINUX_PROT_WRITE 0x02 #define LINUX_PROT_EXEC 0x04 + #define LINUX_PROT_GROWSDOWN 0x01000000 + #define LINUX_PROT_GROWSUP 0x02000000 #define LINUX_MAP_SHARED 0x0001 #define LINUX_MAP_PRIVATE 0x0002 *** /usr/src/sys/compat/linux/syscalls.master.orig Wed Oct 27 13:23:38 2004 --- /usr/src/sys/compat/linux/syscalls.master Mon Jun 25 00:13:42 2007 *************** *** 223,229 **** 123 STD { int linux_sys_modify_ldt(void); } #endif 124 STD { int linux_sys_adjtimex(void); } ! 125 NOARGS { int sys_mprotect(caddr_t addr, int len, int prot); } 126 STD { int linux_sys_sigprocmask(int how, \ linux_old_sigset_t *set, linux_old_sigset_t *oset); } 127 STD { int linux_sys_create_module(void); } --- 223,230 ---- 123 STD { int linux_sys_modify_ldt(void); } #endif 124 STD { int linux_sys_adjtimex(void); } ! 125 STD { int linux_sys_mprotect(const void *start, \ ! unsigned long len, int prot); } 126 STD { int linux_sys_sigprocmask(int how, \ linux_old_sigset_t *set, linux_old_sigset_t *oset); } 127 STD { int linux_sys_create_module(void); }

