1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 
5 #include <sepol/policydb/policydb.h>
6 #include <sepol/policydb/services.h>
7 #include "context_internal.h"
8 
9 #include "debug.h"
10 #include "context.h"
11 #include "handle.h"
12 #include "mls.h"
13 #include "private.h"
14 
15 /* ----- Compatibility ---- */
policydb_context_isvalid(const policydb_t * p,const context_struct_t * c)16 int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c)
17 {
18 
19 	return context_is_valid(p, c);
20 }
21 
sepol_check_context(const char * context)22 int sepol_check_context(const char *context)
23 {
24 
25 	return sepol_context_to_sid((const sepol_security_context_t)context,
26 				    strlen(context) + 1, NULL);
27 }
28 
29 /* ---- End compatibility --- */
30 
31 /*
32  * Return 1 if the fields in the security context
33  * structure `c' are valid.  Return 0 otherwise.
34  */
context_is_valid(const policydb_t * p,const context_struct_t * c)35 int context_is_valid(const policydb_t * p, const context_struct_t * c)
36 {
37 
38 	role_datum_t *role;
39 	user_datum_t *usrdatum;
40 	ebitmap_t types, roles;
41 
42 	ebitmap_init(&types);
43 	ebitmap_init(&roles);
44 	if (!c->role || c->role > p->p_roles.nprim)
45 		return 0;
46 
47 	if (!c->user || c->user > p->p_users.nprim)
48 		return 0;
49 
50 	if (!c->type || c->type > p->p_types.nprim)
51 		return 0;
52 
53 	if (c->role != OBJECT_R_VAL) {
54 		/*
55 		 * Role must be authorized for the type.
56 		 */
57 		role = p->role_val_to_struct[c->role - 1];
58 		if (!role || !ebitmap_get_bit(&role->cache, c->type - 1))
59 			/* role may not be associated with type */
60 			return 0;
61 
62 		/*
63 		 * User must be authorized for the role.
64 		 */
65 		usrdatum = p->user_val_to_struct[c->user - 1];
66 		if (!usrdatum)
67 			return 0;
68 
69 		if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1))
70 			/* user may not be associated with role */
71 			return 0;
72 	}
73 
74 	if (!mls_context_isvalid(p, c))
75 		return 0;
76 
77 	return 1;
78 }
79 
80 /*
81  * Write the security context string representation of
82  * the context structure `context' into a dynamically
83  * allocated string of the correct size.  Set `*scontext'
84  * to point to this string and set `*scontext_len' to
85  * the length of the string.
86  */
context_to_string(sepol_handle_t * handle,const policydb_t * policydb,const context_struct_t * context,char ** result,size_t * result_len)87 int context_to_string(sepol_handle_t * handle,
88 		      const policydb_t * policydb,
89 		      const context_struct_t * context,
90 		      char **result, size_t * result_len)
91 {
92 
93 	char *scontext = NULL;
94 	size_t scontext_len = 0;
95 	char *ptr;
96 
97 	/* Compute the size of the context. */
98 	scontext_len +=
99 	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1;
100 	scontext_len +=
101 	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1;
102 	scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]);
103 	scontext_len += mls_compute_context_len(policydb, context);
104 
105 	/* We must null terminate the string */
106 	scontext_len += 1;
107 
108 	/* Allocate space for the context; caller must free this space. */
109 	scontext = malloc(scontext_len);
110 	if (!scontext)
111 		goto omem;
112 	scontext[scontext_len - 1] = '\0';
113 
114 	/*
115 	 * Copy the user name, role name and type name into the context.
116 	 */
117 	ptr = scontext;
118 	sprintf(ptr, "%s:%s:%s",
119 		policydb->p_user_val_to_name[context->user - 1],
120 		policydb->p_role_val_to_name[context->role - 1],
121 		policydb->p_type_val_to_name[context->type - 1]);
122 
123 	ptr +=
124 	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 +
125 	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 +
126 	    strlen(policydb->p_type_val_to_name[context->type - 1]);
127 
128 	mls_sid_to_context(policydb, context, &ptr);
129 
130 	*result = scontext;
131 	*result_len = scontext_len;
132 	return STATUS_SUCCESS;
133 
134       omem:
135 	ERR(handle, "out of memory, could not convert " "context to string");
136 	free(scontext);
137 	return STATUS_ERR;
138 }
139 
140 /*
141  * Create a context structure from the given record
142  */
context_from_record(sepol_handle_t * handle,const policydb_t * policydb,context_struct_t ** cptr,const sepol_context_t * record)143 int context_from_record(sepol_handle_t * handle,
144 			const policydb_t * policydb,
145 			context_struct_t ** cptr,
146 			const sepol_context_t * record)
147 {
148 
149 	context_struct_t *scontext = NULL;
150 	user_datum_t *usrdatum;
151 	role_datum_t *roldatum;
152 	type_datum_t *typdatum;
153 
154 	/* Hashtab keys are not constant - suppress warnings */
155 	char *user = strdup(sepol_context_get_user(record));
156 	char *role = strdup(sepol_context_get_role(record));
157 	char *type = strdup(sepol_context_get_type(record));
158 	const char *mls = sepol_context_get_mls(record);
159 
160 	scontext = (context_struct_t *) malloc(sizeof(context_struct_t));
161 	if (!user || !role || !type || !scontext) {
162 		ERR(handle, "out of memory");
163 		goto err;
164 	}
165 	context_init(scontext);
166 
167 	/* User */
168 	usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table,
169 						   (hashtab_key_t) user);
170 	if (!usrdatum) {
171 		ERR(handle, "user %s is not defined", user);
172 		goto err_destroy;
173 	}
174 	scontext->user = usrdatum->s.value;
175 
176 	/* Role */
177 	roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table,
178 						   (hashtab_key_t) role);
179 	if (!roldatum) {
180 		ERR(handle, "role %s is not defined", role);
181 		goto err_destroy;
182 	}
183 	scontext->role = roldatum->s.value;
184 
185 	/* Type */
186 	typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table,
187 						   (hashtab_key_t) type);
188 	if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
189 		ERR(handle, "type %s is not defined", type);
190 		goto err_destroy;
191 	}
192 	scontext->type = typdatum->s.value;
193 
194 	/* MLS */
195 	if (mls && !policydb->mls) {
196 		ERR(handle, "MLS is disabled, but MLS context \"%s\" found",
197 		    mls);
198 		goto err_destroy;
199 	} else if (!mls && policydb->mls) {
200 		ERR(handle, "MLS is enabled, but no MLS context found");
201 		goto err_destroy;
202 	}
203 	if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0))
204 		goto err_destroy;
205 
206 	/* Validity check */
207 	if (!context_is_valid(policydb, scontext)) {
208 		if (mls) {
209 			ERR(handle,
210 			    "invalid security context: \"%s:%s:%s:%s\"",
211 			    user, role, type, mls);
212 		} else {
213 			ERR(handle,
214 			    "invalid security context: \"%s:%s:%s\"",
215 			    user, role, type);
216 		}
217 		goto err_destroy;
218 	}
219 
220 	*cptr = scontext;
221 	free(user);
222 	free(type);
223 	free(role);
224 	return STATUS_SUCCESS;
225 
226       err_destroy:
227 	errno = EINVAL;
228 	context_destroy(scontext);
229 
230       err:
231 	free(scontext);
232 	free(user);
233 	free(type);
234 	free(role);
235 	ERR(handle, "could not create context structure");
236 	return STATUS_ERR;
237 }
238 
239 /*
240  * Create a record from the given context structure
241  */
context_to_record(sepol_handle_t * handle,const policydb_t * policydb,const context_struct_t * context,sepol_context_t ** record)242 int context_to_record(sepol_handle_t * handle,
243 		      const policydb_t * policydb,
244 		      const context_struct_t * context,
245 		      sepol_context_t ** record)
246 {
247 
248 	sepol_context_t *tmp_record = NULL;
249 	char *mls = NULL;
250 
251 	if (sepol_context_create(handle, &tmp_record) < 0)
252 		goto err;
253 
254 	if (sepol_context_set_user(handle, tmp_record,
255 				   policydb->p_user_val_to_name[context->user -
256 								1]) < 0)
257 		goto err;
258 
259 	if (sepol_context_set_role(handle, tmp_record,
260 				   policydb->p_role_val_to_name[context->role -
261 								1]) < 0)
262 		goto err;
263 
264 	if (sepol_context_set_type(handle, tmp_record,
265 				   policydb->p_type_val_to_name[context->type -
266 								1]) < 0)
267 		goto err;
268 
269 	if (policydb->mls) {
270 		if (mls_to_string(handle, policydb, context, &mls) < 0)
271 			goto err;
272 
273 		if (sepol_context_set_mls(handle, tmp_record, mls) < 0)
274 			goto err;
275 	}
276 
277 	free(mls);
278 	*record = tmp_record;
279 	return STATUS_SUCCESS;
280 
281       err:
282 	ERR(handle, "could not create context record");
283 	sepol_context_free(tmp_record);
284 	free(mls);
285 	return STATUS_ERR;
286 }
287 
288 /*
289  * Create a context structure from the provided string.
290  */
context_from_string(sepol_handle_t * handle,const policydb_t * policydb,context_struct_t ** cptr,const char * con_str,size_t con_str_len)291 int context_from_string(sepol_handle_t * handle,
292 			const policydb_t * policydb,
293 			context_struct_t ** cptr,
294 			const char *con_str, size_t con_str_len)
295 {
296 
297 	char *con_cpy = NULL;
298 	sepol_context_t *ctx_record = NULL;
299 
300 	if (zero_or_saturated(con_str_len)) {
301 		ERR(handle, "Invalid context length");
302 		goto err;
303 	}
304 
305 	/* sepol_context_from_string expects a NULL-terminated string */
306 	con_cpy = malloc(con_str_len + 1);
307 	if (!con_cpy) {
308 		ERR(handle, "out of memory");
309 		goto err;
310 	}
311 
312 	memcpy(con_cpy, con_str, con_str_len);
313 	con_cpy[con_str_len] = '\0';
314 
315 	if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0)
316 		goto err;
317 
318 	/* Now create from the data structure */
319 	if (context_from_record(handle, policydb, cptr, ctx_record) < 0)
320 		goto err;
321 
322 	free(con_cpy);
323 	sepol_context_free(ctx_record);
324 	return STATUS_SUCCESS;
325 
326       err:
327 	ERR(handle, "could not create context structure");
328 	free(con_cpy);
329 	sepol_context_free(ctx_record);
330 	return STATUS_ERR;
331 }
332 
sepol_context_check(sepol_handle_t * handle,const sepol_policydb_t * policydb,const sepol_context_t * context)333 int sepol_context_check(sepol_handle_t * handle,
334 			const sepol_policydb_t * policydb,
335 			const sepol_context_t * context)
336 {
337 
338 	context_struct_t *con = NULL;
339 	int ret = context_from_record(handle, &policydb->p, &con, context);
340 	context_destroy(con);
341 	free(con);
342 	return ret;
343 }
344