Coverage Report

Created: 2025-08-26 06:22

/src/selinux/libsepol/src/hierarchy.c
Line
Count
Source (jump to first uncovered line)
1
/* Authors: Joshua Brindle <jbrindle@tresys.com>
2
 *      Jason Tang <jtang@tresys.com>
3
 *
4
 * Updates: KaiGai Kohei <kaigai@ak.jp.nec.com>
5
 *          adds checks based on newer boundary facility.
6
 *
7
 * A set of utility functions that aid policy decision when dealing
8
 * with hierarchal namespaces.
9
 *
10
 * Copyright (C) 2005 Tresys Technology, LLC
11
 *
12
 * Copyright (c) 2008 NEC Corporation
13
 *
14
 *  This library is free software; you can redistribute it and/or
15
 *  modify it under the terms of the GNU Lesser General Public
16
 *  License as published by the Free Software Foundation; either
17
 *  version 2.1 of the License, or (at your option) any later version.
18
 *
19
 *  This library is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22
 *  Lesser General Public License for more details.
23
 *
24
 *  You should have received a copy of the GNU Lesser General Public
25
 *  License along with this library; if not, write to the Free Software
26
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
27
 */
28
29
#include <string.h>
30
#include <stdlib.h>
31
#include <assert.h>
32
#include <sepol/policydb/policydb.h>
33
#include <sepol/policydb/conditional.h>
34
#include <sepol/policydb/hierarchy.h>
35
#include <sepol/policydb/expand.h>
36
#include <sepol/policydb/util.h>
37
38
#include "debug.h"
39
40
313k
#define BOUNDS_AVTAB_SIZE 1024
41
42
static int bounds_insert_helper(sepol_handle_t *handle, avtab_t *avtab,
43
        avtab_key_t *avtab_key, avtab_datum_t *datum)
44
993k
{
45
993k
  int rc = avtab_insert(avtab, avtab_key, datum);
46
993k
  if (rc) {
47
0
    if (rc == SEPOL_ENOMEM)
48
0
      ERR(handle, "Insufficient memory");
49
0
    else
50
0
      ERR(handle, "Unexpected error (%d)", rc);
51
0
  }
52
993k
  return rc;
53
993k
}
54
55
56
static int bounds_insert_rule(sepol_handle_t *handle, avtab_t *avtab,
57
            avtab_t *global, avtab_t *other,
58
            avtab_key_t *avtab_key, avtab_datum_t *datum)
59
2.30M
{
60
2.30M
  int rc = 0;
61
2.30M
  avtab_datum_t *dup = avtab_search(avtab, avtab_key);
62
63
2.30M
  if (!dup) {
64
993k
    rc = bounds_insert_helper(handle, avtab, avtab_key, datum);
65
993k
    if (rc) goto exit;
66
1.31M
  } else {
67
1.31M
    dup->data |= datum->data;
68
1.31M
  }
69
70
2.30M
  if (other) {
71
    /* Search the other conditional avtab for the key and
72
     * add any common permissions to the global avtab
73
     */
74
2.20M
    uint32_t data = 0;
75
2.20M
    dup = avtab_search(other, avtab_key);
76
2.20M
    if (dup) {
77
104k
      data = dup->data & datum->data;
78
104k
      if (data) {
79
102k
        dup = avtab_search(global, avtab_key);
80
102k
        if (!dup) {
81
378
          avtab_datum_t d;
82
378
          d.data = data;
83
378
          rc = bounds_insert_helper(handle, global,
84
378
                  avtab_key, &d);
85
378
          if (rc) goto exit;
86
102k
        } else {
87
102k
          dup->data |= data;
88
102k
        }
89
102k
      }
90
104k
    }
91
2.20M
  }
92
93
2.30M
exit:
94
2.30M
  return rc;
95
2.30M
}
96
97
static int bounds_expand_rule(sepol_handle_t *handle, policydb_t *p,
98
            avtab_t *avtab, avtab_t *global, avtab_t *other,
99
            uint32_t parent, uint32_t src, uint32_t tgt,
100
            uint32_t class, uint32_t data)
101
5.26M
{
102
5.26M
  int rc = 0;
103
5.26M
  avtab_key_t avtab_key;
104
5.26M
  avtab_datum_t datum;
105
5.26M
  ebitmap_node_t *tnode;
106
5.26M
  unsigned int i;
107
108
5.26M
  avtab_key.specified = AVTAB_ALLOWED;
109
5.26M
  avtab_key.target_class = class;
110
5.26M
  datum.data = data;
111
112
5.26M
  if (ebitmap_get_bit(&p->attr_type_map[src - 1], parent - 1)) {
113
2.21M
    avtab_key.source_type = parent;
114
141M
    ebitmap_for_each_positive_bit(&p->attr_type_map[tgt - 1], tnode, i) {
115
2.30M
      avtab_key.target_type = i + 1;
116
2.30M
      rc = bounds_insert_rule(handle, avtab, global, other,
117
2.30M
            &avtab_key, &datum);
118
2.30M
      if (rc) goto exit;
119
2.30M
    }
120
2.21M
  }
121
122
5.26M
exit:
123
5.26M
  return rc;
124
5.26M
}
125
126
static int bounds_expand_cond_rules(sepol_handle_t *handle, policydb_t *p,
127
            cond_av_list_t *cur, avtab_t *avtab,
128
            avtab_t *global, avtab_t *other,
129
            uint32_t parent)
130
307k
{
131
307k
  int rc = 0;
132
133
4.95M
  for (; cur; cur = cur->next) {
134
4.64M
    avtab_ptr_t n = cur->node;
135
4.64M
    rc = bounds_expand_rule(handle, p, avtab, global, other, parent,
136
4.64M
          n->key.source_type, n->key.target_type,
137
4.64M
          n->key.target_class, n->datum.data);
138
4.64M
    if (rc) goto exit;
139
4.64M
  }
140
141
307k
exit:
142
307k
  return rc;
143
307k
}
144
145
struct bounds_expand_args {
146
  sepol_handle_t *handle;
147
  policydb_t *p;
148
  avtab_t *avtab;
149
  uint32_t parent;
150
};
151
152
static int bounds_expand_rule_callback(avtab_key_t *k, avtab_datum_t *d,
153
               void *args)
154
650k
{
155
650k
  struct bounds_expand_args *a = (struct bounds_expand_args *)args;
156
157
650k
  if (!(k->specified & AVTAB_ALLOWED))
158
31.0k
    return 0;
159
160
619k
  return bounds_expand_rule(a->handle, a->p, a->avtab, NULL, NULL,
161
619k
          a->parent, k->source_type, k->target_type,
162
619k
          k->target_class, d->data);
163
650k
}
164
165
struct bounds_cond_info {
166
  avtab_t true_avtab;
167
  avtab_t false_avtab;
168
  cond_list_t *cond_list;
169
  struct bounds_cond_info *next;
170
};
171
172
static void bounds_destroy_cond_info(struct bounds_cond_info *cur)
173
6.40k
{
174
6.40k
  struct bounds_cond_info *next;
175
176
313k
  for (; cur; cur = next) {
177
306k
    next = cur->next;
178
306k
    avtab_destroy(&cur->true_avtab);
179
306k
    avtab_destroy(&cur->false_avtab);
180
306k
    cur->next = NULL;
181
306k
    free(cur);
182
306k
  }
183
6.40k
}
184
185
static int bounds_expand_parent_rules(sepol_handle_t *handle, policydb_t *p,
186
              avtab_t *global_avtab,
187
              struct bounds_cond_info **cond_info,
188
              uint32_t parent)
189
6.40k
{
190
6.40k
  int rc = 0;
191
6.40k
  struct bounds_expand_args args;
192
6.40k
  cond_list_t *cur;
193
194
6.40k
  avtab_init(global_avtab);
195
6.40k
  rc = avtab_alloc(global_avtab, BOUNDS_AVTAB_SIZE);
196
6.40k
  if (rc) goto oom;
197
198
6.40k
  args.handle = handle;
199
6.40k
  args.p = p;
200
6.40k
  args.avtab = global_avtab;
201
6.40k
  args.parent = parent;
202
6.40k
  rc = avtab_map(&p->te_avtab, bounds_expand_rule_callback, &args);
203
6.40k
  if (rc) goto exit;
204
205
6.40k
  *cond_info = NULL;
206
313k
  for (cur = p->cond_list; cur; cur = cur->next) {
207
306k
    struct bounds_cond_info *ci;
208
306k
    ci = malloc(sizeof(struct bounds_cond_info));
209
306k
    if (!ci) goto oom;
210
306k
    avtab_init(&ci->true_avtab);
211
306k
    avtab_init(&ci->false_avtab);
212
306k
    ci->cond_list = cur;
213
306k
    ci->next = *cond_info;
214
306k
    *cond_info = ci;
215
306k
    if (cur->true_list) {
216
91.1k
      rc = avtab_alloc(&ci->true_avtab, BOUNDS_AVTAB_SIZE);
217
91.1k
      if (rc) goto oom;
218
91.1k
      rc = bounds_expand_cond_rules(handle, p, cur->true_list,
219
91.1k
                  &ci->true_avtab, NULL,
220
91.1k
                  NULL, parent);
221
91.1k
      if (rc) goto exit;
222
91.1k
    }
223
306k
    if (cur->false_list) {
224
216k
      rc = avtab_alloc(&ci->false_avtab, BOUNDS_AVTAB_SIZE);
225
216k
      if (rc) goto oom;
226
216k
      rc = bounds_expand_cond_rules(handle, p, cur->false_list,
227
216k
                  &ci->false_avtab,
228
216k
                  global_avtab,
229
216k
                  &ci->true_avtab, parent);
230
216k
      if (rc) goto exit;
231
216k
    }
232
306k
  }
233
234
6.40k
  return 0;
235
236
0
oom:
237
0
  ERR(handle, "Insufficient memory");
238
239
0
exit:
240
0
  ERR(handle,"Failed to expand parent rules");
241
0
  avtab_destroy(global_avtab);
242
0
  bounds_destroy_cond_info(*cond_info);
243
0
  *cond_info = NULL;
244
0
  return rc;
245
0
}
246
247
static int bounds_not_covered(avtab_t *global_avtab, avtab_t *cur_avtab,
248
            avtab_key_t *avtab_key, uint32_t data)
249
4.60M
{
250
4.60M
  avtab_datum_t *datum = avtab_search(cur_avtab, avtab_key);
251
4.60M
  if (datum)
252
169k
    data &= ~datum->data;
253
4.60M
  if (global_avtab && data) {
254
4.40M
    datum = avtab_search(global_avtab, avtab_key);
255
4.40M
    if (datum)
256
4.33M
      data &= ~datum->data;
257
4.40M
  }
258
259
4.60M
  return data;
260
4.60M
}
261
262
static int bounds_add_bad(sepol_handle_t *handle, uint32_t src, uint32_t tgt,
263
        uint32_t class, uint32_t data, avtab_ptr_t *bad)
264
102k
{
265
102k
  struct avtab_node *new = malloc(sizeof(struct avtab_node));
266
102k
  if (new == NULL) {
267
0
    ERR(handle, "Insufficient memory");
268
0
    return SEPOL_ENOMEM;
269
0
  }
270
102k
  memset(new, 0, sizeof(struct avtab_node));
271
102k
  new->key.source_type = src;
272
102k
  new->key.target_type = tgt;
273
102k
  new->key.target_class = class;
274
102k
  new->datum.data = data;
275
102k
  new->next = *bad;
276
102k
  *bad = new;
277
278
102k
  return 0;
279
102k
}
280
281
static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p,
282
           avtab_t *global_avtab, avtab_t *cur_avtab,
283
           uint32_t child, uint32_t parent, uint32_t src,
284
           uint32_t tgt, uint32_t class, uint32_t data,
285
           avtab_ptr_t *bad, int *numbad)
286
5.08M
{
287
5.08M
  int rc = 0;
288
5.08M
  avtab_key_t avtab_key;
289
5.08M
  type_datum_t *td;
290
5.08M
  ebitmap_node_t *tnode;
291
5.08M
  unsigned int i;
292
5.08M
  uint32_t d;
293
294
5.08M
  avtab_key.specified = AVTAB_ALLOWED;
295
5.08M
  avtab_key.target_class = class;
296
297
5.08M
  if (ebitmap_get_bit(&p->attr_type_map[src - 1], child - 1)) {
298
135k
    avtab_key.source_type = parent;
299
13.3M
    ebitmap_for_each_positive_bit(&p->attr_type_map[tgt - 1], tnode, i) {
300
4.60M
      td = p->type_val_to_struct[i];
301
4.60M
      if (td && td->bounds) {
302
2.35M
        avtab_key.target_type = td->bounds;
303
2.35M
        d = bounds_not_covered(global_avtab, cur_avtab,
304
2.35M
                   &avtab_key, data);
305
2.35M
      } else {
306
2.24M
        avtab_key.target_type = i + 1;
307
2.24M
        d = bounds_not_covered(global_avtab, cur_avtab,
308
2.24M
                   &avtab_key, data);
309
2.24M
      }
310
4.60M
      if (d) {
311
102k
        (*numbad)++;
312
102k
        rc = bounds_add_bad(handle, child, i+1, class, d, bad);
313
102k
        if (rc) goto exit;
314
102k
      }
315
4.60M
    }
316
135k
  }
317
318
5.08M
exit:
319
5.08M
  return rc;
320
5.08M
}
321
322
static int bounds_check_cond_rules(sepol_handle_t *handle, policydb_t *p,
323
           avtab_t *global_avtab, avtab_t *cond_avtab,
324
           cond_av_list_t *rules, uint32_t child,
325
           uint32_t parent, avtab_ptr_t *bad,
326
           int *numbad)
327
613k
{
328
613k
  int rc = 0;
329
613k
  cond_av_list_t *cur;
330
331
5.26M
  for (cur = rules; cur; cur = cur->next) {
332
4.64M
    avtab_ptr_t ap = cur->node;
333
4.64M
    avtab_key_t *key = &ap->key;
334
4.64M
    avtab_datum_t *datum = &ap->datum;
335
4.64M
    if (!(key->specified & AVTAB_ALLOWED))
336
183k
      continue;
337
4.46M
    rc = bounds_check_rule(handle, p, global_avtab, cond_avtab,
338
4.46M
               child, parent, key->source_type,
339
4.46M
               key->target_type, key->target_class,
340
4.46M
               datum->data, bad, numbad);
341
4.46M
    if (rc) goto exit;
342
4.46M
  }
343
344
613k
exit:
345
613k
  return rc;
346
613k
}
347
348
struct bounds_check_args {
349
  sepol_handle_t *handle;
350
  policydb_t *p;
351
  avtab_t *cur_avtab;
352
  uint32_t child;
353
  uint32_t parent;
354
  avtab_ptr_t bad;
355
  int numbad;
356
};
357
358
static int bounds_check_rule_callback(avtab_key_t *k, avtab_datum_t *d,
359
              void *args)
360
650k
{
361
650k
  struct bounds_check_args *a = (struct bounds_check_args *)args;
362
363
650k
  if (!(k->specified & AVTAB_ALLOWED))
364
31.0k
    return 0;
365
366
619k
  return bounds_check_rule(a->handle, a->p, NULL, a->cur_avtab, a->child,
367
619k
         a->parent, k->source_type, k->target_type,
368
619k
         k->target_class, d->data, &a->bad, &a->numbad);
369
650k
}
370
371
static int bounds_check_child_rules(sepol_handle_t *handle, policydb_t *p,
372
            avtab_t *global_avtab,
373
            struct bounds_cond_info *cond_info,
374
            uint32_t child, uint32_t parent,
375
            avtab_ptr_t *bad, int *numbad)
376
6.40k
{
377
6.40k
  int rc;
378
6.40k
  struct bounds_check_args args;
379
6.40k
  struct bounds_cond_info *cur;
380
381
6.40k
  args.handle = handle;
382
6.40k
  args.p = p;
383
6.40k
  args.cur_avtab = global_avtab;
384
6.40k
  args.child = child;
385
6.40k
  args.parent = parent;
386
6.40k
  args.bad = NULL;
387
6.40k
  args.numbad = 0;
388
6.40k
  rc = avtab_map(&p->te_avtab, bounds_check_rule_callback, &args);
389
6.40k
  if (rc) goto exit;
390
391
313k
  for (cur = cond_info; cur; cur = cur->next) {
392
306k
    cond_list_t *node = cur->cond_list;
393
306k
    rc = bounds_check_cond_rules(handle, p, global_avtab,
394
306k
               &cur->true_avtab,
395
306k
               node->true_list, child, parent,
396
306k
               &args.bad, &args.numbad);
397
306k
    if (rc) goto exit;
398
399
306k
    rc = bounds_check_cond_rules(handle, p, global_avtab,
400
306k
               &cur->false_avtab,
401
306k
               node->false_list, child, parent,
402
306k
               &args.bad, &args.numbad);
403
306k
    if (rc) goto exit;
404
306k
  }
405
406
6.40k
  *numbad += args.numbad;
407
6.40k
  *bad = args.bad;
408
409
6.40k
exit:
410
6.40k
  return rc;
411
6.40k
}
412
413
int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
414
          uint32_t parent, avtab_ptr_t *bad, int *numbad)
415
6.40k
{
416
6.40k
  int rc = 0;
417
6.40k
  avtab_t global_avtab;
418
6.40k
  struct bounds_cond_info *cond_info = NULL;
419
420
6.40k
  rc = bounds_expand_parent_rules(handle, p, &global_avtab, &cond_info, parent);
421
6.40k
  if (rc) goto exit;
422
423
6.40k
  rc = bounds_check_child_rules(handle, p, &global_avtab, cond_info,
424
6.40k
              child, parent, bad, numbad);
425
426
6.40k
  bounds_destroy_cond_info(cond_info);
427
6.40k
  avtab_destroy(&global_avtab);
428
429
6.40k
exit:
430
6.40k
  return rc;
431
6.40k
}
432
433
struct bounds_args {
434
  sepol_handle_t *handle;
435
  policydb_t *p;
436
  int numbad;
437
};
438
439
static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
440
        uint32_t parent, avtab_ptr_t cur)
441
22
{
442
22
  ERR(handle, "Child type %s exceeds bounds of parent %s in the following rules:",
443
22
      p->p_type_val_to_name[child - 1],
444
22
      p->p_type_val_to_name[parent - 1]);
445
56
  for (; cur; cur = cur->next) {
446
34
    char *permstr = sepol_av_to_string(p, cur->key.target_class, cur->datum.data);
447
448
34
    ERR(handle, "    %s %s : %s { %s }",
449
34
        p->p_type_val_to_name[cur->key.source_type - 1],
450
34
        p->p_type_val_to_name[cur->key.target_type - 1],
451
34
        p->p_class_val_to_name[cur->key.target_class - 1],
452
34
        permstr ?: "<format-failure>");
453
454
34
    free(permstr);
455
34
  }
456
22
}
457
458
void bounds_destroy_bad(avtab_ptr_t cur)
459
1.94k
{
460
1.94k
  avtab_ptr_t next;
461
462
104k
  for (; cur; cur = next) {
463
102k
    next = cur->next;
464
102k
    cur->next = NULL;
465
102k
    free(cur);
466
102k
  }
467
1.94k
}
468
469
static int bounds_check_type_callback(hashtab_key_t k __attribute__ ((unused)),
470
              hashtab_datum_t d, void *args)
471
2.80k
{
472
2.80k
  int rc = 0;
473
2.80k
  struct bounds_args *a = (struct bounds_args *)args;
474
2.80k
  type_datum_t *t = (type_datum_t *)d;
475
2.80k
  avtab_ptr_t bad = NULL;
476
477
2.80k
  if (t->bounds) {
478
510
    rc = bounds_check_type(a->handle, a->p, t->s.value, t->bounds,
479
510
               &bad, &a->numbad);
480
510
    if (bad) {
481
22
      bounds_report(a->handle, a->p, t->s.value, t->bounds,
482
22
              bad);
483
22
      bounds_destroy_bad(bad);
484
22
    }
485
510
  }
486
487
2.80k
  return rc;
488
2.80k
}
489
490
int bounds_check_types(sepol_handle_t *handle, policydb_t *p)
491
2.13k
{
492
2.13k
  int rc;
493
2.13k
  struct bounds_args args;
494
495
2.13k
  args.handle = handle;
496
2.13k
  args.p = p;
497
2.13k
  args.numbad = 0;
498
499
2.13k
  rc = hashtab_map(p->p_types.table, bounds_check_type_callback, &args);
500
2.13k
  if (rc) goto exit;
501
502
2.13k
  if (args.numbad > 0) {
503
12
    ERR(handle, "%d errors found during type bounds check",
504
12
        args.numbad);
505
12
    rc = SEPOL_ERR;
506
12
  }
507
508
2.13k
exit:
509
2.13k
  return rc;
510
2.13k
}
511
512
/* The role bounds is defined as: a child role cannot have a type that
513
 * its parent doesn't have.
514
 */
515
static int bounds_check_role_callback(hashtab_key_t k,
516
              hashtab_datum_t d, void *args)
517
42.2k
{
518
42.2k
  struct bounds_args *a = (struct bounds_args *)args;
519
42.2k
  role_datum_t *r = (role_datum_t *) d;
520
42.2k
  role_datum_t *rp = NULL;
521
522
42.2k
  if (!r->bounds)
523
42.0k
    return 0;
524
525
166
  rp = a->p->role_val_to_struct[r->bounds - 1];
526
527
166
  if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
528
47
    ERR(a->handle, "Role bounds violation, %s exceeds %s",
529
47
        (char *)k, a->p->p_role_val_to_name[rp->s.value - 1]);
530
47
    a->numbad++;
531
47
  }
532
533
166
  return 0;
534
166
}
535
536
int bounds_check_roles(sepol_handle_t *handle, policydb_t *p)
537
5.39k
{
538
5.39k
  struct bounds_args args;
539
540
5.39k
  args.handle = handle;
541
5.39k
  args.p = p;
542
5.39k
  args.numbad = 0;
543
544
5.39k
  hashtab_map(p->p_roles.table, bounds_check_role_callback, &args);
545
546
5.39k
  if (args.numbad > 0) {
547
47
    ERR(handle, "%d errors found during role bounds check",
548
47
        args.numbad);
549
47
    return SEPOL_ERR;
550
47
  }
551
552
5.34k
  return 0;
553
5.39k
}
554
555
/* The user bounds is defined as: a child user cannot have a role that
556
 * its parent doesn't have.
557
 */
558
static int bounds_check_user_callback(hashtab_key_t k,
559
              hashtab_datum_t d, void *args)
560
8.06k
{
561
8.06k
  struct bounds_args *a = (struct bounds_args *)args;
562
8.06k
  user_datum_t *u = (user_datum_t *) d;
563
8.06k
  user_datum_t *up = NULL;
564
565
8.06k
  if (!u->bounds)
566
8.01k
    return 0;
567
568
53
  up = a->p->user_val_to_struct[u->bounds - 1];
569
570
53
  if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
571
2
    ERR(a->handle, "User bounds violation, %s exceeds %s",
572
2
        (char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
573
2
    a->numbad++;
574
2
  }
575
576
53
  return 0;
577
53
}
578
579
int bounds_check_users(sepol_handle_t *handle, policydb_t *p)
580
5.39k
{
581
5.39k
  struct bounds_args args;
582
583
5.39k
  args.handle = handle;
584
5.39k
  args.p = p;
585
5.39k
  args.numbad = 0;
586
587
5.39k
  hashtab_map(p->p_users.table, bounds_check_user_callback, &args);
588
589
5.39k
  if (args.numbad > 0) {
590
2
    ERR(handle, "%d errors found during user bounds check",
591
2
        args.numbad);
592
2
    return SEPOL_ERR;
593
2
  }
594
595
5.38k
  return 0;
596
5.39k
}
597
598
#define add_hierarchy_callback_template(prefix)       \
599
  int hierarchy_add_##prefix##_callback(hashtab_key_t k __attribute__ ((unused)), \
600
27.6k
              hashtab_datum_t d, void *args) \
601
27.6k
{               \
602
27.6k
  struct bounds_args *a = (struct bounds_args *)args;   \
603
27.6k
  sepol_handle_t *handle = a->handle;       \
604
27.6k
  policydb_t *p = a->p;           \
605
27.6k
  prefix##_datum_t *datum = (prefix##_datum_t *)d;    \
606
27.6k
  prefix##_datum_t *parent;         \
607
27.6k
  char *parent_name, *datum_name, *tmp;       \
608
27.6k
                  \
609
27.6k
  if (!datum->bounds) {           \
610
27.0k
    datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
611
27.0k
                  \
612
27.0k
    tmp = strrchr(datum_name, '.');       \
613
27.0k
    /* no '.' means it has no parent */     \
614
27.0k
    if (!tmp) return 0;         \
615
27.0k
                  \
616
27.0k
    parent_name = strdup(datum_name);     \
617
884
    if (!parent_name) {         \
618
0
      ERR(handle, "Insufficient memory");    \
619
0
      return SEPOL_ENOMEM;       \
620
0
    }              \
621
884
    parent_name[tmp - datum_name] = '\0';     \
622
884
                  \
623
884
    parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
624
884
    if (!parent) {           \
625
621
      /* Orphan type/role/user */     \
626
621
      ERR(handle, "%s doesn't exist, %s is an orphan",\
627
621
          parent_name,        \
628
621
          p->p_##prefix##_val_to_name[datum->s.value - 1]); \
629
621
      free(parent_name);        \
630
621
      a->numbad++;          \
631
621
      return 0;         \
632
621
    }              \
633
884
    datum->bounds = parent->s.value;      \
634
263
    free(parent_name);          \
635
263
  }                \
636
27.6k
                  \
637
27.6k
  return 0;             \
638
27.6k
}                \
hierarchy.c:hierarchy_add_user_callback
Line
Count
Source
600
2.10k
              hashtab_datum_t d, void *args) \
601
2.10k
{               \
602
2.10k
  struct bounds_args *a = (struct bounds_args *)args;   \
603
2.10k
  sepol_handle_t *handle = a->handle;       \
604
2.10k
  policydb_t *p = a->p;           \
605
2.10k
  prefix##_datum_t *datum = (prefix##_datum_t *)d;    \
606
2.10k
  prefix##_datum_t *parent;         \
607
2.10k
  char *parent_name, *datum_name, *tmp;       \
608
2.10k
                  \
609
2.10k
  if (!datum->bounds) {           \
610
2.06k
    datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
611
2.06k
                  \
612
2.06k
    tmp = strrchr(datum_name, '.');       \
613
2.06k
    /* no '.' means it has no parent */     \
614
2.06k
    if (!tmp) return 0;         \
615
2.06k
                  \
616
2.06k
    parent_name = strdup(datum_name);     \
617
63
    if (!parent_name) {         \
618
0
      ERR(handle, "Insufficient memory");    \
619
0
      return SEPOL_ENOMEM;       \
620
0
    }              \
621
63
    parent_name[tmp - datum_name] = '\0';     \
622
63
                  \
623
63
    parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
624
63
    if (!parent) {           \
625
51
      /* Orphan type/role/user */     \
626
51
      ERR(handle, "%s doesn't exist, %s is an orphan",\
627
51
          parent_name,        \
628
51
          p->p_##prefix##_val_to_name[datum->s.value - 1]); \
629
51
      free(parent_name);        \
630
51
      a->numbad++;          \
631
51
      return 0;         \
632
51
    }              \
633
63
    datum->bounds = parent->s.value;      \
634
12
    free(parent_name);          \
635
12
  }                \
636
2.10k
                  \
637
2.10k
  return 0;             \
638
2.10k
}                \
hierarchy.c:hierarchy_add_role_callback
Line
Count
Source
600
22.2k
              hashtab_datum_t d, void *args) \
601
22.2k
{               \
602
22.2k
  struct bounds_args *a = (struct bounds_args *)args;   \
603
22.2k
  sepol_handle_t *handle = a->handle;       \
604
22.2k
  policydb_t *p = a->p;           \
605
22.2k
  prefix##_datum_t *datum = (prefix##_datum_t *)d;    \
606
22.2k
  prefix##_datum_t *parent;         \
607
22.2k
  char *parent_name, *datum_name, *tmp;       \
608
22.2k
                  \
609
22.2k
  if (!datum->bounds) {           \
610
22.1k
    datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
611
22.1k
                  \
612
22.1k
    tmp = strrchr(datum_name, '.');       \
613
22.1k
    /* no '.' means it has no parent */     \
614
22.1k
    if (!tmp) return 0;         \
615
22.1k
                  \
616
22.1k
    parent_name = strdup(datum_name);     \
617
577
    if (!parent_name) {         \
618
0
      ERR(handle, "Insufficient memory");    \
619
0
      return SEPOL_ENOMEM;       \
620
0
    }              \
621
577
    parent_name[tmp - datum_name] = '\0';     \
622
577
                  \
623
577
    parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
624
577
    if (!parent) {           \
625
455
      /* Orphan type/role/user */     \
626
455
      ERR(handle, "%s doesn't exist, %s is an orphan",\
627
455
          parent_name,        \
628
455
          p->p_##prefix##_val_to_name[datum->s.value - 1]); \
629
455
      free(parent_name);        \
630
455
      a->numbad++;          \
631
455
      return 0;         \
632
455
    }              \
633
577
    datum->bounds = parent->s.value;      \
634
122
    free(parent_name);          \
635
122
  }                \
636
22.2k
                  \
637
22.2k
  return 0;             \
638
22.2k
}                \
hierarchy.c:hierarchy_add_type_callback
Line
Count
Source
600
3.28k
              hashtab_datum_t d, void *args) \
601
3.28k
{               \
602
3.28k
  struct bounds_args *a = (struct bounds_args *)args;   \
603
3.28k
  sepol_handle_t *handle = a->handle;       \
604
3.28k
  policydb_t *p = a->p;           \
605
3.28k
  prefix##_datum_t *datum = (prefix##_datum_t *)d;    \
606
3.28k
  prefix##_datum_t *parent;         \
607
3.28k
  char *parent_name, *datum_name, *tmp;       \
608
3.28k
                  \
609
3.28k
  if (!datum->bounds) {           \
610
2.89k
    datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
611
2.89k
                  \
612
2.89k
    tmp = strrchr(datum_name, '.');       \
613
2.89k
    /* no '.' means it has no parent */     \
614
2.89k
    if (!tmp) return 0;         \
615
2.89k
                  \
616
2.89k
    parent_name = strdup(datum_name);     \
617
244
    if (!parent_name) {         \
618
0
      ERR(handle, "Insufficient memory");    \
619
0
      return SEPOL_ENOMEM;       \
620
0
    }              \
621
244
    parent_name[tmp - datum_name] = '\0';     \
622
244
                  \
623
244
    parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
624
244
    if (!parent) {           \
625
115
      /* Orphan type/role/user */     \
626
115
      ERR(handle, "%s doesn't exist, %s is an orphan",\
627
115
          parent_name,        \
628
115
          p->p_##prefix##_val_to_name[datum->s.value - 1]); \
629
115
      free(parent_name);        \
630
115
      a->numbad++;          \
631
115
      return 0;         \
632
115
    }              \
633
244
    datum->bounds = parent->s.value;      \
634
129
    free(parent_name);          \
635
129
  }                \
636
3.28k
                  \
637
3.28k
  return 0;             \
638
3.28k
}                \
639
640
static add_hierarchy_callback_template(type)
641
static add_hierarchy_callback_template(role)
642
static add_hierarchy_callback_template(user)
643
644
int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p)
645
2.45k
{
646
2.45k
  int rc = 0;
647
2.45k
  struct bounds_args args;
648
649
2.45k
  args.handle = handle;
650
2.45k
  args.p = p;
651
2.45k
  args.numbad = 0;
652
653
2.45k
  rc = hashtab_map(p->p_users.table, hierarchy_add_user_callback, &args);
654
2.45k
  if (rc) goto exit;
655
656
2.45k
  rc = hashtab_map(p->p_roles.table, hierarchy_add_role_callback, &args);
657
2.45k
  if (rc) goto exit;
658
659
2.45k
  rc = hashtab_map(p->p_types.table, hierarchy_add_type_callback, &args);
660
2.45k
  if (rc) goto exit;
661
662
2.45k
  if (args.numbad > 0) {
663
322
    ERR(handle, "%d errors found while adding hierarchies",
664
322
        args.numbad);
665
322
    rc = SEPOL_ERR;
666
322
  }
667
668
2.45k
exit:
669
2.45k
  return rc;
670
2.45k
}
671
672
int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
673
2.45k
{
674
2.45k
  int rc = 0;
675
2.45k
  int violation = 0;
676
677
2.45k
  rc = hierarchy_add_bounds(handle, p);
678
2.45k
  if (rc) goto exit;
679
680
2.13k
  rc = bounds_check_users(handle, p);
681
2.13k
  if (rc)
682
1
    violation = 1;
683
684
2.13k
  rc = bounds_check_roles(handle, p);
685
2.13k
  if (rc)
686
47
    violation = 1;
687
688
2.13k
  rc = bounds_check_types(handle, p);
689
2.13k
  if (rc) {
690
12
    if (rc == SEPOL_ERR)
691
12
      violation = 1;
692
0
    else
693
0
      goto exit;
694
12
  }
695
696
2.13k
  if (violation)
697
60
    rc = SEPOL_ERR;
698
699
2.45k
exit:
700
2.45k
  return rc;
701
2.13k
}