1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /* Copyright 2015, Richard Lowe. */
  13 
  14 #include <sys/secflags.h>
  15 #include <sys/types.h>
  16 
  17 #if defined(_KERNEL)
  18 #include <sys/kmem.h>
  19 #include <sys/sunddi.h>
  20 #else
  21 #include "lint.h"               /* libc header */
  22 #include <stdio.h>
  23 #include <stdlib.h>
  24 #include <strings.h>
  25 #endif
  26 
  27 secflagset_t
  28 secflag_to_bit(secflag_t secflag)
  29 {
  30         return (1 << secflag);
  31 }
  32 
  33 boolean_t
  34 secflag_isset(secflagset_t flags, secflag_t sf)
  35 {
  36         return ((flags & secflag_to_bit(sf)) != 0);
  37 }
  38 
  39 void
  40 secflag_clear(secflagset_t *flags, secflag_t sf)
  41 {
  42         *flags &= ~secflag_to_bit(sf);
  43 }
  44 
  45 void
  46 secflag_set(secflagset_t *flags, secflag_t sf)
  47 {
  48         *flags |= secflag_to_bit(sf);
  49 }
  50 
  51 boolean_t
  52 secflags_isempty(secflagset_t flags)
  53 {
  54         return (flags == 0);
  55 }
  56 
  57 void
  58 secflags_zero(secflagset_t *flags)
  59 {
  60         *flags = 0;
  61 }
  62 
  63 void
  64 secflags_fullset(secflagset_t *flags)
  65 {
  66         *flags = PROC_SEC_MASK;
  67 }
  68 
  69 void
  70 secflags_copy(secflagset_t *dst, const secflagset_t *src)
  71 {
  72         *dst = *src;
  73 }
  74 
  75 boolean_t
  76 secflags_issubset(secflagset_t a, secflagset_t b)
  77 {
  78         return (!(a & ~b));
  79 }
  80 
  81 boolean_t
  82 secflags_issuperset(secflagset_t a, secflagset_t b)
  83 {
  84         return (secflags_issubset(b, a));
  85 }
  86 
  87 boolean_t
  88 secflags_intersection(secflagset_t a, secflagset_t b)
  89 {
  90         return (a & b);
  91 }
  92 
  93 void
  94 secflags_union(secflagset_t *a, const secflagset_t *b)
  95 {
  96         *a |= *b;
  97 }
  98 
  99 void
 100 secflags_difference(secflagset_t *a, const secflagset_t *b)
 101 {
 102         *a &= ~*b;
 103 }
 104 
 105 boolean_t
 106 psecflags_validate_delta(const psecflags_t *sf, const secflagdelta_t *delta)
 107 {
 108         if (delta->psd_ass_active) {
 109                 /*
 110                  * If there's a bit in lower not in args, or a bit args not in
 111                  * upper
 112                  */
 113                 if (!secflags_issubset(delta->psd_assign, sf->psf_upper) ||
 114                     !secflags_issuperset(delta->psd_assign, sf->psf_lower)) {
 115                         return (B_FALSE);
 116                 }
 117 
 118                 if (!secflags_issubset(delta->psd_assign, PROC_SEC_MASK))
 119                         return (B_FALSE);
 120         } else {
 121                 /* If we're adding a bit not in upper */
 122                 if (!secflags_isempty(delta->psd_add)) {
 123                         if (!secflags_issubset(delta->psd_add, sf->psf_upper)) {
 124                                 return (B_FALSE);
 125                         }
 126                 }
 127 
 128                 /* If we're removing a bit that's in lower */
 129                 if (!secflags_isempty(delta->psd_rem)) {
 130                         if (secflags_intersection(delta->psd_rem,
 131                             sf->psf_lower)) {
 132                                 return (B_FALSE);
 133                         }
 134                 }
 135 
 136                 if (!secflags_issubset(delta->psd_add, PROC_SEC_MASK) ||
 137                     !secflags_issubset(delta->psd_rem, PROC_SEC_MASK))
 138                         return (B_FALSE);
 139         }
 140 
 141         return (B_TRUE);
 142 }
 143 
 144 boolean_t
 145 psecflags_validate(const psecflags_t *sf)
 146 {
 147         if (!secflags_issubset(sf->psf_lower, PROC_SEC_MASK) ||
 148             !secflags_issubset(sf->psf_inherit, PROC_SEC_MASK) ||
 149             !secflags_issubset(sf->psf_effective, PROC_SEC_MASK) ||
 150             !secflags_issubset(sf->psf_upper, PROC_SEC_MASK))
 151                 return (B_FALSE);
 152 
 153         if (!secflags_issubset(sf->psf_lower, sf->psf_inherit))
 154                 return (B_FALSE);
 155         if (!secflags_issubset(sf->psf_lower, sf->psf_upper))
 156                 return (B_FALSE);
 157         if (!secflags_issubset(sf->psf_inherit, sf->psf_upper))
 158                 return (B_FALSE);
 159 
 160         return (B_TRUE);
 161 }
 162 
 163 void
 164 psecflags_default(psecflags_t *sf)
 165 {
 166         secflags_zero(&sf->psf_effective);
 167         secflags_zero(&sf->psf_inherit);
 168         secflags_zero(&sf->psf_lower);
 169         secflags_fullset(&sf->psf_upper);
 170 }
 171 
 172 static struct flagdesc {
 173         secflag_t value;
 174         const char *name;
 175 } flagdescs[] = {
 176         { PROC_SEC_ASLR,                "aslr" },
 177         { PROC_SEC_FORBIDNULLMAP,       "forbidnullmap" },
 178         { PROC_SEC_NOEXECSTACK,         "noexecstack" },
 179         { 0x0, NULL }
 180 };
 181 
 182 boolean_t
 183 secflag_by_name(const char *str, secflag_t *ret)
 184 {
 185         struct flagdesc *fd;
 186 
 187         for (fd = flagdescs; fd->name != NULL; fd++) {
 188                 if (strcasecmp(str, fd->name) == 0) {
 189                         *ret = fd->value;
 190                         return (B_TRUE);
 191                 }
 192         }
 193 
 194         return (B_FALSE);
 195 }
 196 
 197 const char *
 198 secflag_to_str(secflag_t sf)
 199 {
 200         struct flagdesc *fd;
 201 
 202         for (fd = flagdescs; fd->name != NULL; fd++) {
 203                 if (sf == fd->value)
 204                         return (fd->name);
 205         }
 206 
 207         return (NULL);
 208 }
 209 
 210 void
 211 secflags_to_str(secflagset_t flags, char *buf, size_t buflen)
 212 {
 213         struct flagdesc *fd;
 214 
 215         if (buflen >= 1)
 216                 buf[0] = '\0';
 217 
 218         if (flags == 0) {
 219                 (void) strlcpy(buf, "none", buflen);
 220                 return;
 221         }
 222 
 223         for (fd = flagdescs; fd->name != NULL; fd++) {
 224                 if (secflag_isset(flags, fd->value)) {
 225                         if (buf[0] != '\0')
 226                                 (void) strlcat(buf, ", ", buflen);
 227                         (void) strlcat(buf, fd->name, buflen);
 228                 }
 229 
 230                 secflag_clear(&flags, fd->value);
 231         }
 232 
 233         if (flags != 0) {       /* unknown flags */
 234                 char hexbuf[11]; /* 0x%08x */
 235 
 236                 (void) snprintf(hexbuf, sizeof (hexbuf), "0x%08x", flags);
 237                 if (buf[0] != '\0')
 238                         (void) strlcat(buf, ", ", buflen);
 239                 (void) strlcat(buf, hexbuf, buflen);
 240         }
 241 }