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[19]; /* 0x%16 PRIx64 */ 235 236 (void) snprintf(hexbuf, sizeof (hexbuf), "0x%16" PRIx64, flags); 237 if (buf[0] != '\0') 238 (void) strlcat(buf, ",", buflen); 239 (void) strlcat(buf, hexbuf, buflen); 240 } 241 }