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
secflag_to_bit(secflag_t secflag)28 secflag_to_bit(secflag_t secflag)
29 {
30 return (1 << secflag);
31 }
32
33 boolean_t
secflag_isset(secflagset_t flags,secflag_t sf)34 secflag_isset(secflagset_t flags, secflag_t sf)
35 {
36 return ((flags & secflag_to_bit(sf)) != 0);
37 }
38
39 void
secflag_clear(secflagset_t * flags,secflag_t sf)40 secflag_clear(secflagset_t *flags, secflag_t sf)
41 {
42 *flags &= ~secflag_to_bit(sf);
43 }
44
45 void
secflag_set(secflagset_t * flags,secflag_t sf)46 secflag_set(secflagset_t *flags, secflag_t sf)
47 {
48 *flags |= secflag_to_bit(sf);
49 }
50
51 boolean_t
secflags_isempty(secflagset_t flags)52 secflags_isempty(secflagset_t flags)
53 {
54 return (flags == 0);
55 }
56
57 void
secflags_zero(secflagset_t * flags)58 secflags_zero(secflagset_t *flags)
59 {
60 *flags = 0;
61 }
62
63 void
secflags_fullset(secflagset_t * flags)64 secflags_fullset(secflagset_t *flags)
65 {
66 *flags = PROC_SEC_MASK;
67 }
68
69 void
secflags_copy(secflagset_t * dst,const secflagset_t * src)70 secflags_copy(secflagset_t *dst, const secflagset_t *src)
71 {
72 *dst = *src;
73 }
74
75 boolean_t
secflags_issubset(secflagset_t a,secflagset_t b)76 secflags_issubset(secflagset_t a, secflagset_t b)
77 {
78 return (!(a & ~b));
79 }
80
81 boolean_t
secflags_issuperset(secflagset_t a,secflagset_t b)82 secflags_issuperset(secflagset_t a, secflagset_t b)
83 {
84 return (secflags_issubset(b, a));
85 }
86
87 boolean_t
secflags_intersection(secflagset_t a,secflagset_t b)88 secflags_intersection(secflagset_t a, secflagset_t b)
89 {
90 return (a & b);
91 }
92
93 void
secflags_union(secflagset_t * a,const secflagset_t * b)94 secflags_union(secflagset_t *a, const secflagset_t *b)
95 {
96 *a |= *b;
97 }
98
99 void
secflags_difference(secflagset_t * a,const secflagset_t * b)100 secflags_difference(secflagset_t *a, const secflagset_t *b)
101 {
102 *a &= ~*b;
103 }
104
105 boolean_t
psecflags_validate_delta(const psecflags_t * sf,const secflagdelta_t * delta)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
psecflags_validate(const psecflags_t * sf)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
psecflags_default(psecflags_t * sf)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
secflag_by_name(const char * str,secflag_t * ret)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 *
secflag_to_str(secflag_t sf)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
secflags_to_str(secflagset_t flags,char * buf,size_t buflen)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 }
242