| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,334 @@ | ||
| /*- | ||
| * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org> | ||
| * Copyright (c) 2013-2016, by Oliver Pinter <oliver.pinter@hardenedbsd.org> | ||
| * Copyright (c) 2014-2015, by Shawn Webb <shawn.webb@hardenedbsd.org> | ||
| * All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. The name of the author may not be used to endorse or promote products | ||
| * derived from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| * | ||
| * $FreeBSD$ | ||
| */ | ||
|
|
||
| #include <sys/cdefs.h> | ||
| __FBSDID("$FreeBSD$"); | ||
|
|
||
| #include "opt_compat.h" | ||
| #include "opt_pax.h" | ||
|
|
||
| #include <sys/param.h> | ||
| #include <sys/systm.h> | ||
| #include <sys/kernel.h> | ||
| #include <sys/exec.h> | ||
| #include <sys/imgact.h> | ||
| #include <sys/imgact_elf.h> | ||
| #include <sys/jail.h> | ||
| #include <sys/ktr.h> | ||
| #include <sys/libkern.h> | ||
| #include <sys/mman.h> | ||
| #include <sys/pax.h> | ||
| #include <sys/proc.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/sysctl.h> | ||
|
|
||
| #include <machine/_inttypes.h> | ||
|
|
||
| static void pax_set_flags(struct proc *p, struct thread *td, const pax_flag_t flags); | ||
| static void pax_set_flags_td(struct thread *td, const pax_flag_t flags); | ||
| static int pax_validate_flags(const pax_flag_t flags); | ||
| static int pax_check_conflicting_modes(const pax_flag_t mode); | ||
|
|
||
| CTASSERT((sizeof((struct proc *)NULL)->p_pax) == sizeof(pax_flag_t)); | ||
| CTASSERT((sizeof((struct thread *)NULL)->td_pax) == sizeof(pax_flag_t)); | ||
|
|
||
| SYSCTL_NODE(_hardening, OID_AUTO, pax, CTLFLAG_RD, 0, | ||
| "PaX (exploit mitigation) features."); | ||
|
|
||
| const char *pax_status_str[] = { | ||
| [PAX_FEATURE_DISABLED] = "disabled", | ||
| [PAX_FEATURE_OPTIN] = "opt-in", | ||
| [PAX_FEATURE_OPTOUT] = "opt-out", | ||
| [PAX_FEATURE_FORCE_ENABLED] = "force enabled", | ||
| }; | ||
|
|
||
| const char *pax_status_simple_str[] = { | ||
| [PAX_FEATURE_SIMPLE_DISABLED] = "disabled", | ||
| [PAX_FEATURE_SIMPLE_ENABLED] = "enabled" | ||
| }; | ||
|
|
||
|
|
||
| /* | ||
| * @brief Get the current process prison. | ||
| * | ||
| * @param p The current process pointer. | ||
| * | ||
| * @return prion0's address if failed or kernel process | ||
| * the actual process' prison's address else | ||
| * | ||
| */ | ||
| struct prison * | ||
| pax_get_prison(struct proc *p) | ||
| { | ||
|
|
||
| KASSERT(p != NULL, ("%s: p == NULL", __func__)); | ||
|
|
||
| PROC_LOCK_ASSERT(p, MA_OWNED); | ||
|
|
||
| if (p->p_ucred == NULL) | ||
| return (&prison0); | ||
|
|
||
| return (p->p_ucred->cr_prison); | ||
| } | ||
|
|
||
| struct prison * | ||
| pax_get_prison_td(struct thread *td) | ||
| { | ||
|
|
||
| if (td == NULL || td->td_ucred == NULL) | ||
| return (&prison0); | ||
|
|
||
| return (td->td_ucred->cr_prison); | ||
| } | ||
|
|
||
| /* | ||
| * @brief Get the current PaX status from process. | ||
| * | ||
| * @param p The controlled process pointer. | ||
| * @param flags Where to write the current state. | ||
| * | ||
| * @return none | ||
| */ | ||
| void | ||
| pax_get_flags(struct proc *p, pax_flag_t *flags) | ||
| { | ||
|
|
||
| KASSERT(p == curthread->td_proc, | ||
| ("%s: p != curthread->td_proc", __func__)); | ||
|
|
||
| #ifdef HBSD_DEBUG | ||
| struct thread *td; | ||
|
|
||
| FOREACH_THREAD_IN_PROC(p, td) { | ||
| KASSERT(td->td_pax == p->p_pax, ("%s: td->td_pax != p->p_pax", | ||
| __func__)); | ||
| } | ||
| #endif | ||
|
|
||
| *flags = p->p_pax; | ||
| } | ||
|
|
||
| void | ||
| pax_get_flags_td(struct thread *td, pax_flag_t *flags) | ||
| { | ||
|
|
||
| KASSERT(td == curthread, | ||
| ("%s: td != curthread", __func__)); | ||
|
|
||
| #ifdef HBSD_DEBUG | ||
| struct proc *p; | ||
| struct thread *td0; | ||
|
|
||
| p = td->td_proc; | ||
|
|
||
| FOREACH_THREAD_IN_PROC(p, td0) { | ||
| KASSERT(td0->td_proc == p, | ||
| ("%s: td0->td_proc != p", __func__)); | ||
| KASSERT(td0->td_pax == p->p_pax, ("%s: td0->td_pax != p->p_pax", | ||
| __func__)); | ||
| } | ||
| #endif | ||
|
|
||
| *flags = td->td_pax; | ||
| } | ||
|
|
||
| void | ||
| pax_set_flags(struct proc *p, struct thread *td, const pax_flag_t flags) | ||
| { | ||
| struct thread *td0; | ||
|
|
||
| KASSERT(td == curthread, | ||
| ("%s: td != curthread", __func__)); | ||
| KASSERT(td->td_proc == p, | ||
| ("%s: td->td_proc != p", __func__)); | ||
|
|
||
| PROC_LOCK(p); | ||
| p->p_pax = flags; | ||
| FOREACH_THREAD_IN_PROC(p, td0) { | ||
| pax_set_flags_td(td0, flags); | ||
| } | ||
| PROC_UNLOCK(p); | ||
| } | ||
|
|
||
| void | ||
| pax_set_flags_td(struct thread *td, const pax_flag_t flags) | ||
| { | ||
|
|
||
| td->td_pax = flags; | ||
| } | ||
|
|
||
| /* | ||
| * rename to pax_valid_flags, and change return values and type to bool | ||
| */ | ||
| static int | ||
| pax_validate_flags(const pax_flag_t flags) | ||
| { | ||
|
|
||
| if ((flags & ~PAX_NOTE_ALL) != 0) | ||
| return (1); | ||
|
|
||
| return (0); | ||
| } | ||
|
|
||
| /* | ||
| * same as pax_valid_flags | ||
| */ | ||
| static int | ||
| pax_check_conflicting_modes(const pax_flag_t mode) | ||
| { | ||
|
|
||
| if (((mode & PAX_NOTE_ALL_ENABLED) & ((mode & PAX_NOTE_ALL_DISABLED) >> 1)) != 0) | ||
| return (1); | ||
|
|
||
| return (0); | ||
| } | ||
|
|
||
| /* | ||
| * @bried Initialize the new process PaX state | ||
| * | ||
| * @param imgp Executable image's structure. | ||
| * @param mode Requested mode. | ||
| * | ||
| * @return ENOEXEC on fail | ||
| * 0 on success | ||
| */ | ||
| int | ||
| pax_elf(struct image_params *imgp, struct thread *td, pax_flag_t mode) | ||
| { | ||
| pax_flag_t flags; | ||
|
|
||
| if (pax_validate_flags(mode) != 0) { | ||
| pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT, | ||
| "unknown paxflags: %x", mode); | ||
| pax_ulog_internal("unknown paxflags: %x\n", mode); | ||
|
|
||
| return (ENOEXEC); | ||
| } | ||
|
|
||
| if (pax_check_conflicting_modes(mode) != 0) { | ||
| /* | ||
| * indicate flags inconsistencies in dmesg and in user terminal | ||
| */ | ||
| pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT, | ||
| "inconsistent paxflags: %x", mode); | ||
| pax_ulog_internal("inconsistent paxflags: %x\n", mode); | ||
|
|
||
| return (ENOEXEC); | ||
| } | ||
|
|
||
| flags = 0; | ||
|
|
||
| #ifdef PAX_ASLR | ||
| flags |= pax_aslr_setup_flags(imgp, td, mode); | ||
| #ifdef MAP_32BIT | ||
| flags |= pax_disallow_map32bit_setup_flags(imgp, td, mode); | ||
| #endif | ||
| #endif | ||
|
|
||
| CTR3(KTR_PAX, "%s : flags = %x mode = %x", | ||
| __func__, flags, mode); | ||
|
|
||
| /* | ||
| * Recheck the flags after the parsing: prevent broken setups. | ||
| */ | ||
| if (pax_validate_flags(flags) != 0) { | ||
| pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT, | ||
| "unknown paxflags after the setup: %x", flags); | ||
| pax_ulog_internal("unknown paxflags after the setup: %x\n", flags); | ||
|
|
||
| return (ENOEXEC); | ||
| } | ||
|
|
||
| /* | ||
| * Recheck the flags after the parsing: prevent conflicting setups. | ||
| * This check should be always false. | ||
| */ | ||
| if (pax_check_conflicting_modes(flags) != 0) { | ||
| /* | ||
| * indicate flags inconsistencies in dmesg and in user terminal | ||
| */ | ||
| pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT, | ||
| "inconsistent paxflags after the setup: %x", flags); | ||
| pax_ulog_internal("inconsistent paxflags after the setup: %x\n", flags); | ||
|
|
||
| return (ENOEXEC); | ||
| } | ||
|
|
||
| pax_set_flags(imgp->proc, td, flags); | ||
|
|
||
| /* | ||
| * if we enable/disable features with secadm, print out a warning | ||
| */ | ||
| if (mode != 0) { | ||
| pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT, | ||
| "the process has non-default settings"); | ||
| } | ||
|
|
||
| return (0); | ||
| } | ||
|
|
||
|
|
||
| /* | ||
| * @brief Print out PaX settings on boot time, and validate some of them. | ||
| * | ||
| * @return none | ||
| */ | ||
| static void | ||
| pax_sysinit(void) | ||
| { | ||
|
|
||
| } | ||
| SYSINIT(pax, SI_SUB_PAX, SI_ORDER_FIRST, pax_sysinit, NULL); | ||
|
|
||
| /* | ||
| * @brief Initialize prison's state. | ||
| * | ||
| * The prison0 state initialized with global state. | ||
| * The child prisons state initialized with it's parent's state. | ||
| * | ||
| * @param pr Initializable prison's pointer. | ||
| * | ||
| * @return none | ||
| */ | ||
| void | ||
| pax_init_prison(struct prison *pr) | ||
| { | ||
|
|
||
| CTR2(KTR_PAX, "%s: Setting prison %s PaX variables\n", | ||
| __func__, pr->pr_name); | ||
|
|
||
| pax_aslr_init_prison(pr); | ||
|
|
||
| #ifdef COMPAT_FREEBSD32 | ||
| pax_aslr_init_prison32(pr); | ||
| #endif | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| /*- | ||
| * Copyright (c) 2016, by Oliver Pinter <oliver.pinter@hardenedbsd.org> | ||
| * All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. The name of the author may not be used to endorse or promote products | ||
| * derived from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| * | ||
| * $FreeBSD$ | ||
| */ | ||
|
|
||
| #ifndef __HBSD_PAX_INTERNAL_H | ||
| #define __HBSD_PAX_INTERNAL_H | ||
|
|
||
| #define SYSCTL_HBSD_2STATE(g_status, pr_status, parent, name, access, desc) \ | ||
| static int sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS); \ | ||
| SYSCTL_PROC(parent, OID_AUTO, name, access, \ | ||
| NULL, 0, sysctl ## parent ## _ ## name, "I", \ | ||
| desc " status: " \ | ||
| "0 - disabled, " \ | ||
| "1 - enabled"); \ | ||
| \ | ||
| static int \ | ||
| sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS) \ | ||
| { \ | ||
| struct prison *pr; \ | ||
| int err, val; \ | ||
| \ | ||
| pr = pax_get_prison_td(req->td); \ | ||
| \ | ||
| val = pr->pr_status; \ | ||
| err = sysctl_handle_int(oidp, &val, sizeof(int), req); \ | ||
| if (err || (req->newptr == NULL)) \ | ||
| return (err); \ | ||
| \ | ||
| switch (val) { \ | ||
| case PAX_FEATURE_SIMPLE_DISABLED: \ | ||
| case PAX_FEATURE_SIMPLE_ENABLED: \ | ||
| if (pr == &prison0) \ | ||
| g_status = val; \ | ||
| pr->pr_status = val; \ | ||
| break; \ | ||
| default: \ | ||
| return (EINVAL); \ | ||
| } \ | ||
| \ | ||
| return (0); \ | ||
| } | ||
|
|
||
| #define SYSCTL_HBSD_4STATE(g_status, pr_status, parent, name, access) \ | ||
| static int sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS); \ | ||
| SYSCTL_PROC(parent, OID_AUTO, name, access, \ | ||
| NULL, 0, sysctl ## parent ## _ ## name, "I", \ | ||
| "Restrictions status: " \ | ||
| "0 - disabled, " \ | ||
| "1 - opt-in, " \ | ||
| "2 - opt-out, " \ | ||
| "3 - force enabled"); \ | ||
| \ | ||
| static int \ | ||
| sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS) \ | ||
| { \ | ||
| struct prison *pr; \ | ||
| int err, val; \ | ||
| \ | ||
| pr = pax_get_prison_td(req->td); \ | ||
| \ | ||
| val = pr->pr_status; \ | ||
| err = sysctl_handle_int(oidp, &val, sizeof(int), req); \ | ||
| if (err || (req->newptr == NULL)) \ | ||
| return (err); \ | ||
| \ | ||
| switch (val) { \ | ||
| case PAX_FEATURE_DISABLED: \ | ||
| case PAX_FEATURE_OPTIN: \ | ||
| case PAX_FEATURE_OPTOUT: \ | ||
| case PAX_FEATURE_FORCE_ENABLED: \ | ||
| if (pr == &prison0) \ | ||
| g_status = val; \ | ||
| pr->pr_status = val; \ | ||
| break; \ | ||
| default: \ | ||
| return (EINVAL); \ | ||
| } \ | ||
| \ | ||
| return (0); \ | ||
| } | ||
|
|
||
| #endif /* __HBSD_PAX_INTERNAL_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,380 @@ | ||
| /*- | ||
| * Copyright (c) 2014, by Oliver Pinter <oliver.pinter@hardenedbsd.org> | ||
| * All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| * SUCH DAMAGE. | ||
| * | ||
| * $FreeBSD$ | ||
| */ | ||
|
|
||
| #include "opt_pax.h" | ||
| #include "opt_ddb.h" | ||
|
|
||
| #include <sys/cdefs.h> | ||
|
|
||
| #include <sys/param.h> | ||
| #include <sys/systm.h> | ||
| #include <sys/types.h> | ||
| #include <sys/kernel.h> | ||
| #include <sys/ktr.h> | ||
| #include <sys/imgact.h> | ||
| #include <sys/pax.h> | ||
| #include <sys/proc.h> | ||
| #include <sys/sbuf.h> | ||
| #include <sys/jail.h> | ||
| #include <machine/stdarg.h> | ||
|
|
||
| #ifdef DDB | ||
| #include <ddb/ddb.h> | ||
| #endif | ||
|
|
||
| #include "hbsd_pax_internal.h" | ||
|
|
||
| static void pax_log_log(struct proc *p, struct thread *td, pax_log_settings_t flags, | ||
| const char *prefix, const char *fmt, va_list ap); | ||
| static void pax_log_ulog(const char *prefix, const char *fmt, va_list ap); | ||
|
|
||
| #define PAX_LOG_FEATURES_STRING \ | ||
| "\020" \ | ||
| "\001PAGEEXEC" \ | ||
| "\002NOPAGEEXEC" \ | ||
| "\003MPROTECT" \ | ||
| "\004NOMPROTECT" \ | ||
| "\005SEGVGUARD" \ | ||
| "\006NOSEGVGUARD" \ | ||
| "\007ASLR" \ | ||
| "\010NOASLR" \ | ||
| "\011SHLIBRANDOM" \ | ||
| "\012NOSHLIBRANDOM" \ | ||
| "\013DISALLOWMAP32BIT" \ | ||
| "\014NODISALLOWMAP32BIT" \ | ||
| "\015<f12>" \ | ||
| "\016<f13>" \ | ||
| "\017<f14>" \ | ||
| "\020<f15>" \ | ||
| "\021<f16>" \ | ||
| "\022<f17>" \ | ||
| "\023<f18>" \ | ||
| "\024<f19>" \ | ||
| "\025<f20>" \ | ||
| "\026<f21>" \ | ||
| "\027<f22>" \ | ||
| "\030<f23>" \ | ||
| "\031<f24>" \ | ||
| "\032<f25>" \ | ||
| "\033<f26>" \ | ||
| "\034<f27>" \ | ||
| "\035<f28>" \ | ||
| "\036<f29>" \ | ||
| "\037<f30>" \ | ||
| "\040<f31>" | ||
|
|
||
| #define __HARDENING_LOG_TEMPLATE(MAIN, SUBJECT, prefix, name) \ | ||
| void \ | ||
| prefix##_log_##name(struct proc *p, pax_log_settings_t flags, \ | ||
| const char* fmt, ...) \ | ||
| { \ | ||
| const char *prefix = "["#MAIN" "#SUBJECT"]"; \ | ||
| va_list args; \ | ||
| \ | ||
| if (hardening_log_log == 0) \ | ||
| return; \ | ||
| \ | ||
| va_start(args, fmt); \ | ||
| pax_log_log(p, NULL, flags, prefix, fmt, args); \ | ||
| va_end(args); \ | ||
| } \ | ||
| \ | ||
| void \ | ||
| prefix##_ulog_##name(const char* fmt, ...) \ | ||
| { \ | ||
| const char *prefix = "["#MAIN" "#SUBJECT"]"; \ | ||
| va_list args; \ | ||
| \ | ||
| if (hardening_log_ulog == 0) \ | ||
| return; \ | ||
| \ | ||
| va_start(args, fmt); \ | ||
| pax_log_ulog(prefix, fmt, args); \ | ||
| va_end(args); \ | ||
| } | ||
|
|
||
| static int hardening_log_log = PAX_FEATURE_SIMPLE_ENABLED; | ||
| static int hardening_log_ulog = PAX_FEATURE_SIMPLE_DISABLED; | ||
|
|
||
| TUNABLE_INT("hardening.log.log", &hardening_log_log); | ||
| TUNABLE_INT("hardening.log.ulog", &hardening_log_ulog); | ||
|
|
||
| #ifdef PAX_SYSCTLS | ||
| SYSCTL_NODE(_hardening, OID_AUTO, log, CTLFLAG_RD, 0, | ||
| "Hardening related logging facility."); | ||
|
|
||
| SYSCTL_HBSD_2STATE(hardening_log_log, pr_hbsd.log.log, _hardening_log, log, | ||
| CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE, | ||
| "log to syslog "); | ||
|
|
||
| SYSCTL_HBSD_2STATE(hardening_log_ulog, pr_hbsd.log.ulog, _hardening_log, ulog, | ||
| CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE, | ||
| "log to syslog "); | ||
| #endif | ||
|
|
||
|
|
||
| static void | ||
| hardening_log_sysinit(void) | ||
| { | ||
| switch (hardening_log_log) { | ||
| case PAX_FEATURE_SIMPLE_DISABLED: | ||
| case PAX_FEATURE_SIMPLE_ENABLED: | ||
| break; | ||
| default: | ||
| printf("[HBSD LOG] WARNING, invalid settings in loader.conf!" | ||
| " (hardening.log.log = %d)\n", hardening_log_log); | ||
| hardening_log_log = PAX_FEATURE_SIMPLE_ENABLED; | ||
| } | ||
| printf("[HBSD LOG] logging to system: %s\n", | ||
| pax_status_simple_str[hardening_log_log]); | ||
|
|
||
| switch (hardening_log_ulog) { | ||
| case PAX_FEATURE_SIMPLE_DISABLED: | ||
| case PAX_FEATURE_SIMPLE_ENABLED: | ||
| break; | ||
| default: | ||
| printf("[HBSD LOG] WARNING, invalid settings in loader.conf!" | ||
| " (hardening.log.ulog = %d)\n", hardening_log_ulog); | ||
| hardening_log_ulog = PAX_FEATURE_SIMPLE_ENABLED; | ||
| } | ||
| printf("[HBSD LOG] logging to user: %s\n", | ||
| pax_status_simple_str[hardening_log_ulog]); | ||
| } | ||
| SYSINIT(hardening_log, SI_SUB_PAX, SI_ORDER_SECOND, hardening_log_sysinit, NULL); | ||
|
|
||
| void | ||
| pax_log_init_prison(struct prison *pr) | ||
| { | ||
| struct prison *pr_p; | ||
|
|
||
| CTR2(KTR_PAX, "%s: Setting prison %s PaX variables\n", | ||
| __func__, pr->pr_name); | ||
|
|
||
| if (pr == &prison0) { | ||
| /* prison0 has no parent, use globals */ | ||
| pr->pr_hbsd.log.log = hardening_log_log; | ||
| pr->pr_hbsd.log.ulog = hardening_log_ulog; | ||
| } else { | ||
| KASSERT(pr->pr_parent != NULL, | ||
| ("%s: pr->pr_parent == NULL", __func__)); | ||
| pr_p = pr->pr_parent; | ||
|
|
||
| pr->pr_hbsd.log.log = pr_p->pr_hbsd.log.log; | ||
| pr->pr_hbsd.log.ulog = pr_p->pr_hbsd.log.ulog; | ||
| } | ||
| } | ||
|
|
||
| static void | ||
| _pax_log_prefix(struct sbuf *sb, pax_log_settings_t flags, const char *prefix) | ||
| { | ||
|
|
||
| sbuf_printf(sb, "%s ", prefix); | ||
| } | ||
|
|
||
| static void | ||
| _pax_log_indent(struct sbuf *sb, pax_log_settings_t flags) | ||
| { | ||
|
|
||
| if ((flags & PAX_LOG_NO_INDENT) != PAX_LOG_NO_INDENT) | ||
| sbuf_printf(sb, "\n -> "); | ||
| } | ||
|
|
||
| static void | ||
| _pax_log_proc_details(struct sbuf *sb, pax_log_settings_t flags, struct proc *p) | ||
| { | ||
|
|
||
| if (p != NULL) { | ||
| if ((flags & PAX_LOG_P_COMM) == PAX_LOG_P_COMM) | ||
| sbuf_printf(sb, "p_comm: %s ", p->p_comm); | ||
|
|
||
| sbuf_printf(sb, "pid: %d ", p->p_pid); | ||
| sbuf_printf(sb, "ppid: %d ", p->p_pptr->p_pid); | ||
|
|
||
| if ((flags & PAX_LOG_NO_P_PAX) != PAX_LOG_NO_P_PAX) | ||
| sbuf_printf(sb, "p_pax: 0x%b ", p->p_pax, PAX_LOG_FEATURES_STRING); | ||
| } | ||
| } | ||
|
|
||
| static void | ||
| _pax_log_thread_details(struct sbuf *sb, pax_log_settings_t flags, struct thread *td) | ||
| { | ||
|
|
||
| if (td != NULL) { | ||
| sbuf_printf(sb, "tid: %d ", td->td_tid); | ||
| } | ||
| } | ||
|
|
||
| static void | ||
| _pax_log_details_end(struct sbuf *sb) | ||
| { | ||
|
|
||
| sbuf_printf(sb, "\n"); | ||
| } | ||
|
|
||
| static void | ||
| _pax_log_imgp_details(struct sbuf *sb, pax_log_settings_t flags, struct image_params *imgp) | ||
| { | ||
|
|
||
| if (imgp != NULL && imgp->args != NULL) | ||
| if (imgp->args->fname != NULL) | ||
| sbuf_printf(sb, "fname: %s ", | ||
| imgp->args->fname); | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| pax_log_log(struct proc *p, struct thread *td, pax_log_settings_t flags, | ||
| const char *prefix, const char *fmt, va_list ap) | ||
| { | ||
| struct sbuf *sb; | ||
|
|
||
| sb = sbuf_new_auto(); | ||
| if (sb == NULL) | ||
| panic("%s: Could not allocate memory", __func__); | ||
|
|
||
| _pax_log_prefix(sb, flags, prefix); | ||
|
|
||
| sbuf_vprintf(sb, fmt, ap); | ||
| if ((flags & PAX_LOG_SKIP_DETAILS) != PAX_LOG_SKIP_DETAILS) { | ||
| _pax_log_indent(sb, flags); | ||
| _pax_log_proc_details(sb, flags, p); | ||
| _pax_log_thread_details(sb, flags, td); | ||
| _pax_log_details_end(sb); | ||
| } | ||
|
|
||
| if (sbuf_finish(sb) != 0) | ||
| panic("%s: Could not generate message", __func__); | ||
|
|
||
| printf("%s", sbuf_data(sb)); | ||
| sbuf_delete(sb); | ||
| } | ||
|
|
||
| static void | ||
| pax_log_ulog(const char *prefix, const char *fmt, va_list ap) | ||
| { | ||
| struct sbuf *sb; | ||
|
|
||
| sb = sbuf_new_auto(); | ||
| if (sb == NULL) | ||
| panic("%s: Could not allocate memory", __func__); | ||
|
|
||
| if (prefix != NULL) | ||
| sbuf_printf(sb, "%s ", prefix); | ||
| sbuf_vprintf(sb, fmt, ap); | ||
| if (sbuf_finish(sb) != 0) | ||
| panic("%s: Could not generate message", __func__); | ||
|
|
||
| hbsd_uprintf("%s", sbuf_data(sb)); \ | ||
| sbuf_delete(sb); | ||
| } | ||
|
|
||
| void | ||
| pax_printf_flags(struct proc *p, pax_log_settings_t flags) | ||
| { | ||
|
|
||
| if (p != NULL) { | ||
| printf("pax flags: 0x%b%c", p->p_pax, PAX_LOG_FEATURES_STRING, | ||
| ((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ? | ||
| ' ' : '\n'); | ||
| } | ||
| } | ||
|
|
||
| void | ||
| pax_printf_flags_td(struct thread *td, pax_log_settings_t flags) | ||
| { | ||
|
|
||
| if (td != NULL) { | ||
| printf("pax flags: 0x%b%c", td->td_pax, PAX_LOG_FEATURES_STRING, | ||
| ((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ? | ||
| ' ' : '\n'); | ||
| } | ||
| } | ||
|
|
||
| #ifdef DDB | ||
| void | ||
| pax_db_printf_flags(struct proc *p, pax_log_settings_t flags) | ||
| { | ||
|
|
||
| if (p != NULL) { | ||
| db_printf(" pax flags: 0x%b%c", p->p_pax, PAX_LOG_FEATURES_STRING, | ||
| ((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ? | ||
| ' ' : '\n'); | ||
| } | ||
| } | ||
|
|
||
| void | ||
| pax_db_printf_flags_td(struct thread *td, pax_log_settings_t flags) | ||
| { | ||
|
|
||
| if (td != NULL) { | ||
| db_printf(" pax flags: 0x%b%c", td->td_pax, PAX_LOG_FEATURES_STRING, | ||
| ((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ? | ||
| ' ' : '\n'); | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| __HARDENING_LOG_TEMPLATE(HBSD, INTERNAL, pax, internal); | ||
| __HARDENING_LOG_TEMPLATE(HBSD, ASLR, pax, aslr); | ||
|
|
||
| void | ||
| pax_log_internal_imgp(struct image_params *imgp, pax_log_settings_t flags, const char* fmt, ...) | ||
| { | ||
| const char *prefix = "[HBSD INTERNAL]"; | ||
| struct sbuf *sb; | ||
| va_list args; | ||
|
|
||
| KASSERT(imgp != NULL, ("%s: imgp == NULL", __func__)); | ||
|
|
||
| if (hardening_log_log == 0) | ||
| return; | ||
|
|
||
| sb = sbuf_new_auto(); | ||
| if (sb == NULL) | ||
| panic("%s: Could not allocate memory", __func__); | ||
|
|
||
| _pax_log_prefix(sb, flags, prefix); | ||
|
|
||
| va_start(args, fmt); | ||
| sbuf_vprintf(sb, fmt, args); | ||
| va_end(args); | ||
|
|
||
| if ((flags & PAX_LOG_SKIP_DETAILS) != PAX_LOG_SKIP_DETAILS) { | ||
| _pax_log_indent(sb, flags); | ||
| _pax_log_imgp_details(sb, flags, imgp); | ||
| _pax_log_indent(sb, flags); | ||
| _pax_log_proc_details(sb, flags, imgp->proc); | ||
| _pax_log_details_end(sb); | ||
| } | ||
|
|
||
| if (sbuf_finish(sb) != 0) | ||
| panic("%s: Could not generate message", __func__); | ||
|
|
||
| printf("%s", sbuf_data(sb)); | ||
| sbuf_delete(sb); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| /*- | ||
| * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org> | ||
| * Copyright (c) 2013-2016, by Oliver Pinter <oliver.pinter@hardenedbsd.org> | ||
| * Copyright (c) 2014-2015 by Shawn Webb <shawn.webb@hardenedbsd.org> | ||
| * All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. The name of the author may not be used to endorse or promote products | ||
| * derived from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| * | ||
| * $FreeBSD$ | ||
| */ | ||
|
|
||
| #ifndef _SYS_PAX_H | ||
| #define _SYS_PAX_H | ||
|
|
||
| #if defined(_KERNEL) || defined(_WANT_PRISON) | ||
| struct hbsd_features { | ||
| struct hbsd_aslr { | ||
| int status; /* (p) PaX ASLR enabled */ | ||
| int compat_status; /* (p) PaX ASLR enabled (compat32) */ | ||
| int disallow_map32bit_status; /* (p) MAP_32BIT protection (__LP64__ only) */ | ||
| } aslr; | ||
| struct hbsd_log { | ||
| int log; /* (p) Per-jail logging status */ | ||
| int ulog; /* (p) Per-jail user visible logging status */ | ||
| } log; | ||
| }; | ||
| #endif | ||
|
|
||
| #ifdef _KERNEL | ||
|
|
||
| #include <vm/vm.h> | ||
|
|
||
| struct image_params; | ||
| struct prison; | ||
| struct thread; | ||
| struct proc; | ||
| struct vnode; | ||
| struct vm_offset_t; | ||
|
|
||
| typedef uint32_t pax_flag_t; | ||
|
|
||
| /* | ||
| * used in sysctl handler | ||
| */ | ||
| #define PAX_FEATURE_DISABLED 0 | ||
| #define PAX_FEATURE_OPTIN 1 | ||
| #define PAX_FEATURE_OPTOUT 2 | ||
| #define PAX_FEATURE_FORCE_ENABLED 3 | ||
|
|
||
| extern const char *pax_status_str[]; | ||
|
|
||
| #define PAX_FEATURE_SIMPLE_DISABLED 0 | ||
| #define PAX_FEATURE_SIMPLE_ENABLED 1 | ||
|
|
||
| extern const char *pax_status_simple_str[]; | ||
|
|
||
| /* | ||
| * generic pax functions | ||
| */ | ||
| int pax_elf(struct image_params *imgp, struct thread *td, pax_flag_t mode); | ||
| void pax_get_flags(struct proc *p, pax_flag_t *flags); | ||
| void pax_get_flags_td(struct thread *td, pax_flag_t *flags); | ||
| struct prison *pax_get_prison(struct proc *p); | ||
| struct prison *pax_get_prison_td(struct thread *td); | ||
| void pax_init_prison(struct prison *pr); | ||
|
|
||
| /* | ||
| * ASLR related functions | ||
| */ | ||
| bool pax_aslr_active(struct proc *p); | ||
| #ifdef PAX_ASLR | ||
| void pax_aslr_init_prison(struct prison *pr); | ||
| void pax_aslr_init_prison32(struct prison *pr); | ||
| void pax_aslr_init_vmspace(struct proc *p); | ||
| void pax_aslr_init_vmspace32(struct proc *p); | ||
| #else | ||
| #define pax_aslr_init_prison(pr) do {} while (0) | ||
| #define pax_aslr_init_prison32(pr) do {} while (0) | ||
| #define pax_aslr_init_vmspace NULL | ||
| #define pax_aslr_init_vmspace32 NULL | ||
| #endif | ||
| void pax_aslr_init(struct image_params *imgp); | ||
| void pax_aslr_execbase(struct proc *p, u_long *et_dyn_addrp); | ||
| void pax_aslr_mmap(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int mmap_flags); | ||
| void pax_aslr_mmap_map_32bit(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int mmap_flags); | ||
| void pax_aslr_rtld(struct proc *p, u_long *addr); | ||
| pax_flag_t pax_aslr_setup_flags(struct image_params *imgp, struct thread *td, pax_flag_t mode); | ||
| void pax_aslr_stack(struct proc *p, vm_offset_t *addr); | ||
| void pax_aslr_stack_with_gap(struct proc *p, vm_offset_t *addr); | ||
| void pax_aslr_vdso(struct proc *p, vm_offset_t *addr); | ||
| pax_flag_t pax_disallow_map32bit_setup_flags(struct image_params *imgp, struct thread *td, pax_flag_t mode); | ||
| bool pax_disallow_map32bit_active(struct thread *td, int mmap_flags); | ||
|
|
||
| /* | ||
| * Log related functions | ||
| */ | ||
|
|
||
| typedef uint64_t pax_log_settings_t; | ||
|
|
||
| #define PAX_LOG_DEFAULT 0x00000000 | ||
| #define PAX_LOG_SKIP_DETAILS 0x00000001 | ||
| #define PAX_LOG_NO_NEWLINE 0x00000002 | ||
| #define PAX_LOG_P_COMM 0x00000004 | ||
| #define PAX_LOG_NO_P_PAX 0x00000008 | ||
| #define PAX_LOG_NO_INDENT 0x00000010 | ||
|
|
||
| void pax_log_init_prison(struct prison *pr); | ||
| void pax_printf_flags(struct proc *p, pax_log_settings_t flags); | ||
| void pax_printf_flags_td(struct thread *td, pax_log_settings_t flags); | ||
| void pax_db_printf_flags(struct proc *p, pax_log_settings_t flags); | ||
| void pax_db_printf_flags_td(struct thread *td, pax_log_settings_t flags); | ||
| int hbsd_uprintf(const char *fmt, ...) __printflike(1, 2); | ||
| void pax_log_internal(struct proc *, pax_log_settings_t flags, const char *fmt, ...) __printflike(3, 4); | ||
| void pax_log_internal_imgp(struct image_params *imgp, pax_log_settings_t flags, const char* fmt, ...) __printflike(3, 4); | ||
| void pax_ulog_internal(const char *fmt, ...) __printflike(1, 2); | ||
| void pax_log_aslr(struct proc *, pax_log_settings_t flags, const char *fmt, ...) __printflike(3, 4); | ||
| void pax_ulog_aslr(const char *fmt, ...) __printflike(1, 2); | ||
|
|
||
| /* | ||
| * Hardening related functions | ||
| */ | ||
| #ifdef PAX_HARDENING | ||
| void pax_hardening_init_prison(struct prison *pr); | ||
| #else | ||
| #define pax_hardening_init_prison(pr) do {} while (0) | ||
| #endif | ||
| int pax_procfs_harden(struct thread *td); | ||
|
|
||
| #define PAX_NOTE_PAGEEXEC 0x00000001 | ||
| #define PAX_NOTE_NOPAGEEXEC 0x00000002 | ||
| #define PAX_NOTE_MPROTECT 0x00000004 | ||
| #define PAX_NOTE_NOMPROTECT 0x00000008 | ||
| #define PAX_NOTE_SEGVGUARD 0x00000010 | ||
| #define PAX_NOTE_NOSEGVGUARD 0x00000020 | ||
| #define PAX_NOTE_ASLR 0x00000040 | ||
| #define PAX_NOTE_NOASLR 0x00000080 | ||
| #define PAX_NOTE_SHLIBRANDOM 0x00000100 | ||
| #define PAX_NOTE_NOSHLIBRANDOM 0x00000200 | ||
| #define PAX_NOTE_DISALLOWMAP32BIT 0x00000400 | ||
| #define PAX_NOTE_NODISALLOWMAP32BIT 0x00000800 | ||
|
|
||
| #define PAX_NOTE_RESERVED0 0x40000000 | ||
| #define PAX_NOTE_FINALIZED 0x80000000 | ||
|
|
||
| #define PAX_NOTE_ALL_ENABLED \ | ||
| (PAX_NOTE_PAGEEXEC | PAX_NOTE_MPROTECT | PAX_NOTE_SEGVGUARD | \ | ||
| PAX_NOTE_ASLR | PAX_NOTE_SHLIBRANDOM | PAX_NOTE_DISALLOWMAP32BIT) | ||
| #define PAX_NOTE_ALL_DISABLED \ | ||
| (PAX_NOTE_NOPAGEEXEC | PAX_NOTE_NOMPROTECT | \ | ||
| PAX_NOTE_NOSEGVGUARD | PAX_NOTE_NOASLR | PAX_NOTE_NOSHLIBRANDOM | \ | ||
| PAX_NOTE_NODISALLOWMAP32BIT) | ||
| #define PAX_NOTE_ALL (PAX_NOTE_ALL_ENABLED | PAX_NOTE_ALL_DISABLED | PAX_NOTE_FINALIZED) | ||
|
|
||
| #endif /* _KERNEL */ | ||
|
|
||
| #define PAX_HARDENING_SHLIBRANDOM 0x00000100 | ||
| #define PAX_HARDENING_NOSHLIBRANDOM 0x00000200 | ||
|
|
||
| #endif /* !_SYS_PAX_H */ |