858 changes: 858 additions & 0 deletions sys/hardenedbsd/hbsd_pax_aslr.c

Large diffs are not rendered by default.

334 changes: 334 additions & 0 deletions sys/hardenedbsd/hbsd_pax_common.c
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
}

107 changes: 107 additions & 0 deletions sys/hardenedbsd/hbsd_pax_internal.h
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 */
380 changes: 380 additions & 0 deletions sys/hardenedbsd/hbsd_pax_log.c
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);
}
3 changes: 3 additions & 0 deletions sys/i386/conf/GENERIC
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,6 @@ device xenpci # Xen HVM Hypervisor services driver

# VMware support
device vmx # VMware VMXNET3 Ethernet

options PAX
options PAX_ASLR
3 changes: 3 additions & 0 deletions sys/i386/i386/elf_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
__FBSDID("$FreeBSD$");

#include "opt_cpu.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
Expand Down Expand Up @@ -88,6 +90,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_shared_page_base = SHAREDPAGE,
.sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL,
.sv_pax_aslr_init = pax_aslr_init_vmspace,
};
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);

Expand Down
10 changes: 5 additions & 5 deletions sys/i386/i386/machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,11 +486,11 @@ osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)

regs->tf_esp = (int)fp;
if (p->p_sysent->sv_sigcode_base != 0) {
regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
regs->tf_eip = p->p_sigcode_base + szsigcode -
szosigcode;
} else {
/* a.out sysentvec does not use shared page */
regs->tf_eip = p->p_sysent->sv_psstrings - szosigcode;
regs->tf_eip = p->p_psstrings - szosigcode;
}
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
Expand Down Expand Up @@ -618,7 +618,7 @@ freebsd4_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}

regs->tf_esp = (int)sfp;
regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
regs->tf_eip = p->p_sigcode_base + szsigcode -
szfreebsd4_sigcode;
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
Expand Down Expand Up @@ -792,9 +792,9 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}

regs->tf_esp = (int)sfp;
regs->tf_eip = p->p_sysent->sv_sigcode_base;
regs->tf_eip = p->p_sigcode_base;
if (regs->tf_eip == 0)
regs->tf_eip = p->p_sysent->sv_psstrings - szsigcode;
regs->tf_eip = p->p_psstrings - szsigcode;
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;
Expand Down
2 changes: 1 addition & 1 deletion sys/i386/linux/linux_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot,
* mmap's return value.
*/
PROC_LOCK(p);
p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
p->p_vmspace->vm_maxsaddr = (char *)p->p_usrstack -
lim_cur(p, RLIMIT_STACK);
PROC_UNLOCK(p);
}
Expand Down
8 changes: 6 additions & 2 deletions sys/i386/linux/linux_sysvec.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include "opt_pax.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/exec.h>
Expand All @@ -41,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/syscallsubr.h>
Expand Down Expand Up @@ -250,8 +253,8 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
("unsafe elf_linux_fixup(), should be curproc"));

p = imgp->proc;
arginfo = (struct ps_strings *)p->p_psstrings;
issetugid = imgp->proc->p_flag & P_SUGID ? 1 : 0;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
args = (Elf32_Auxargs *)imgp->auxargs;
pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
Expand Down Expand Up @@ -311,7 +314,7 @@ linux_copyout_strings(struct image_params *imgp)
* Also deal with signal trampoline code for this exec type.
*/
p = imgp->proc;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
arginfo = (struct ps_strings *)p->p_psstrings;
destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform -
roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));

Expand Down Expand Up @@ -975,6 +978,7 @@ struct sysentvec linux_sysvec = {
.sv_shared_page_base = LINUX_SHAREDPAGE,
.sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = linux_schedtail,
.sv_pax_aslr_init = pax_aslr_init_vmspace,
};
INIT_SYSENTVEC(aout_sysvec, &linux_sysvec);

Expand Down
37 changes: 23 additions & 14 deletions sys/kern/imgact_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$");

#include "opt_capsicum.h"
#include "opt_compat.h"
#include "opt_core.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/capsicum.h>
Expand All @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/namei.h>
#include <sys/pax.h>
#include <sys/pioctl.h>
#include <sys/proc.h>
#include <sys/procfs.h>
Expand Down Expand Up @@ -791,16 +792,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
if (hdr->e_type == ET_DYN) {
if ((brand_info->flags & BI_CAN_EXEC_DYN) == 0)
return (ENOEXEC);
/*
* Honour the base load address from the dso if it is
* non-zero for some reason.
*/
if (baddr == 0)
et_dyn_addr = ET_DYN_LOAD_ADDR;
else
et_dyn_addr = 0;
} else
et_dyn_addr = 0;
}
sv = brand_info->sysvec;
if (interp != NULL && brand_info->interp_newpath != NULL)
newinterp = brand_info->interp_newpath;
Expand All @@ -821,6 +813,20 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
error = exec_new_vmspace(imgp, sv);
imgp->proc->p_sysent = sv;

et_dyn_addr = 0;
if (hdr->e_type == ET_DYN) {
/*
* Honour the base load address from the dso if it is
* non-zero for some reason.
*/
if (baddr == 0) {
et_dyn_addr = ET_DYN_LOAD_ADDR;
#ifdef PAX_ASLR
pax_aslr_execbase(imgp->proc, &et_dyn_addr);
#endif
}
}

vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
if (error)
return (error);
Expand Down Expand Up @@ -918,6 +924,9 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
*/
addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(imgp->proc,
RLIMIT_DATA));
#ifdef PAX_ASLR
pax_aslr_rtld(imgp->proc, &addr);
#endif
PROC_UNLOCK(imgp->proc);

imgp->entry_addr = entry;
Expand Down Expand Up @@ -1011,7 +1020,7 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp)
}
if (imgp->sysent->sv_timekeep_base != 0) {
AUXARGS_ENTRY(pos, AT_TIMEKEEP,
imgp->sysent->sv_timekeep_base);
imgp->proc->p_timekeep_base);
}
AUXARGS_ENTRY(pos, AT_STACKPROT, imgp->sysent->sv_shared_page_obj
!= NULL && imgp->stack_prot != 0 ? imgp->stack_prot :
Expand Down Expand Up @@ -1979,9 +1988,9 @@ __elfN(note_procstat_psstrings)(void *arg, struct sbuf *sb, size_t *sizep)
KASSERT(*sizep == size, ("invalid size"));
structsize = sizeof(ps_strings);
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
ps_strings = PTROUT(p->p_sysent->sv_psstrings);
ps_strings = PTROUT(p->p_psstrings);
#else
ps_strings = p->p_sysent->sv_psstrings;
ps_strings = p->p_psstrings;
#endif
sbuf_bcat(sb, &structsize, sizeof(structsize));
sbuf_bcat(sb, &ps_strings, sizeof(ps_strings));
Expand Down
15 changes: 13 additions & 2 deletions sys/kern/init_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");

#include "opt_ddb.h"
#include "opt_init_path.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/kernel.h>
Expand All @@ -60,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/racct.h>
#include <sys/resourcevar.h>
Expand Down Expand Up @@ -410,6 +412,7 @@ struct sysentvec null_sysvec = {
.sv_fetch_syscall_args = null_fetch_syscall_args,
.sv_syscallnames = NULL,
.sv_schedtail = NULL,
.sv_pax_aslr_init = NULL,
};

/*
Expand Down Expand Up @@ -476,6 +479,11 @@ proc0_init(void *dummy __unused)
p->p_flag = P_SYSTEM | P_INMEM;
p->p_flag2 = 0;
p->p_state = PRS_NORMAL;
#ifdef PAX
p->p_pax = PAX_NOTE_ALL_DISABLED;
#endif
p->p_usrstack = USRSTACK;
p->p_psstrings = PS_STRINGS;
knlist_init_mtx(&p->p_klist, &p->p_mtx);
STAILQ_INIT(&p->p_ktr);
p->p_nice = NZERO;
Expand All @@ -493,6 +501,9 @@ proc0_init(void *dummy __unused)
td->td_flags = TDF_INMEM;
td->td_pflags = TDP_KTHREAD;
td->td_cpuset = cpuset_thread0();
#ifdef PAX
td->td_pax = PAX_NOTE_ALL_DISABLED;
#endif
prison0_init();
p->p_peers = 0;
p->p_leader = p;
Expand Down Expand Up @@ -713,7 +724,7 @@ start_init(void *dummy)
/*
* Need just enough stack to hold the faked-up "execve()" arguments.
*/
addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
addr = p->p_usrstack - PAGE_SIZE;
if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE, 0,
VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0)
panic("init: couldn't allocate argument space");
Expand All @@ -740,7 +751,7 @@ start_init(void *dummy)
* Move out the boot flag argument.
*/
options = 0;
ucp = (char *)p->p_sysent->sv_usrstack;
ucp = (char *)p->p_usrstack;
(void)subyte(--ucp, 0); /* trailing zero */
if (boothowto & RB_SINGLE) {
(void)subyte(--ucp, 's');
Expand Down
89 changes: 69 additions & 20 deletions sys/kern/kern_exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#include "opt_hwpmc_hooks.h"
#include "opt_kdtrace.h"
#include "opt_ktrace.h"
#include "opt_pax.h"
#include "opt_vm.h"

#include <sys/param.h>
Expand All @@ -52,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/imgact_elf.h>
#include <sys/wait.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/pioctl.h>
Expand Down Expand Up @@ -128,11 +130,6 @@ SYSCTL_INT(_kern, OID_AUTO, disallow_high_osrel, CTLFLAG_RW,
&disallow_high_osrel, 0,
"Disallow execution of binaries built for higher version of the world");

static int map_at_zero = 0;
TUNABLE_INT("security.bsd.map_at_zero", &map_at_zero);
SYSCTL_INT(_security_bsd, OID_AUTO, map_at_zero, CTLFLAG_RW, &map_at_zero, 0,
"Permit processes to map an object at virtual address 0.");

static int
sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS)
{
Expand All @@ -143,12 +140,12 @@ sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS)
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
unsigned int val;
val = (unsigned int)p->p_sysent->sv_psstrings;
val = (unsigned int)p->p_psstrings;
error = SYSCTL_OUT(req, &val, sizeof(val));
} else
#endif
error = SYSCTL_OUT(req, &p->p_sysent->sv_psstrings,
sizeof(p->p_sysent->sv_psstrings));
error = SYSCTL_OUT(req, &p->p_psstrings,
sizeof(p->p_psstrings));
return error;
}

Expand All @@ -162,12 +159,12 @@ sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS)
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
unsigned int val;
val = (unsigned int)p->p_sysent->sv_usrstack;
val = (unsigned int)p->p_usrstack;
error = SYSCTL_OUT(req, &val, sizeof(val));
} else
#endif
error = SYSCTL_OUT(req, &p->p_sysent->sv_usrstack,
sizeof(p->p_sysent->sv_usrstack));
error = SYSCTL_OUT(req, &p->p_usrstack,
sizeof(p->p_usrstack));
return error;
}

Expand Down Expand Up @@ -452,6 +449,12 @@ do_execve(td, args, mac_p)
imgp->vp = binvp;
}

#ifdef PAX
error = pax_elf(imgp, td, 0);
if (error)
goto exec_fail_dealloc;
#endif

/*
* Check file permissions (also 'opens' file)
*/
Expand Down Expand Up @@ -565,6 +568,11 @@ do_execve(td, args, mac_p)
goto exec_fail_dealloc;
}

p->p_psstrings = p->p_sysent->sv_psstrings;
#ifdef PAX_ASLR
pax_aslr_stack_with_gap(p, &(p->p_psstrings));
#endif

/*
* Copy out strings (args and env) and initialize stack base
*/
Expand Down Expand Up @@ -1045,10 +1053,7 @@ exec_new_vmspace(imgp, sv)
* not disrupted
*/
map = &vmspace->vm_map;
if (map_at_zero)
sv_minuser = sv->sv_minuser;
else
sv_minuser = MAX(sv->sv_minuser, PAGE_SIZE);
sv_minuser = MAX(sv->sv_minuser, PAGE_SIZE);
if (vmspace->vm_refcnt == 1 && vm_map_min(map) == sv_minuser &&
vm_map_max(map) == sv->sv_maxuser) {
shmexit(vmspace);
Expand All @@ -1062,19 +1067,44 @@ exec_new_vmspace(imgp, sv)
map = &vmspace->vm_map;
}

#ifdef PAX_ASLR
PROC_LOCK(imgp->proc);
pax_aslr_init(imgp);
PROC_UNLOCK(imgp->proc);
#endif

/* Map a shared page */
obj = sv->sv_shared_page_obj;
if (obj != NULL) {
p->p_shared_page_base = sv->sv_shared_page_base;
#ifdef PAX_ASLR
PROC_LOCK(imgp->proc);
pax_aslr_vdso(p, &(p->p_shared_page_base));
PROC_UNLOCK(imgp->proc);
#endif
vm_object_reference(obj);
error = vm_map_fixed(map, obj, 0,
sv->sv_shared_page_base, sv->sv_shared_page_len,
p->p_shared_page_base, sv->sv_shared_page_len,
VM_PROT_READ | VM_PROT_EXECUTE,
VM_PROT_READ | VM_PROT_EXECUTE,
MAP_INHERIT_SHARE | MAP_ACC_NO_CHARGE);
if (error) {
#ifdef PAX_ASLR
pax_log_aslr(p, PAX_LOG_DEFAULT,
"failed to map the shared-page @%p",
(void *)p->p_shared_page_base);
#endif
vm_object_deallocate(obj);
return (error);
}

p->p_timekeep_base = sv->sv_timekeep_base;
#ifdef PAX_ASLR
PROC_LOCK(imgp->proc);
if (p->p_timekeep_base != 0)
pax_aslr_vdso(p, &(p->p_timekeep_base));
PROC_UNLOCK(imgp->proc);
#endif
}

/* Allocate a new stack */
Expand All @@ -1094,13 +1124,27 @@ exec_new_vmspace(imgp, sv)
} else {
ssiz = maxssiz;
}
stack_addr = sv->sv_usrstack - ssiz;
stack_addr = sv->sv_usrstack;
#ifdef PAX_ASLR
/* Randomize the stack top. */
pax_aslr_stack(p, &stack_addr);
#endif
/* Save the process specific randomized stack top */
p->p_usrstack = stack_addr;
/* Calculate the stack's mapping address */
stack_addr -= ssiz;
error = vm_map_stack(map, stack_addr, (vm_size_t)ssiz,
obj != NULL && imgp->stack_prot != 0 ? imgp->stack_prot :
sv->sv_stackprot,
VM_PROT_ALL, MAP_STACK_GROWS_DOWN);
if (error)
if (error) {
#ifdef PAX_ASLR
pax_log_aslr(p, PAX_LOG_DEFAULT,
"failed to map the main stack @%p",
(void *)p->p_usrstack);
#endif
return (error);
}

#ifdef __ia64__
/* Allocate a new register stack */
Expand Down Expand Up @@ -1278,10 +1322,15 @@ exec_copyout_strings(imgp)
execpath_len = 0;
p = imgp->proc;
szsigcode = 0;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
if (p->p_sysent->sv_sigcode_base == 0) {
p->p_sigcode_base = p->p_sysent->sv_sigcode_base;
arginfo = (struct ps_strings *)p->p_psstrings;
if (p->p_sigcode_base == 0) {
if (p->p_sysent->sv_szsigcode != NULL)
szsigcode = *(p->p_sysent->sv_szsigcode);
#ifdef PAX_ASLR
} else {
pax_aslr_vdso(p, &(p->p_sigcode_base));
#endif
}
destp = (uintptr_t)arginfo;

Expand Down
1 change: 1 addition & 0 deletions sys/kern/kern_fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
__rangeof(struct thread, td_startcopy, td_endcopy));

bcopy(&p2->p_comm, &td2->td_name, sizeof(td2->td_name));
td2->td_pax = p2->p_pax;
td2->td_sigstk = td->td_sigstk;
td2->td_flags = TDF_INMEM;
td2->td_lend_user_pri = PRI_MAX;
Expand Down
30 changes: 30 additions & 0 deletions sys/kern/kern_jail.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ddb.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/types.h>
Expand Down Expand Up @@ -249,6 +250,10 @@ prison0_init(void)
prison0.pr_cpuset = cpuset_ref(thread0.td_cpuset);
prison0.pr_osreldate = osreldate;
strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease));

#ifdef PAX
pax_init_prison(&prison0);
#endif
}

#ifdef INET
Expand Down Expand Up @@ -1367,6 +1372,10 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
goto done_releroot;
}

#ifdef PAX
pax_init_prison(pr);
#endif

mtx_lock(&pr->pr_mtx);
/*
* New prisons do not yet have a reference, because we do not
Expand Down Expand Up @@ -4731,6 +4740,27 @@ db_show_prison(struct prison *pr)
ii == 0 ? "ip6.addr =" : " ",
ip6_sprintf(ip6buf, &pr->pr_ip6[ii]));
#endif
#ifdef PAX
db_printf(" pr_hbsd = {\n");

db_printf(" .aslr = {\n");
db_printf(" .status = %d\n",
pr->pr_hbsd.aslr.status);
db_printf(" .compat_status = %d\n",
pr->pr_hbsd.aslr.compat_status);
db_printf(" .disallow_map32bit_status = %d\n",
pr->pr_hbsd.aslr.disallow_map32bit_status);
db_printf(" }\n");

db_printf(" .log = {\n");
db_printf(" .log = %d\n",
pr->pr_hbsd.log.log);
db_printf(" .ulog = %d\n",
pr->pr_hbsd.log.ulog);
db_printf(" }\n");

db_printf(" }\n");
#endif
}

DB_SHOW_COMMAND(prison, db_show_prison_command)
Expand Down
2 changes: 2 additions & 0 deletions sys/kern/kern_mib.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ SYSCTL_ROOT_NODE(OID_AUTO, compat, CTLFLAG_RW, 0,
"Compatibility code");
SYSCTL_ROOT_NODE(OID_AUTO, security, CTLFLAG_RW, 0,
"Security");
SYSCTL_ROOT_NODE(OID_AUTO, hardening, CTLFLAG_RW, 0,
"Kernel hardening features");
#ifdef REGRESSION
SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0,
"Regression test MIB");
Expand Down
24 changes: 12 additions & 12 deletions sys/kern/kern_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,7 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp,
size_t vsize, size;
int i, error;

error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
error = proc_read_mem(td, p, (vm_offset_t)(p->p_psstrings),
&pss, sizeof(pss));
if (error != 0)
return (error);
Expand Down Expand Up @@ -1617,7 +1617,7 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp,
if (SV_PROC_FLAG(p, SV_ILP32) != 0)
return (get_proc_vector32(td, p, proc_vectorp, vsizep, type));
#endif
error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
error = proc_read_mem(td, p, (vm_offset_t)(p->p_psstrings),
&pss, sizeof(pss));
if (error != 0)
return (error);
Expand Down Expand Up @@ -2609,13 +2609,13 @@ sysctl_kern_proc_ps_strings(SYSCTL_HANDLER_ARGS)
* process.
*/
ps_strings32 = SV_PROC_FLAG(p, SV_ILP32) != 0 ?
PTROUT(p->p_sysent->sv_psstrings) : 0;
PTROUT(p->p_psstrings) : 0;
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &ps_strings32, sizeof(ps_strings32));
return (error);
}
#endif
ps_strings = p->p_sysent->sv_psstrings;
ps_strings = p->p_psstrings;
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &ps_strings, sizeof(ps_strings));
return (error);
Expand Down Expand Up @@ -2719,13 +2719,13 @@ sysctl_kern_proc_sigtramp(SYSCTL_HANDLER_ARGS)
bzero(&kst32, sizeof(kst32));
if (SV_PROC_FLAG(p, SV_ILP32)) {
if (sv->sv_sigcode_base != 0) {
kst32.ksigtramp_start = sv->sv_sigcode_base;
kst32.ksigtramp_end = sv->sv_sigcode_base +
kst32.ksigtramp_start = p->p_sigcode_base;
kst32.ksigtramp_end = p->p_sigcode_base +
*sv->sv_szsigcode;
} else {
kst32.ksigtramp_start = sv->sv_psstrings -
kst32.ksigtramp_start = p->p_psstrings -
*sv->sv_szsigcode;
kst32.ksigtramp_end = sv->sv_psstrings;
kst32.ksigtramp_end = p->p_psstrings;
}
}
PROC_UNLOCK(p);
Expand All @@ -2735,13 +2735,13 @@ sysctl_kern_proc_sigtramp(SYSCTL_HANDLER_ARGS)
#endif
bzero(&kst, sizeof(kst));
if (sv->sv_sigcode_base != 0) {
kst.ksigtramp_start = (char *)sv->sv_sigcode_base;
kst.ksigtramp_end = (char *)sv->sv_sigcode_base +
kst.ksigtramp_start = (char *)p->p_sigcode_base;
kst.ksigtramp_end = (char *)p->p_sigcode_base +
*sv->sv_szsigcode;
} else {
kst.ksigtramp_start = (char *)sv->sv_psstrings -
kst.ksigtramp_start = (char *)p->p_psstrings -
*sv->sv_szsigcode;
kst.ksigtramp_end = (char *)sv->sv_psstrings;
kst.ksigtramp_end = (char *)p->p_psstrings;
}
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &kst, sizeof(kst));
Expand Down
6 changes: 4 additions & 2 deletions sys/kern/kern_resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
__FBSDID("$FreeBSD$");

#include "opt_compat.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/systm.h>
Expand All @@ -47,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/refcount.h>
Expand Down Expand Up @@ -776,12 +778,12 @@ kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which,
if (limp->rlim_cur > oldssiz.rlim_cur) {
prot = p->p_sysent->sv_stackprot;
size = limp->rlim_cur - oldssiz.rlim_cur;
addr = p->p_sysent->sv_usrstack -
addr = p->p_usrstack -
limp->rlim_cur;
} else {
prot = VM_PROT_NONE;
size = oldssiz.rlim_cur - limp->rlim_cur;
addr = p->p_sysent->sv_usrstack -
addr = p->p_usrstack -
oldssiz.rlim_cur;
}
addr = trunc_page(addr);
Expand Down
1 change: 1 addition & 0 deletions sys/kern/kern_thr.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ create_thread(struct thread *td, mcontext_t *ctx,
td->td_proc->p_flag |= P_HADTHREADS;
thread_link(newtd, p);
bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
newtd->td_pax = p->p_pax;
thread_lock(td);
/* let the scheduler know about these things. */
sched_fork_thread(td, newtd);
Expand Down
45 changes: 45 additions & 0 deletions sys/kern/subr_prf.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");

#ifdef _KERNEL
#include "opt_ddb.h"
#include "opt_pax.h"
#include "opt_printf.h"
#endif /* _KERNEL */

Expand All @@ -52,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/msgbuf.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/stddef.h>
Expand Down Expand Up @@ -180,6 +182,49 @@ uprintf(const char *fmt, ...)
return (retval);
}

int
hbsd_uprintf(const char *fmt, ...)
{
va_list ap;
struct putchar_arg pca;
struct proc *p;
struct thread *td;
int p_locked, retval;

td = curthread;
if (TD_IS_IDLETHREAD(td))
return (0);

sx_slock(&proctree_lock);
p = td->td_proc;
if ((p_locked = PROC_LOCKED(p)))
PROC_LOCK(p);
if ((p->p_flag & P_CONTROLT) == 0) {
if (p_locked)
PROC_UNLOCK(p);
sx_sunlock(&proctree_lock);
return (0);
}
SESS_LOCK(p->p_session);
pca.tty = p->p_session->s_ttyp;
SESS_UNLOCK(p->p_session);
if (p_locked)
PROC_UNLOCK(p);
if (pca.tty == NULL) {
sx_sunlock(&proctree_lock);
return (0);
}
pca.flags = TOTTY;
pca.p_bufr = NULL;
va_start(ap, fmt);
tty_lock(pca.tty);
sx_sunlock(&proctree_lock);
retval = kvprintf(fmt, putchar, &pca, 10, ap);
tty_unlock(pca.tty);
va_end(ap);
return (retval);
}

/*
* tprintf and vtprintf print on the controlling terminal associated with the
* given session, possibly to the log as well.
Expand Down
2 changes: 2 additions & 0 deletions sys/kern/sys_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
__FBSDID("$FreeBSD$");

#include "opt_compat.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/systm.h>
Expand All @@ -44,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/pax.h>
#include <sys/ptrace.h>
#include <sys/rwlock.h>
#include <sys/sx.h>
Expand Down
5 changes: 5 additions & 0 deletions sys/mips/mips/elf_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include "opt_pax.h"

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
Expand All @@ -36,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/signalvar.h>
Expand Down Expand Up @@ -83,6 +86,7 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
.sv_schedtail = NULL,
.sv_pax_aslr_init = pax_aslr_init_vmspace,
};

static Elf64_Brandinfo freebsd_brand_info = {
Expand Down Expand Up @@ -139,6 +143,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
.sv_schedtail = NULL,
.sv_pax_aslr_init = pax_aslr_init_vmspace,
};

static Elf32_Brandinfo freebsd_brand_info = {
Expand Down
5 changes: 4 additions & 1 deletion sys/mips/mips/freebsd32_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
*/

#include "opt_compat.h"
#include "opt_pax.h"

#define __ELF_WORD_SIZE 32

Expand All @@ -42,6 +43,7 @@
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/fcntl.h>
Expand Down Expand Up @@ -106,6 +108,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = freebsd32_syscallnames,
.sv_schedtail = NULL,
.sv_pax_aslr_init = pax_aslr_init_vmspace32,
};
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);

Expand Down Expand Up @@ -464,7 +467,7 @@ freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/*
* Signal trampoline code is at base of user stack.
*/
td->td_frame->ra = (register_t)(intptr_t)FREEBSD32_PS_STRINGS - *(p->p_sysent->sv_szsigcode);
td->td_frame->ra = (register_t)(intptr_t)p->p_psstrings - *(p->p_sysent->sv_szsigcode);
PROC_LOCK(p);
mtx_lock(&psp->ps_mtx);
}
Expand Down
2 changes: 1 addition & 1 deletion sys/mips/mips/pm_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/*
* Signal trampoline code is at base of user stack.
*/
regs->ra = (register_t)(intptr_t)PS_STRINGS - *(p->p_sysent->sv_szsigcode);
regs->ra = (register_t)(intptr_t)p->p_psstrings - *(p->p_sysent->sv_szsigcode);
PROC_LOCK(p);
mtx_lock(&psp->ps_mtx);
}
Expand Down
4 changes: 4 additions & 0 deletions sys/powerpc/powerpc/elf32_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
* $FreeBSD$
*/

#include "opt_pax.h"

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
Expand All @@ -34,6 +36,7 @@
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/fcntl.h>
Expand Down Expand Up @@ -107,6 +110,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_shared_page_base = FREEBSD32_SHAREDPAGE,
.sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL,
.sv_pax_aslr_init = pax_aslr_init_vmspace32,
};
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);

Expand Down
4 changes: 4 additions & 0 deletions sys/powerpc/powerpc/elf64_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@
* $FreeBSD$
*/

#include "opt_pax.h"

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/fcntl.h>
Expand Down Expand Up @@ -83,6 +86,7 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_shared_page_base = SHAREDPAGE,
.sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL,
.sv_pax_aslr_init = pax_aslr_init_vmspace,
};
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);

Expand Down
2 changes: 1 addition & 1 deletion sys/powerpc/powerpc/exec_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
mtx_unlock(&psp->ps_mtx);
PROC_UNLOCK(p);

tf->srr0 = (register_t)p->p_sysent->sv_sigcode_base;
tf->srr0 = (register_t)p->p_sigcode_base;

/*
* copy the frame out to userland.
Expand Down
4 changes: 4 additions & 0 deletions sys/sparc64/sparc64/elf_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
* from: NetBSD: mdreloc.c,v 1.42 2008/04/28 20:23:04 martin Exp
*/

#include "opt_pax.h"

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

Expand All @@ -40,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
Expand Down Expand Up @@ -87,6 +90,7 @@ static struct sysentvec elf64_freebsd_sysvec = {
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
.sv_schedtail = NULL,
.sv_pax_aslr_init = pax_aslr_init_vmspace,
};

static Elf64_Brandinfo freebsd_brand_info = {
Expand Down
2 changes: 1 addition & 1 deletion sys/sparc64/sparc64/machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
bzero(pcb, sizeof(*pcb));
bzero(tf, sizeof(*tf));
tf->tf_out[0] = stack;
tf->tf_out[3] = p->p_sysent->sv_psstrings;
tf->tf_out[3] = p->p_psstrings;
tf->tf_out[6] = sp - SPOFF - sizeof(struct frame);
tf->tf_tnpc = imgp->entry_addr + 4;
tf->tf_tpc = imgp->entry_addr;
Expand Down
5 changes: 5 additions & 0 deletions sys/sys/jail.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#ifndef _SYS_JAIL_H_
#define _SYS_JAIL_H_

#if defined(_KERNEL) || defined(_WANT_PRISON)
#include <sys/pax.h>
#endif

#ifdef _KERNEL
struct jail_v0 {
u_int32_t version;
Expand Down Expand Up @@ -187,6 +191,7 @@ struct prison {
char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */
char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */
char pr_osrelease[OSRELEASELEN]; /* (c) kern.osrelease value */
struct hbsd_features pr_hbsd; /* (p) PaX-inspired hardening features */
};

struct prison_racct {
Expand Down
1 change: 1 addition & 0 deletions sys/sys/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ enum sysinit_sub_id {
SI_SUB_WITNESS = 0x1A80000, /* witness initialization */
SI_SUB_MTX_POOL_DYNAMIC = 0x1AC0000, /* dynamic mutex pool */
SI_SUB_LOCK = 0x1B00000, /* various locks */
SI_SUB_PAX = 0x1B80000, /* pax setup */
SI_SUB_EVENTHANDLER = 0x1C00000, /* eventhandler init */
SI_SUB_VNET_PRELINK = 0x1E00000, /* vnet init before modules */
SI_SUB_KLD = 0x2000000, /* KLD and module setup */
Expand Down
179 changes: 179 additions & 0 deletions sys/sys/pax.h
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 */
7 changes: 7 additions & 0 deletions sys/sys/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ struct thread {
u_char td_pri_class; /* (t) Scheduling class. */
u_char td_user_pri; /* (t) User pri from estcpu and nice. */
u_char td_base_user_pri; /* (t) Base user pri */
uint32_t td_pax; /* (b) Cached PaX settings from process. */
#define td_endcopy td_pcb

/*
Expand Down Expand Up @@ -561,6 +562,12 @@ struct proc {
rlim_t p_cpulimit; /* (c) Current CPU limit in seconds. */
signed char p_nice; /* (c) Process "nice" value. */
int p_fibnum; /* in this routing domain XXX MRT */
uint32_t p_pax; /* (b) PaX is enabled to this process */
vm_offset_t p_usrstack; /* (b) Process stack top. */
vm_offset_t p_psstrings; /* (b) Process psstrings address. */
vm_offset_t p_timekeep_base; /* (c) Address of timekeep structure. */
vm_offset_t p_shared_page_base; /* (c) Address of shared page. */
vm_offset_t p_sigcode_base; /* Address of sigcode. */
/* End area that is copied on creation. */
#define p_endcopy p_xstat

Expand Down
1 change: 1 addition & 0 deletions sys/sys/sysctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,7 @@ SYSCTL_DECL(_compat);
SYSCTL_DECL(_regression);
SYSCTL_DECL(_security);
SYSCTL_DECL(_security_bsd);
SYSCTL_DECL(_hardening);

extern char machine[];
extern char osrelease[];
Expand Down
2 changes: 2 additions & 0 deletions sys/sys/sysent.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct rlimit;
struct sysent;
struct thread;
struct ksiginfo;
struct proc;

typedef int sy_call_t(struct thread *, void *);

Expand Down Expand Up @@ -130,6 +131,7 @@ struct sysentvec {
uint32_t sv_timekeep_gen;
void *sv_shared_page_obj;
void (*sv_schedtail)(struct thread *);
void (* const sv_pax_aslr_init)(struct proc *p);
};

#define SV_ILP32 0x000100
Expand Down
24 changes: 23 additions & 1 deletion sys/vm/vm_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include "opt_pax.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/vmmeter.h>
#include <sys/mman.h>
Expand Down Expand Up @@ -295,6 +298,15 @@ vmspace_alloc(vm_offset_t min, vm_offset_t max, pmap_pinit_t pinit)
vm->vm_taddr = 0;
vm->vm_daddr = 0;
vm->vm_maxsaddr = 0;
#ifdef PAX_ASLR
vm->vm_aslr_delta_mmap = 0;
vm->vm_aslr_delta_stack = 0;
vm->vm_aslr_delta_exec = 0;
vm->vm_aslr_delta_vdso = 0;
#ifdef __LP64__
vm->vm_aslr_delta_map32bit = 0;
#endif
#endif
return (vm);
}

Expand Down Expand Up @@ -3275,6 +3287,15 @@ vmspace_fork(struct vmspace *vm1, vm_ooffset_t *fork_charge)
vm2->vm_taddr = vm1->vm_taddr;
vm2->vm_daddr = vm1->vm_daddr;
vm2->vm_maxsaddr = vm1->vm_maxsaddr;
#ifdef PAX_ASLR
vm2->vm_aslr_delta_exec = vm1->vm_aslr_delta_exec;
vm2->vm_aslr_delta_mmap = vm1->vm_aslr_delta_mmap;
vm2->vm_aslr_delta_stack = vm1->vm_aslr_delta_stack;
vm2->vm_aslr_delta_vdso = vm1->vm_aslr_delta_vdso;
#ifdef __LP64__
vm2->vm_aslr_delta_map32bit = vm1->vm_aslr_delta_map32bit;
#endif
#endif
vm_map_lock(old_map);
if (old_map->busy)
vm_map_wait_busy(old_map);
Expand Down Expand Up @@ -3657,7 +3678,8 @@ vm_map_growstack(struct proc *p, vm_offset_t addr)
return (KERN_NO_SPACE);
}

is_procstack = (addr >= (vm_offset_t)vm->vm_maxsaddr) ? 1 : 0;
is_procstack = (addr >= (vm_offset_t)vm->vm_maxsaddr &&
addr < (vm_offset_t)p->p_usrstack) ? 1 : 0;

/*
* If this is the main process stack, see if we're over the stack
Expand Down
7 changes: 7 additions & 0 deletions sys/vm/vm_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ struct vmspace {
caddr_t vm_taddr; /* (c) user virtual address of text */
caddr_t vm_daddr; /* (c) user virtual address of data */
caddr_t vm_maxsaddr; /* user VA at max stack growth */
vm_offset_t vm_aslr_delta_mmap; /* mmap() random delta for ASLR */
vm_offset_t vm_aslr_delta_stack; /* stack random delta for ASLR */
vm_offset_t vm_aslr_delta_exec; /* exec base random delta for ASLR */
vm_offset_t vm_aslr_delta_vdso; /* VDSO base random delta for ASLR */
#ifdef __LP64__
vm_offset_t vm_aslr_delta_map32bit; /* random for MAP_32BIT mappings */
#endif
volatile int vm_refcnt; /* number of references */
/*
* Keep the PMAP last, so that CPU-specific variations of that
Expand Down
23 changes: 22 additions & 1 deletion sys/vm/vm_mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");

#include "opt_compat.h"
#include "opt_hwpmc_hooks.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/systm.h>
Expand All @@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/sysproto.h>
#include <sys/filedesc.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/procctl.h>
Expand Down Expand Up @@ -211,6 +213,9 @@ sys_mmap(td, uap)
off_t pos;
struct vmspace *vms = td->td_proc->p_vmspace;
cap_rights_t rights;
#ifdef PAX_ASLR
int pax_aslr_done;
#endif

addr = (vm_offset_t) uap->addr;
size = uap->len;
Expand All @@ -220,6 +225,10 @@ sys_mmap(td, uap)

fp = NULL;

#ifdef PAX_ASLR
pax_aslr_done = 0;
#endif

/*
* Enforce the constraints.
* Mapping of length 0 is only allowed for old binaries.
Expand Down Expand Up @@ -297,7 +306,13 @@ sys_mmap(td, uap)
*/
if (addr + size > MAP_32BIT_MAX_ADDR)
addr = 0;
#endif
#ifdef PAX_ASLR
PROC_LOCK(td->td_proc);
pax_aslr_mmap_map_32bit(td->td_proc, &addr, (vm_offset_t)uap->addr, flags);
pax_aslr_done = 1;
PROC_UNLOCK(td->td_proc);
#endif /* PAX_ASLR */
#endif /* MAP_32BIT */
} else {
/*
* XXX for non-fixed mappings where no hint is provided or
Expand All @@ -315,6 +330,12 @@ sys_mmap(td, uap)
addr = round_page((vm_offset_t)vms->vm_daddr +
lim_max(td->td_proc, RLIMIT_DATA));
PROC_UNLOCK(td->td_proc);
#ifdef PAX_ASLR
PROC_LOCK(td->td_proc);
pax_aslr_mmap(td->td_proc, &addr, (vm_offset_t)uap->addr, flags);
pax_aslr_done = 1;
PROC_UNLOCK(td->td_proc);
#endif
}
if (flags & MAP_ANON) {
/*
Expand Down