Coverage Report

Created: 2025-08-26 06:22

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