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