diff --git a/sys/conf/NOTES b/sys/conf/NOTES index ef77f23bb6e..ea402378acb 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -3061,6 +3061,7 @@ options GZIO # PAX and HardenedBSD related knobs options PAX # Enable the PAX framework options PAX_ASLR # Address Space Layout Randomization +options PAX_HARDENING # Other hardening features options PAX_SEGVGUARD # ASLR bruteforce protection options HBSD_DEBUG diff --git a/sys/conf/files b/sys/conf/files index 45058eb7483..c20593770ff 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3219,6 +3219,7 @@ fs/ext2fs/ext2_vfsops.c optional ext2fs fs/ext2fs/ext2_vnops.c optional ext2fs # hardenedbsd/hbsd_pax_common.c optional pax +hardenedbsd/hbsd_pax_hardening.c optional pax pax_hardening hardenedbsd/hbsd_pax_log.c optional pax hardenedbsd/hbsd_pax_aslr.c optional pax pax_aslr hardenedbsd/hbsd_pax_segvguard.c optional pax pax_segvguard diff --git a/sys/conf/options b/sys/conf/options index 12bd8740546..3db152789fc 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -968,6 +968,7 @@ RCTL opt_global.h # PaX-inspired hardening features PAX opt_pax.h PAX_ASLR opt_pax.h +PAX_HARDENING opt_pax.h PAX_SEGVGUARD opt_pax.h PAX_SYSCTLS opt_pax.h HBSD_DEBUG opt_pax.h diff --git a/sys/fs/procfs/procfs_dbregs.c b/sys/fs/procfs/procfs_dbregs.c index 1598443bce9..4c5f25bb4d4 100644 --- a/sys/fs/procfs/procfs_dbregs.c +++ b/sys/fs/procfs/procfs_dbregs.c @@ -44,11 +44,13 @@ */ #include "opt_compat.h" +#include "opt_pax.h" #include #include #include #include +#include #include #include #include @@ -121,11 +123,17 @@ procfs_doprocdbregs(PFS_FILL_ARGS) PROC_LOCK(p); } if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (!P_SHOULDSTOP(p)) /* XXXKSE should be P_TRACED? */ + if (!P_SHOULDSTOP(p)) /* XXXKSE should be P_TRACED? */ { error = EBUSY; - else + } +#ifdef PAX_HARDENING + else if ((error = pax_procfs_harden(td2)) == 0) { +#else + else { +#endif /* XXXKSE: */ error = PROC(write, dbregs, td2, &r); + } } PROC_UNLOCK(p); diff --git a/sys/fs/procfs/procfs_fpregs.c b/sys/fs/procfs/procfs_fpregs.c index d2f01535eb5..a7a01a51e53 100644 --- a/sys/fs/procfs/procfs_fpregs.c +++ b/sys/fs/procfs/procfs_fpregs.c @@ -38,11 +38,13 @@ */ #include "opt_compat.h" +#include "opt_pax.h" #include #include #include #include +#include #include #include #include @@ -120,11 +122,17 @@ procfs_doprocfpregs(PFS_FILL_ARGS) PROC_LOCK(p); } if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (!P_SHOULDSTOP(p)) + if (!P_SHOULDSTOP(p)) { error = EBUSY; - else + } +#ifdef PAX_HARDENING + else if ((error = pax_procfs_harden(td2)) == 0) { +#else + else { +#endif /* XXXKSE: */ error = PROC(write, fpregs, td2, &r); + } } PROC_UNLOCK(p); diff --git a/sys/fs/procfs/procfs_mem.c b/sys/fs/procfs/procfs_mem.c index d4a789635b0..1a8e4314d54 100644 --- a/sys/fs/procfs/procfs_mem.c +++ b/sys/fs/procfs/procfs_mem.c @@ -36,9 +36,12 @@ * $FreeBSD$ */ +#include "opt_pax.h" + #include #include #include +#include #include #include #include @@ -63,6 +66,10 @@ procfs_doprocmem(PFS_FILL_ARGS) PROC_LOCK(p); error = p_candebug(td, p); +#ifdef PAX_HARDENING + if (error == 0) + error = pax_procfs_harden(td); +#endif PROC_UNLOCK(p); if (error == 0) error = proc_rwmem(p, uio); diff --git a/sys/fs/procfs/procfs_regs.c b/sys/fs/procfs/procfs_regs.c index 3f784782d89..83c198b2629 100644 --- a/sys/fs/procfs/procfs_regs.c +++ b/sys/fs/procfs/procfs_regs.c @@ -38,11 +38,13 @@ */ #include "opt_compat.h" +#include "opt_pax.h" #include #include #include #include +#include #include #include #include @@ -120,11 +122,17 @@ procfs_doprocregs(PFS_FILL_ARGS) PROC_LOCK(p); } if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (!P_SHOULDSTOP(p)) + if (!P_SHOULDSTOP(p)) { error = EBUSY; - else + } +#ifdef PAX_HARDENING + else if ((error = pax_procfs_harden(td2)) == 0) { +#else + else { +#endif /* XXXKSE: */ error = PROC(write, regs, td2, &r); + } } PROC_UNLOCK(p); diff --git a/sys/hardenedbsd/hbsd_pax_hardening.c b/sys/hardenedbsd/hbsd_pax_hardening.c new file mode 100644 index 00000000000..d84d6996357 --- /dev/null +++ b/sys/hardenedbsd/hbsd_pax_hardening.c @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 2014, by Shawn Webb + * Copyright (c) 2014-2016, by Oliver Pinter + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" +#include "opt_pax.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hbsd_pax_internal.h" + +FEATURE(hbsd_hardening, "Various hardening features."); + +static int pax_procfs_harden_global = PAX_FEATURE_SIMPLE_ENABLED; + +TUNABLE_INT("hardening.procfs_harden", &pax_procfs_harden_global); + +#ifdef PAX_SYSCTLS +SYSCTL_HBSD_2STATE(pax_procfs_harden_global, pr_hbsd.hardening.procfs_harden, + _hardening, procfs_harden, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_SECURE, + "Harden procfs, disabling write of /proc/pid/mem"); +#endif + +static void +pax_hardening_sysinit(void) +{ + + switch (pax_procfs_harden_global) { + case PAX_FEATURE_SIMPLE_DISABLED: + case PAX_FEATURE_SIMPLE_ENABLED: + break; + default: + printf("[HBSD HARDENING] WARNING, invalid settings in loader.conf!" + " (hardening.procfs_harden = %d)\n", pax_procfs_harden_global); + pax_procfs_harden_global = PAX_FEATURE_SIMPLE_ENABLED; + } + printf("[HBSD HARDENING] procfs hardening: %s\n", + pax_status_simple_str[pax_procfs_harden_global]); +} +SYSINIT(pax_hardening, SI_SUB_PAX, SI_ORDER_SECOND, pax_hardening_sysinit, NULL); + +void +pax_hardening_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.hardening.procfs_harden = + pax_procfs_harden_global; + } else { + KASSERT(pr->pr_parent != NULL, + ("%s: pr->pr_parent == NULL", __func__)); + pr_p = pr->pr_parent; + + pr->pr_hbsd.hardening.procfs_harden = + pr_p->pr_hbsd.hardening.procfs_harden; + } +} + +int +pax_procfs_harden(struct thread *td) +{ + struct prison *pr; + + pr = pax_get_prison_td(td); + + return (pr->pr_hbsd.hardening.procfs_harden ? EPERM : 0); +} diff --git a/sys/sys/pax.h b/sys/sys/pax.h index fd54d561f91..3dee76fc242 100644 --- a/sys/sys/pax.h +++ b/sys/sys/pax.h @@ -49,6 +49,9 @@ struct hbsd_features { int log; /* (p) Per-jail logging status */ int ulog; /* (p) Per-jail user visible logging status */ } log; + struct hbsd_hardening { + int procfs_harden; /* (p) Harden procfs */ + } hardening; }; #endif