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