The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_pax.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_pax.c,v 1.63 2022/10/26 23:22:38 riastradh Exp $  */
    2 
    3 /*
    4  * Copyright (c) 2015, 2020 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Maxime Villard.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
   34  * All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  * 3. The name of the author may not be used to endorse or promote products
   45  *    derived from this software without specific prior written permission.
   46  *
   47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   50  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   51  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   52  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   53  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   54  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   55  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   56  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   57  */
   58 
   59 #include <sys/cdefs.h>
   60 __KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.63 2022/10/26 23:22:38 riastradh Exp $");
   61 
   62 #include "opt_pax.h"
   63 
   64 #include <sys/param.h>
   65 #include <sys/proc.h>
   66 #include <sys/exec.h>
   67 #include <sys/exec_elf.h>
   68 #include <sys/pax.h>
   69 #include <sys/sysctl.h>
   70 #include <sys/kmem.h>
   71 #include <sys/mman.h>
   72 #include <sys/syslog.h>
   73 #include <sys/vnode.h>
   74 #include <sys/queue.h>
   75 #include <sys/bitops.h>
   76 #include <sys/kauth.h>
   77 #include <sys/cprng.h>
   78 
   79 #ifdef PAX_ASLR_DEBUG
   80 #define PAX_DPRINTF(_fmt, args...) \
   81         do if (pax_aslr_debug) uprintf("%s: " _fmt "\n", __func__, ##args); \
   82         while (/*CONSTCOND*/0)
   83 #else
   84 #define PAX_DPRINTF(_fmt, args...)      do {} while (/*CONSTCOND*/0)
   85 #endif
   86 
   87 #ifdef PAX_ASLR
   88 #include <sys/mman.h>
   89 #include <sys/resourcevar.h>
   90 
   91 int pax_aslr_enabled = 1;
   92 int pax_aslr_global = PAX_ASLR;
   93 
   94 #ifndef PAX_ASLR_DELTA_MMAP_LSB
   95 #define PAX_ASLR_DELTA_MMAP_LSB         PGSHIFT
   96 #endif
   97 #ifndef PAX_ASLR_DELTA_MMAP_LEN
   98 #define PAX_ASLR_DELTA_MMAP_LEN         ((sizeof(void *) * NBBY) / 2)
   99 #endif
  100 #ifndef PAX_ASLR_DELTA_MMAP_LEN32
  101 #define PAX_ASLR_DELTA_MMAP_LEN32       ((sizeof(uint32_t) * NBBY) / 2)
  102 #endif
  103 #ifndef PAX_ASLR_DELTA_STACK_LSB
  104 #define PAX_ASLR_DELTA_STACK_LSB        PGSHIFT
  105 #endif
  106 #ifndef PAX_ASLR_DELTA_STACK_LEN
  107 #define PAX_ASLR_DELTA_STACK_LEN        ((sizeof(void *) * NBBY) / 4)
  108 #endif
  109 #ifndef PAX_ASLR_DELTA_STACK_LEN32
  110 #define PAX_ASLR_DELTA_STACK_LEN32      ((sizeof(uint32_t) * NBBY) / 4)
  111 #endif
  112 #define PAX_ASLR_MAX_STACK_WASTE        8
  113 
  114 #ifdef PAX_ASLR_DEBUG
  115 int pax_aslr_debug;
  116 /* flag set means disable */
  117 int pax_aslr_flags;
  118 uint32_t pax_aslr_rand;
  119 #define PAX_ASLR_STACK          0x01
  120 #define PAX_ASLR_STACK_GAP      0x02
  121 #define PAX_ASLR_MMAP           0x04
  122 #define PAX_ASLR_EXEC_OFFSET    0x08
  123 #define PAX_ASLR_RTLD_OFFSET    0x10
  124 #define PAX_ASLR_FIXED          0x20
  125 #endif
  126 
  127 static bool pax_aslr_elf_flags_active(uint32_t);
  128 #endif /* PAX_ASLR */
  129 
  130 #ifdef PAX_MPROTECT
  131 static int pax_mprotect_enabled = 1;
  132 static int pax_mprotect_global = PAX_MPROTECT;
  133 static int pax_mprotect_ptrace = 1;
  134 static bool pax_mprotect_elf_flags_active(uint32_t);
  135 #endif /* PAX_MPROTECT */
  136 #ifdef PAX_MPROTECT_DEBUG
  137 int pax_mprotect_debug;
  138 #endif
  139 
  140 #ifdef PAX_SEGVGUARD
  141 #ifndef PAX_SEGVGUARD_EXPIRY
  142 #define PAX_SEGVGUARD_EXPIRY            (2 * 60)
  143 #endif
  144 #ifndef PAX_SEGVGUARD_SUSPENSION
  145 #define PAX_SEGVGUARD_SUSPENSION        (10 * 60)
  146 #endif
  147 #ifndef PAX_SEGVGUARD_MAXCRASHES
  148 #define PAX_SEGVGUARD_MAXCRASHES        5
  149 #endif
  150 
  151 
  152 static int pax_segvguard_enabled = 1;
  153 static int pax_segvguard_global = PAX_SEGVGUARD;
  154 static int pax_segvguard_expiry = PAX_SEGVGUARD_EXPIRY;
  155 static int pax_segvguard_suspension = PAX_SEGVGUARD_SUSPENSION;
  156 static int pax_segvguard_maxcrashes = PAX_SEGVGUARD_MAXCRASHES;
  157 
  158 struct pax_segvguard_uid_entry {
  159         uid_t sue_uid;
  160         size_t sue_ncrashes;
  161         time_t sue_expiry;
  162         time_t sue_suspended;
  163         LIST_ENTRY(pax_segvguard_uid_entry) sue_list;
  164 };
  165 
  166 struct pax_segvguard_entry {
  167         LIST_HEAD(, pax_segvguard_uid_entry) segv_uids;
  168 };
  169 
  170 static bool pax_segvguard_elf_flags_active(uint32_t);
  171 #endif /* PAX_SEGVGUARD */
  172 
  173 SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
  174 {
  175         const struct sysctlnode *rnode = NULL, *cnode;
  176 
  177         sysctl_createv(clog, 0, NULL, &rnode,
  178                        CTLFLAG_PERMANENT,
  179                        CTLTYPE_NODE, "pax",
  180                        SYSCTL_DESCR("PaX (exploit mitigation) features."),
  181                        NULL, 0, NULL, 0,
  182                        CTL_SECURITY, CTL_CREATE, CTL_EOL);
  183 
  184         cnode = rnode;
  185 
  186 #ifdef PAX_MPROTECT
  187         rnode = cnode;
  188         sysctl_createv(clog, 0, &rnode, &rnode,
  189                        CTLFLAG_PERMANENT,
  190                        CTLTYPE_NODE, "mprotect",
  191                        SYSCTL_DESCR("mprotect(2) W^X restrictions."),
  192                        NULL, 0, NULL, 0,
  193                        CTL_CREATE, CTL_EOL);
  194         sysctl_createv(clog, 0, &rnode, NULL,
  195                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  196                        CTLTYPE_INT, "enabled",
  197                        SYSCTL_DESCR("Restrictions enabled."),
  198                        NULL, 0, &pax_mprotect_enabled, 0,
  199                        CTL_CREATE, CTL_EOL);
  200         sysctl_createv(clog, 0, &rnode, NULL,
  201                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  202                        CTLTYPE_INT, "global",
  203                        SYSCTL_DESCR("When enabled, unless explicitly "
  204                                     "specified, apply restrictions to "
  205                                     "all processes."),
  206                        NULL, 0, &pax_mprotect_global, 0,
  207                        CTL_CREATE, CTL_EOL);
  208         sysctl_createv(clog, 0, &rnode, NULL,
  209                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  210                        CTLTYPE_INT, "ptrace",
  211                        SYSCTL_DESCR("When enabled, allow ptrace(2) to "
  212                             "override mprotect permissions on traced "
  213                             "processes"),
  214                        NULL, 0, &pax_mprotect_ptrace, 0,
  215                        CTL_CREATE, CTL_EOL);
  216 #ifdef PAX_MPROTECT_DEBUG
  217         sysctl_createv(clog, 0, &rnode, NULL,
  218                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  219                        CTLTYPE_INT, "debug",
  220                        SYSCTL_DESCR("print mprotect changes."),
  221                        NULL, 0, &pax_mprotect_debug, 0,
  222                        CTL_CREATE, CTL_EOL);
  223 #endif
  224 #endif /* PAX_MPROTECT */
  225 
  226 #ifdef PAX_SEGVGUARD
  227         rnode = cnode;
  228         sysctl_createv(clog, 0, &rnode, &rnode,
  229                        CTLFLAG_PERMANENT,
  230                        CTLTYPE_NODE, "segvguard",
  231                        SYSCTL_DESCR("PaX segvguard."),
  232                        NULL, 0, NULL, 0,
  233                        CTL_CREATE, CTL_EOL);
  234         sysctl_createv(clog, 0, &rnode, NULL,
  235                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  236                        CTLTYPE_INT, "enabled",
  237                        SYSCTL_DESCR("segvguard enabled."),
  238                        NULL, 0, &pax_segvguard_enabled, 0,
  239                        CTL_CREATE, CTL_EOL);
  240         sysctl_createv(clog, 0, &rnode, NULL,
  241                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  242                        CTLTYPE_INT, "global",
  243                        SYSCTL_DESCR("segvguard all programs."),
  244                        NULL, 0, &pax_segvguard_global, 0,
  245                        CTL_CREATE, CTL_EOL);
  246         sysctl_createv(clog, 0, &rnode, NULL,
  247                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  248                        CTLTYPE_INT, "expiry_timeout",
  249                        SYSCTL_DESCR("Entry expiry timeout (in seconds)."),
  250                        NULL, 0, &pax_segvguard_expiry, 0,
  251                        CTL_CREATE, CTL_EOL);
  252         sysctl_createv(clog, 0, &rnode, NULL,
  253                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  254                        CTLTYPE_INT, "suspend_timeout",
  255                        SYSCTL_DESCR("Entry suspension timeout (in seconds)."),
  256                        NULL, 0, &pax_segvguard_suspension, 0,
  257                        CTL_CREATE, CTL_EOL);
  258         sysctl_createv(clog, 0, &rnode, NULL,
  259                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  260                        CTLTYPE_INT, "max_crashes",
  261                        SYSCTL_DESCR("Max number of crashes before expiry."),
  262                        NULL, 0, &pax_segvguard_maxcrashes, 0,
  263                        CTL_CREATE, CTL_EOL);
  264 #endif /* PAX_SEGVGUARD */
  265 
  266 #ifdef PAX_ASLR
  267         rnode = cnode;
  268         sysctl_createv(clog, 0, &rnode, &rnode,
  269                        CTLFLAG_PERMANENT,
  270                        CTLTYPE_NODE, "aslr",
  271                        SYSCTL_DESCR("Address Space Layout Randomization."),
  272                        NULL, 0, NULL, 0,
  273                        CTL_CREATE, CTL_EOL);
  274         sysctl_createv(clog, 0, &rnode, NULL,
  275                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  276                        CTLTYPE_INT, "enabled",
  277                        SYSCTL_DESCR("Restrictions enabled."),
  278                        NULL, 0, &pax_aslr_enabled, 0,
  279                        CTL_CREATE, CTL_EOL);
  280         sysctl_createv(clog, 0, &rnode, NULL,
  281                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  282                        CTLTYPE_INT, "global",
  283                        SYSCTL_DESCR("When enabled, unless explicitly "
  284                                     "specified, apply to all processes."),
  285                        NULL, 0, &pax_aslr_global, 0,
  286                        CTL_CREATE, CTL_EOL);
  287 #ifdef PAX_ASLR_DEBUG
  288         sysctl_createv(clog, 0, &rnode, NULL,
  289                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  290                        CTLTYPE_INT, "debug",
  291                        SYSCTL_DESCR("Print ASLR selected addresses."),
  292                        NULL, 0, &pax_aslr_debug, 0,
  293                        CTL_CREATE, CTL_EOL);
  294         sysctl_createv(clog, 0, &rnode, NULL,
  295                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  296                        CTLTYPE_INT, "flags",
  297                        SYSCTL_DESCR("Disable/Enable select ASLR features."),
  298                        NULL, 0, &pax_aslr_flags, 0,
  299                        CTL_CREATE, CTL_EOL);
  300         sysctl_createv(clog, 0, &rnode, NULL,
  301                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  302                        CTLTYPE_INT, "rand",
  303                        SYSCTL_DESCR("Use the given fixed random value"),
  304                        NULL, 0, &pax_aslr_rand, 0,
  305                        CTL_CREATE, CTL_EOL);
  306 #endif
  307         sysctl_createv(clog, 0, &rnode, NULL,
  308                        CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
  309                        CTLTYPE_INT, "mmap_len",
  310                        SYSCTL_DESCR("Number of bits randomized for "
  311                                     "mmap(2) calls."),
  312                        NULL, PAX_ASLR_DELTA_MMAP_LEN, NULL, 0,
  313                        CTL_CREATE, CTL_EOL);
  314         sysctl_createv(clog, 0, &rnode, NULL,
  315                        CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
  316                        CTLTYPE_INT, "stack_len",
  317                        SYSCTL_DESCR("Number of bits randomized for "
  318                                     "the stack."),
  319                        NULL, PAX_ASLR_DELTA_STACK_LEN, NULL, 0,
  320                        CTL_CREATE, CTL_EOL);
  321         sysctl_createv(clog, 0, &rnode, NULL,
  322                        CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
  323                        CTLTYPE_INT, "exec_len",
  324                        SYSCTL_DESCR("Number of bits randomized for "
  325                                     "the PIE exec base."),
  326                        NULL, PAX_ASLR_DELTA_EXEC_LEN, NULL, 0,
  327                        CTL_CREATE, CTL_EOL);
  328 
  329 #endif /* PAX_ASLR */
  330 }
  331 
  332 /*
  333  * Initialize PaX.
  334  */
  335 void
  336 pax_init(void)
  337 {
  338 #ifdef PAX_ASLR
  339         /* Adjust maximum stack by the size we can consume for ASLR */
  340         maxsmap = MAXSSIZ - (MAXSSIZ / PAX_ASLR_MAX_STACK_WASTE);
  341         // XXX: compat32 is not handled.
  342 #endif
  343 }
  344 
  345 void
  346 pax_set_flags(struct exec_package *epp, struct proc *p)
  347 {
  348         p->p_pax = epp->ep_pax_flags;
  349 
  350 #ifdef PAX_MPROTECT
  351         if (pax_mprotect_ptrace == 0)
  352                 return;
  353         /*
  354          * If we are running under the debugger, turn off MPROTECT so
  355          * the debugger can insert/delete breakpoints
  356          */
  357         if (p->p_slflag & PSL_TRACED)
  358                 p->p_pax &= ~P_PAX_MPROTECT;
  359 #endif
  360 }
  361 
  362 void
  363 pax_setup_elf_flags(struct exec_package *epp, uint32_t elf_flags)
  364 {
  365         uint32_t flags = 0;
  366 
  367 #ifdef PAX_ASLR
  368         if (pax_aslr_elf_flags_active(elf_flags)) {
  369                 flags |= P_PAX_ASLR;
  370         }
  371 #endif
  372 #ifdef PAX_MPROTECT
  373         if (pax_mprotect_elf_flags_active(elf_flags)) {
  374                 flags |= P_PAX_MPROTECT;
  375         }
  376 #endif
  377 #ifdef PAX_SEGVGUARD
  378         if (pax_segvguard_elf_flags_active(elf_flags)) {
  379                 flags |= P_PAX_GUARD;
  380         }
  381 #endif
  382 
  383         epp->ep_pax_flags = flags;
  384 }
  385 
  386 #if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
  387 static inline bool
  388 pax_flags_active(uint32_t flags, uint32_t opt)
  389 {
  390         if (!(flags & opt))
  391                 return false;
  392         return true;
  393 }
  394 #endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */
  395 
  396 #ifdef PAX_MPROTECT
  397 static bool
  398 pax_mprotect_elf_flags_active(uint32_t flags)
  399 {
  400         if (!pax_mprotect_enabled)
  401                 return false;
  402         if (pax_mprotect_global && (flags & ELF_NOTE_PAX_NOMPROTECT) != 0) {
  403                 /* Mprotect explicitly disabled */
  404                 return false;
  405         }
  406         if (!pax_mprotect_global && (flags & ELF_NOTE_PAX_MPROTECT) == 0) {
  407                 /* Mprotect not requested */
  408                 return false;
  409         }
  410         return true;
  411 }
  412 
  413 vm_prot_t
  414 pax_mprotect_maxprotect(
  415 #ifdef PAX_MPROTECT_DEBUG
  416     const char *file, size_t line,
  417 #endif
  418     struct lwp *l, vm_prot_t active, vm_prot_t extra, vm_prot_t maxprot)
  419 {
  420         uint32_t flags;
  421 
  422         flags = l->l_proc->p_pax;
  423         if (!pax_flags_active(flags, P_PAX_MPROTECT))
  424                 return maxprot;
  425 
  426         return (active|extra) & maxprot;
  427 }
  428 
  429 int
  430 pax_mprotect_validate(
  431 #ifdef PAX_MPROTECT_DEBUG
  432     const char *file, size_t line,
  433 #endif
  434     struct lwp *l, vm_prot_t prot)
  435 {
  436         uint32_t flags;
  437 
  438         flags = l->l_proc->p_pax;
  439         if (!pax_flags_active(flags, P_PAX_MPROTECT))
  440                 return 0;
  441 
  442         if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
  443             (VM_PROT_WRITE|VM_PROT_EXECUTE)) {
  444 #ifdef PAX_MPROTECT_DEBUG
  445                 struct proc *p = l->l_proc;
  446 
  447                 if (pax_mprotect_debug)
  448                         printf("%s: %s,%zu: %d.%d (%s): WX rejected\n",
  449                             __func__, file, line,
  450                             p->p_pid, l->l_lid, p->p_comm);
  451 #endif
  452                 return EACCES;
  453         }
  454         return 0;
  455 }
  456 
  457 /*
  458  * Bypass MPROTECT for traced processes
  459  */
  460 int
  461 pax_mprotect_prot(struct lwp *l)
  462 {
  463         uint32_t flags;
  464 
  465         flags = l->l_proc->p_pax;
  466         if (!pax_flags_active(flags, P_PAX_MPROTECT))
  467                 return 0;
  468         if (pax_mprotect_ptrace < 2)
  469                 return 0;
  470         return UVM_EXTRACT_PROT_ALL;
  471 }
  472 
  473 
  474 #endif /* PAX_MPROTECT */
  475 
  476 #ifdef PAX_ASLR
  477 static bool
  478 pax_aslr_elf_flags_active(uint32_t flags)
  479 {
  480         if (!pax_aslr_enabled)
  481                 return false;
  482         if (pax_aslr_global && (flags & ELF_NOTE_PAX_NOASLR) != 0) {
  483                 /* ASLR explicitly disabled */
  484                 return false;
  485         }
  486         if (!pax_aslr_global && (flags & ELF_NOTE_PAX_ASLR) == 0) {
  487                 /* ASLR not requested */
  488                 return false;
  489         }
  490         return true;
  491 }
  492 
  493 static bool
  494 pax_aslr_epp_active(struct exec_package *epp)
  495 {
  496         if (__predict_false((epp->ep_flags & (EXEC_32|EXEC_TOPDOWN_VM)) == 0))
  497                 return false;
  498         return pax_flags_active(epp->ep_pax_flags, P_PAX_ASLR);
  499 }
  500 
  501 static bool
  502 pax_aslr_active(struct lwp *l)
  503 {
  504         return pax_flags_active(l->l_proc->p_pax, P_PAX_ASLR);
  505 }
  506 
  507 void
  508 pax_aslr_init_vm(struct lwp *l, struct vmspace *vm, struct exec_package *ep)
  509 {
  510         if (!pax_aslr_active(l))
  511                 return;
  512 
  513         if (__predict_false((ep->ep_flags & (EXEC_32|EXEC_TOPDOWN_VM)) == 0))
  514                 return;
  515 
  516 #ifdef PAX_ASLR_DEBUG
  517         if (pax_aslr_flags & PAX_ASLR_MMAP)
  518                 return;
  519 #endif
  520 
  521         uint32_t len = (ep->ep_flags & EXEC_32) ?
  522             PAX_ASLR_DELTA_MMAP_LEN32 : PAX_ASLR_DELTA_MMAP_LEN;
  523 
  524         uint32_t rand = cprng_fast32();
  525 #ifdef PAX_ASLR_DEBUG
  526         if (pax_aslr_flags & PAX_ASLR_FIXED)
  527                 rand = pax_aslr_rand;
  528 #endif
  529         vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand,
  530             PAX_ASLR_DELTA_MMAP_LSB, len);
  531 
  532         PAX_DPRINTF("delta_mmap=%#jx/%u",
  533             (uintmax_t)vm->vm_aslr_delta_mmap, len);
  534 }
  535 
  536 void
  537 pax_aslr_mmap(struct lwp *l, vaddr_t *addr, vaddr_t orig_addr, int f)
  538 {
  539         if (!pax_aslr_active(l))
  540                 return;
  541 #ifdef PAX_ASLR_DEBUG
  542         char buf[256];
  543 
  544         if (pax_aslr_flags & PAX_ASLR_MMAP)
  545                 return;
  546 
  547         if (pax_aslr_debug)
  548                 snprintb(buf, sizeof(buf), MAP_FMT, f);
  549         else
  550                 buf[0] = '\0';
  551 #endif
  552 
  553         if (!(f & MAP_FIXED) && ((orig_addr == 0) || !(f & MAP_ANON))) {
  554                 PAX_DPRINTF("applying to %#jx orig_addr=%#jx f=%s",
  555                     (uintmax_t)*addr, (uintmax_t)orig_addr, buf);
  556                 if (!(l->l_proc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN))
  557                         *addr += l->l_proc->p_vmspace->vm_aslr_delta_mmap;
  558                 else
  559                         *addr -= l->l_proc->p_vmspace->vm_aslr_delta_mmap;
  560                 PAX_DPRINTF("result %#jx", (uintmax_t)*addr);
  561         } else {
  562                 PAX_DPRINTF("not applying to %#jx orig_addr=%#jx f=%s",
  563                     (uintmax_t)*addr, (uintmax_t)orig_addr, buf);
  564         }
  565 }
  566 
  567 static vaddr_t
  568 pax_aslr_offset(vaddr_t align)
  569 {
  570         size_t pax_align, l2, delta;
  571         uint32_t rand;
  572         vaddr_t offset;
  573 
  574         pax_align = align == 0 ? PAGE_SIZE : align;
  575         l2 = ilog2(pax_align);
  576 
  577         rand = cprng_fast32();
  578 #ifdef PAX_ASLR_DEBUG
  579         if (pax_aslr_flags & PAX_ASLR_FIXED)
  580                 rand = pax_aslr_rand;
  581 #endif
  582 
  583 #define PAX_TRUNC(a, b) ((a) & ~((b) - 1))
  584 
  585         delta = PAX_ASLR_DELTA(rand, l2, PAX_ASLR_DELTA_EXEC_LEN);
  586         offset = PAX_TRUNC(delta, pax_align);
  587         offset = MAX(offset, pax_align);
  588 
  589         PAX_DPRINTF("rand=%#x l2=%#zx pax_align=%#zx delta=%#zx offset=%#jx",
  590             rand, l2, pax_align, delta, (uintmax_t)offset);
  591 
  592         return offset;
  593 }
  594 
  595 vaddr_t
  596 pax_aslr_exec_offset(struct exec_package *epp, vaddr_t align)
  597 {
  598         if (!pax_aslr_epp_active(epp))
  599                 goto out;
  600 
  601 #ifdef PAX_ASLR_DEBUG
  602         if (pax_aslr_flags & PAX_ASLR_EXEC_OFFSET)
  603                 goto out;
  604 #endif
  605         return pax_aslr_offset(align);
  606 out:
  607         return MAX(align, PAGE_SIZE);
  608 }
  609 
  610 voff_t
  611 pax_aslr_rtld_offset(struct exec_package *epp, vaddr_t align, int use_topdown)
  612 {
  613         voff_t offset;
  614 
  615         if (!pax_aslr_epp_active(epp))
  616                 return 0;
  617 
  618 #ifdef PAX_ASLR_DEBUG
  619         if (pax_aslr_flags & PAX_ASLR_RTLD_OFFSET)
  620                 return 0;
  621 #endif
  622         offset = pax_aslr_offset(align);
  623         if (use_topdown)
  624                 offset = -offset;
  625 
  626         return offset;
  627 }
  628 
  629 void
  630 pax_aslr_stack(struct exec_package *epp, vsize_t *max_stack_size)
  631 {
  632         if (!pax_aslr_epp_active(epp))
  633                 return;
  634 #ifdef PAX_ASLR_DEBUG
  635         if (pax_aslr_flags & PAX_ASLR_STACK)
  636                 return;
  637 #endif
  638 
  639         uint32_t len = (epp->ep_flags & EXEC_32) ?
  640             PAX_ASLR_DELTA_STACK_LEN32 : PAX_ASLR_DELTA_STACK_LEN;
  641         uint32_t rand = cprng_fast32();
  642 #ifdef PAX_ASLR_DEBUG
  643         if (pax_aslr_flags & PAX_ASLR_FIXED)
  644                 rand = pax_aslr_rand;
  645 #endif
  646         u_long d = PAX_ASLR_DELTA(rand, PAX_ASLR_DELTA_STACK_LSB, len);
  647         d &= (*max_stack_size / PAX_ASLR_MAX_STACK_WASTE) - 1;
  648         u_long newminsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, d);
  649         PAX_DPRINTF("old minsaddr=%#jx delta=%#lx new minsaddr=%#lx",
  650             (uintmax_t)epp->ep_minsaddr, d, newminsaddr);
  651         epp->ep_minsaddr = (vaddr_t)newminsaddr;
  652         *max_stack_size -= d;
  653 }
  654 
  655 uint32_t
  656 pax_aslr_stack_gap(struct exec_package *epp)
  657 {
  658         if (!pax_aslr_epp_active(epp))
  659                 return 0;
  660 
  661 #ifdef PAX_ASLR_DEBUG
  662         if (pax_aslr_flags & PAX_ASLR_STACK_GAP)
  663                 return 0;
  664 #endif
  665 
  666         uint32_t rand = cprng_fast32();
  667 #ifdef PAX_ASLR_DEBUG
  668         if (pax_aslr_flags & PAX_ASLR_FIXED)
  669                 rand = pax_aslr_rand;
  670 #endif
  671         rand %= PAGE_SIZE;
  672         PAX_DPRINTF("stack gap=%#x\n", rand);
  673         return rand;
  674 }
  675 #endif /* PAX_ASLR */
  676 
  677 #ifdef PAX_SEGVGUARD
  678 static bool
  679 pax_segvguard_elf_flags_active(uint32_t flags)
  680 {
  681         if (!pax_segvguard_enabled)
  682                 return false;
  683         if (pax_segvguard_global && (flags & ELF_NOTE_PAX_NOGUARD) != 0) {
  684                 /* Segvguard explicitly disabled */
  685                 return false;
  686         }
  687         if (!pax_segvguard_global && (flags & ELF_NOTE_PAX_GUARD) == 0) {
  688                 /* Segvguard not requested */
  689                 return false;
  690         }
  691         return true;
  692 }
  693 
  694 void
  695 pax_segvguard_cleanup(struct vnode *vp)
  696 {
  697         struct pax_segvguard_entry *p = vp->v_segvguard;
  698         struct pax_segvguard_uid_entry *up;
  699 
  700         if (__predict_true(p == NULL)) {
  701                 return;
  702         }
  703         while ((up = LIST_FIRST(&p->segv_uids)) != NULL) {
  704                 LIST_REMOVE(up, sue_list);
  705                 kmem_free(up, sizeof(*up));
  706         }
  707         kmem_free(p, sizeof(*p));
  708         vp->v_segvguard = NULL;
  709 }
  710 
  711 /*
  712  * Called when a process of image vp generated a segfault.
  713  *
  714  * => exec_lock must be held by the caller
  715  * => if "crashed" is true, exec_lock must be held for write
  716  */
  717 int
  718 pax_segvguard(struct lwp *l, struct vnode *vp, const char *name, bool crashed)
  719 {
  720         struct pax_segvguard_entry *p;
  721         struct pax_segvguard_uid_entry *up;
  722         struct timeval tv;
  723         uid_t uid;
  724         uint32_t flags;
  725         bool have_uid;
  726 
  727         KASSERT(rw_lock_held(&exec_lock));
  728         KASSERT(!crashed || rw_write_held(&exec_lock));
  729 
  730         flags = l->l_proc->p_pax;
  731         if (!pax_flags_active(flags, P_PAX_GUARD))
  732                 return 0;
  733 
  734         if (vp == NULL)
  735                 return EFAULT;  
  736 
  737         /* Fast-path if starting a program we don't know. */
  738         if ((p = vp->v_segvguard) == NULL && !crashed)
  739                 return 0;
  740 
  741         microtime(&tv);
  742 
  743         /*
  744          * If a program we don't know crashed, we need to create a new entry
  745          * for it.
  746          */
  747         if (p == NULL) {
  748                 p = kmem_alloc(sizeof(*p), KM_SLEEP);
  749                 vp->v_segvguard = p;
  750                 LIST_INIT(&p->segv_uids);
  751 
  752                 /*
  753                  * Initialize a new entry with "crashes so far" of 1.
  754                  * The expiry time is when we purge the entry if it didn't
  755                  * reach the limit.
  756                  */
  757                 up = kmem_alloc(sizeof(*up), KM_SLEEP);
  758                 up->sue_uid = kauth_cred_getuid(l->l_cred);
  759                 up->sue_ncrashes = 1;
  760                 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
  761                 up->sue_suspended = 0;
  762                 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list);
  763                 return 0;
  764         }
  765 
  766         /*
  767          * A program we "know" either executed or crashed again.
  768          * See if it's a culprit we're familiar with.
  769          */
  770         uid = kauth_cred_getuid(l->l_cred);
  771         have_uid = false;
  772         LIST_FOREACH(up, &p->segv_uids, sue_list) {
  773                 if (up->sue_uid == uid) {
  774                         have_uid = true;
  775                         break;
  776                 }
  777         }
  778 
  779         /*
  780          * It's someone else. Add an entry for him if we crashed.
  781          */
  782         if (!have_uid) {
  783                 if (crashed) {
  784                         up = kmem_alloc(sizeof(*up), KM_SLEEP);
  785                         up->sue_uid = uid;
  786                         up->sue_ncrashes = 1;
  787                         up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
  788                         up->sue_suspended = 0;
  789                         LIST_INSERT_HEAD(&p->segv_uids, up, sue_list);
  790                 }
  791                 return 0;
  792         }
  793 
  794         if (crashed) {
  795                 /* Check if timer on previous crashes expired first. */
  796                 if (up->sue_expiry < tv.tv_sec) {
  797                         log(LOG_INFO, "PaX Segvguard: [%s] Suspension"
  798                             " expired.\n", name ? name : "unknown");
  799                         up->sue_ncrashes = 1;
  800                         up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
  801                         up->sue_suspended = 0;
  802                         return 0;
  803                 }
  804 
  805                 up->sue_ncrashes++;
  806 
  807                 if (up->sue_ncrashes >= pax_segvguard_maxcrashes) {
  808                         log(LOG_ALERT, "PaX Segvguard: [%s] Suspending "
  809                             "execution for %d seconds after %zu crashes.\n",
  810                             name ? name : "unknown", pax_segvguard_suspension,
  811                             up->sue_ncrashes);
  812 
  813                         /* Suspend this program for a while. */
  814                         up->sue_suspended = tv.tv_sec + pax_segvguard_suspension;
  815                         up->sue_ncrashes = 0;
  816                         up->sue_expiry = 0;
  817                 }
  818         } else {
  819                 /* Are we supposed to be suspended? */
  820                 if (up->sue_suspended > tv.tv_sec) {
  821                         log(LOG_ALERT, "PaX Segvguard: [%s] Preventing "
  822                             "execution due to repeated segfaults.\n", name ?
  823                             name : "unknown");
  824                         return EPERM;
  825                 }
  826         }
  827 
  828         return 0;
  829 }
  830 #endif /* PAX_SEGVGUARD */

Cache object: e95f2d3822825a7bc7bcfbd8acca09f8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.