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