diff --git a/FreeBSD/sys/kern/imgact_elf.c b/FreeBSD/sys/kern/imgact_elf.c --- a/FreeBSD/sys/kern/imgact_elf.c +++ b/FreeBSD/sys/kern/imgact_elf.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -219,7 +220,7 @@ CTLFLAG_RWTUN, &__elfN(sigfastblock), 0, "enable sigfastblock for new processes"); -static bool __elfN(allow_wx) = true; +static bool __elfN(allow_wx) = false; SYSCTL_BOOL(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, allow_wx, CTLFLAG_RWTUN, &__elfN(allow_wx), 0, "Allow pages to be mapped simultaneously writable and executable"); @@ -744,6 +745,15 @@ /* Loadable segment */ prot = __elfN(trans_prot)(phdr[i].p_flags); + if ((imgp->map_flags & MAP_WXORX) == MAP_WXORX && + (prot & (VM_PROT_WRITE | VM_PROT_EXECUTE)) == + (VM_PROT_WRITE | VM_PROT_EXECUTE)) { + log(LOG_WARNING, + "Refusing to run ELF binary with WX section (%s)\n", + imgp->execpath != NULL ? imgp->execpath : + ""); + return (ENOEXEC); + } error = __elfN(load_section)(imgp, phdr[i].p_offset, (caddr_t)(uintptr_t)phdr[i].p_vaddr + rbase, phdr[i].p_memsz, phdr[i].p_filesz, prot); diff --git a/FreeBSD/sys/vm/vm_map.c b/FreeBSD/sys/vm/vm_map.c --- a/FreeBSD/sys/vm/vm_map.c +++ b/FreeBSD/sys/vm/vm_map.c @@ -82,7 +82,9 @@ #include #include #include +#include #include +#include #include #include @@ -1600,6 +1602,54 @@ return (FALSE); } +static int enforce_wxorx = 0; +SYSCTL_INT(_vm, OID_AUTO, enforce_wxorx, CTLFLAG_RWTUN, + &enforce_wxorx, 0, + "Enforce W^X: 0 = no, 1 = log only, 2 = deny mapping, 3 = kill program"); + +/* + * handle_wxorx_exception: + * + * Handle W^X errors according to the sysctl setting. + * + * If the calling function should block the mapping, return true. + * Otherwise, return false. + */ +static bool +handle_wxorx_exception(void) +{ + const char *action = NULL; + bool rv = false; + + switch (enforce_wxorx) { + default: + case 3: + if ((curproc->p_flag & P_KPROC) == 0 && + (curthread->td_pflags & TDP_KTHREAD) == 0) { + kern_psignal(curproc, SIGSEGV); + action = "process killed"; + } + /* Fall Through */ + + case 2: + rv = true; + if (action == NULL) + action = "blocked"; + /* Fall Through */ + + case 1: + log(LOG_WARNING, "Detected WX mapping from pid %u (%s): %s\n", + curproc->p_pid, curproc->p_comm, + action != NULL ? action : "allowed"); + break; + + case 0: + break; + + } + return (rv); +} + /* * vm_map_insert: * @@ -1641,7 +1691,8 @@ return (KERN_INVALID_ADDRESS); if ((map->flags & MAP_WXORX) != 0 && (prot & (VM_PROT_WRITE | - VM_PROT_EXECUTE)) == (VM_PROT_WRITE | VM_PROT_EXECUTE)) + VM_PROT_EXECUTE)) == (VM_PROT_WRITE | VM_PROT_EXECUTE) && + handle_wxorx_exception()) return (KERN_PROTECTION_FAILURE); /* @@ -2728,7 +2779,7 @@ if ((map->flags & MAP_WXORX) != 0 && (flags & VM_MAP_PROTECT_SET_PROT) != 0 && (new_prot & (VM_PROT_WRITE | VM_PROT_EXECUTE)) == (VM_PROT_WRITE | - VM_PROT_EXECUTE)) { + VM_PROT_EXECUTE) && handle_wxorx_exception()) { vm_map_unlock(map); return (KERN_PROTECTION_FAILURE); }