Coverage Report

Created: 2026-07-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/selinux/libsepol/src/hierarchy.c
Line
Count
Source
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
1.14k
#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
552
{
45
552
  int rc = avtab_insert(avtab, avtab_key, datum);
46
552
  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
552
  return rc;
53
552
}
54
55
static int bounds_insert_rule(sepol_handle_t *handle, avtab_t *avtab,
56
            avtab_t *global, avtab_t *other,
57
            avtab_key_t *avtab_key, avtab_datum_t *datum)
58
1.30k
{
59
1.30k
  int rc = 0;
60
1.30k
  avtab_datum_t *dup = avtab_search(avtab, avtab_key);
61
62
1.30k
  if (!dup) {
63
480
    rc = bounds_insert_helper(handle, avtab, avtab_key, datum);
64
480
    if (rc)
65
0
      goto exit;
66
820
  } else {
67
820
    dup->data |= datum->data;
68
820
  }
69
70
1.30k
  if (other) {
71
    /* Search the other conditional avtab for the key and
72
     * add any common permissions to the global avtab
73
     */
74
722
    uint32_t data = 0;
75
722
    dup = avtab_search(other, avtab_key);
76
722
    if (dup) {
77
250
      data = dup->data & datum->data;
78
250
      if (data) {
79
72
        dup = avtab_search(global, avtab_key);
80
72
        if (!dup) {
81
72
          avtab_datum_t d;
82
72
          d.data = data;
83
72
          rc = bounds_insert_helper(
84
72
            handle, global, avtab_key, &d);
85
72
          if (rc)
86
0
            goto exit;
87
72
        } else {
88
0
          dup->data |= data;
89
0
        }
90
72
      }
91
250
    }
92
722
  }
93
94
1.30k
exit:
95
1.30k
  return rc;
96
1.30k
}
97
98
static int bounds_expand_rule(sepol_handle_t *handle, policydb_t *p,
99
            avtab_t *avtab, avtab_t *global, avtab_t *other,
100
            uint32_t parent, uint32_t src, uint32_t tgt,
101
            uint32_t class, uint32_t data)
102
1.87k
{
103
1.87k
  int rc = 0;
104
1.87k
  avtab_key_t avtab_key;
105
1.87k
  avtab_datum_t datum;
106
1.87k
  ebitmap_node_t *tnode;
107
1.87k
  unsigned int i;
108
109
1.87k
  avtab_key.specified = AVTAB_ALLOWED;
110
1.87k
  avtab_key.target_class = class;
111
1.87k
  datum.data = data;
112
113
1.87k
  if (ebitmap_get_bit(&p->attr_type_map[src - 1], parent - 1)) {
114
1.28k
    avtab_key.source_type = parent;
115
74.6k
    ebitmap_for_each_positive_bit(&p->attr_type_map[tgt - 1], tnode,
116
74.6k
                i) {
117
1.30k
      avtab_key.target_type = i + 1;
118
1.30k
      rc = bounds_insert_rule(handle, avtab, global, other,
119
1.30k
            &avtab_key, &datum);
120
1.30k
      if (rc)
121
0
        goto exit;
122
1.30k
    }
123
1.28k
  }
124
125
1.87k
exit:
126
1.87k
  return rc;
127
1.87k
}
128
129
static int bounds_expand_cond_rules(sepol_handle_t *handle, policydb_t *p,
130
            cond_av_list_t *cur, avtab_t *avtab,
131
            avtab_t *global, avtab_t *other,
132
            uint32_t parent)
133
410
{
134
410
  int rc = 0;
135
136
2.08k
  for (; cur; cur = cur->next) {
137
1.67k
    avtab_ptr_t n = cur->node;
138
1.67k
    rc = bounds_expand_rule(handle, p, avtab, global, other, parent,
139
1.67k
          n->key.source_type, n->key.target_type,
140
1.67k
          n->key.target_class, n->datum.data);
141
1.67k
    if (rc)
142
0
      goto exit;
143
1.67k
  }
144
145
410
exit:
146
410
  return rc;
147
410
}
148
149
struct bounds_expand_args {
150
  sepol_handle_t *handle;
151
  policydb_t *p;
152
  avtab_t *avtab;
153
  uint32_t parent;
154
};
155
156
static int bounds_expand_rule_callback(avtab_key_t *k, avtab_datum_t *d,
157
               void *args)
158
1.43k
{
159
1.43k
  struct bounds_expand_args *a = (struct bounds_expand_args *)args;
160
161
1.43k
  if (!(k->specified & AVTAB_ALLOWED))
162
1.24k
    return 0;
163
164
196
  return bounds_expand_rule(a->handle, a->p, a->avtab, NULL, NULL,
165
196
          a->parent, k->source_type, k->target_type,
166
196
          k->target_class, d->data);
167
1.43k
}
168
169
struct bounds_cond_info {
170
  avtab_t true_avtab;
171
  avtab_t false_avtab;
172
  cond_list_t *cond_list;
173
  struct bounds_cond_info *next;
174
};
175
176
static void bounds_destroy_cond_info(struct bounds_cond_info *cur)
177
734
{
178
734
  struct bounds_cond_info *next;
179
180
1.03k
  for (; cur; cur = next) {
181
300
    next = cur->next;
182
300
    avtab_destroy(&cur->true_avtab);
183
300
    avtab_destroy(&cur->false_avtab);
184
300
    cur->next = NULL;
185
300
    free(cur);
186
300
  }
187
734
}
188
189
static int bounds_expand_parent_rules(sepol_handle_t *handle, policydb_t *p,
190
              avtab_t *global_avtab,
191
              struct bounds_cond_info **cond_info,
192
              uint32_t parent)
193
734
{
194
734
  int rc = 0;
195
734
  struct bounds_expand_args args;
196
734
  cond_list_t *cur;
197
198
734
  avtab_init(global_avtab);
199
734
  rc = avtab_alloc(global_avtab, BOUNDS_AVTAB_SIZE);
200
734
  if (rc)
201
0
    goto oom;
202
203
734
  args.handle = handle;
204
734
  args.p = p;
205
734
  args.avtab = global_avtab;
206
734
  args.parent = parent;
207
734
  rc = avtab_map(&p->te_avtab, bounds_expand_rule_callback, &args);
208
734
  if (rc)
209
0
    goto exit;
210
211
734
  *cond_info = NULL;
212
1.03k
  for (cur = p->cond_list; cur; cur = cur->next) {
213
300
    struct bounds_cond_info *ci;
214
300
    ci = malloc(sizeof(struct bounds_cond_info));
215
300
    if (!ci)
216
0
      goto oom;
217
300
    avtab_init(&ci->true_avtab);
218
300
    avtab_init(&ci->false_avtab);
219
300
    ci->cond_list = cur;
220
300
    ci->next = *cond_info;
221
300
    *cond_info = ci;
222
300
    if (cur->true_list) {
223
175
      rc = avtab_alloc(&ci->true_avtab, BOUNDS_AVTAB_SIZE);
224
175
      if (rc)
225
0
        goto oom;
226
175
      rc = bounds_expand_cond_rules(handle, p, cur->true_list,
227
175
                  &ci->true_avtab, NULL,
228
175
                  NULL, parent);
229
175
      if (rc)
230
0
        goto exit;
231
175
    }
232
300
    if (cur->false_list) {
233
235
      rc = avtab_alloc(&ci->false_avtab, BOUNDS_AVTAB_SIZE);
234
235
      if (rc)
235
0
        goto oom;
236
235
      rc = bounds_expand_cond_rules(
237
235
        handle, p, cur->false_list, &ci->false_avtab,
238
235
        global_avtab, &ci->true_avtab, parent);
239
235
      if (rc)
240
0
        goto exit;
241
235
    }
242
300
  }
243
244
734
  return 0;
245
246
0
oom:
247
0
  ERR(handle, "Insufficient memory");
248
249
0
exit:
250
0
  ERR(handle, "Failed to expand parent rules");
251
0
  avtab_destroy(global_avtab);
252
0
  bounds_destroy_cond_info(*cond_info);
253
0
  *cond_info = NULL;
254
0
  return rc;
255
0
}
256
257
static int bounds_not_covered(avtab_t *global_avtab, avtab_t *cur_avtab,
258
            avtab_key_t *avtab_key, uint32_t data)
259
279
{
260
279
  avtab_datum_t *datum = avtab_search(cur_avtab, avtab_key);
261
279
  if (datum)
262
202
    data &= ~datum->data;
263
279
  if (global_avtab && data) {
264
0
    datum = avtab_search(global_avtab, avtab_key);
265
0
    if (datum)
266
0
      data &= ~datum->data;
267
0
  }
268
269
279
  return data;
270
279
}
271
272
static int bounds_add_bad(sepol_handle_t *handle, uint32_t src, uint32_t tgt,
273
        uint32_t class, uint32_t data, avtab_ptr_t *bad)
274
77
{
275
77
  struct avtab_node *new = malloc(sizeof(struct avtab_node));
276
77
  if (new == NULL) {
277
0
    ERR(handle, "Insufficient memory");
278
0
    return SEPOL_ENOMEM;
279
0
  }
280
77
  memset(new, 0, sizeof(struct avtab_node));
281
77
  new->key.source_type = src;
282
77
  new->key.target_type = tgt;
283
77
  new->key.target_class = class;
284
77
  new->datum.data = data;
285
77
  new->next = *bad;
286
77
  *bad = new;
287
288
77
  return 0;
289
77
}
290
291
static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p,
292
           avtab_t *global_avtab, avtab_t *cur_avtab,
293
           uint32_t child, uint32_t parent, uint32_t src,
294
           uint32_t tgt, uint32_t class, uint32_t data,
295
           avtab_ptr_t *bad, int *numbad)
296
310
{
297
310
  int rc = 0;
298
310
  avtab_key_t avtab_key;
299
310
  type_datum_t *td;
300
310
  ebitmap_node_t *tnode;
301
310
  unsigned int i;
302
310
  uint32_t d;
303
304
310
  avtab_key.specified = AVTAB_ALLOWED;
305
310
  avtab_key.target_class = class;
306
307
310
  if (ebitmap_get_bit(&p->attr_type_map[src - 1], child - 1)) {
308
266
    avtab_key.source_type = parent;
309
16.7k
    ebitmap_for_each_positive_bit(&p->attr_type_map[tgt - 1], tnode,
310
16.7k
                i) {
311
279
      td = p->type_val_to_struct[i];
312
279
      if (td && td->bounds) {
313
213
        avtab_key.target_type = td->bounds;
314
213
        d = bounds_not_covered(global_avtab, cur_avtab,
315
213
                   &avtab_key, data);
316
213
      } else {
317
66
        avtab_key.target_type = i + 1;
318
66
        d = bounds_not_covered(global_avtab, cur_avtab,
319
66
                   &avtab_key, data);
320
66
      }
321
279
      if (d) {
322
77
        (*numbad)++;
323
77
        rc = bounds_add_bad(handle, child, i + 1, class,
324
77
                d, bad);
325
77
        if (rc)
326
0
          goto exit;
327
77
      }
328
279
    }
329
266
  }
330
331
310
exit:
332
310
  return rc;
333
310
}
334
335
static int bounds_check_cond_rules(sepol_handle_t *handle, policydb_t *p,
336
           avtab_t *global_avtab, avtab_t *cond_avtab,
337
           cond_av_list_t *rules, uint32_t child,
338
           uint32_t parent, avtab_ptr_t *bad,
339
           int *numbad)
340
600
{
341
600
  int rc = 0;
342
600
  cond_av_list_t *cur;
343
344
2.27k
  for (cur = rules; cur; cur = cur->next) {
345
1.67k
    avtab_ptr_t ap = cur->node;
346
1.67k
    avtab_key_t *key = &ap->key;
347
1.67k
    avtab_datum_t *datum = &ap->datum;
348
1.67k
    if (!(key->specified & AVTAB_ALLOWED))
349
1.56k
      continue;
350
114
    rc = bounds_check_rule(handle, p, global_avtab, cond_avtab,
351
114
               child, parent, key->source_type,
352
114
               key->target_type, key->target_class,
353
114
               datum->data, bad, numbad);
354
114
    if (rc)
355
0
      goto exit;
356
114
  }
357
358
600
exit:
359
600
  return rc;
360
600
}
361
362
struct bounds_check_args {
363
  sepol_handle_t *handle;
364
  policydb_t *p;
365
  avtab_t *cur_avtab;
366
  uint32_t child;
367
  uint32_t parent;
368
  avtab_ptr_t bad;
369
  int numbad;
370
};
371
372
static int bounds_check_rule_callback(avtab_key_t *k, avtab_datum_t *d,
373
              void *args)
374
1.43k
{
375
1.43k
  struct bounds_check_args *a = (struct bounds_check_args *)args;
376
377
1.43k
  if (!(k->specified & AVTAB_ALLOWED))
378
1.24k
    return 0;
379
380
196
  return bounds_check_rule(a->handle, a->p, NULL, a->cur_avtab, a->child,
381
196
         a->parent, k->source_type, k->target_type,
382
196
         k->target_class, d->data, &a->bad, &a->numbad);
383
1.43k
}
384
385
static int bounds_check_child_rules(sepol_handle_t *handle, policydb_t *p,
386
            avtab_t *global_avtab,
387
            struct bounds_cond_info *cond_info,
388
            uint32_t child, uint32_t parent,
389
            avtab_ptr_t *bad, int *numbad)
390
734
{
391
734
  int rc;
392
734
  struct bounds_check_args args;
393
734
  struct bounds_cond_info *cur;
394
395
734
  args.handle = handle;
396
734
  args.p = p;
397
734
  args.cur_avtab = global_avtab;
398
734
  args.child = child;
399
734
  args.parent = parent;
400
734
  args.bad = NULL;
401
734
  args.numbad = 0;
402
734
  rc = avtab_map(&p->te_avtab, bounds_check_rule_callback, &args);
403
734
  if (rc)
404
0
    goto exit;
405
406
1.03k
  for (cur = cond_info; cur; cur = cur->next) {
407
300
    cond_list_t *node = cur->cond_list;
408
300
    rc = bounds_check_cond_rules(handle, p, global_avtab,
409
300
               &cur->true_avtab, node->true_list,
410
300
               child, parent, &args.bad,
411
300
               &args.numbad);
412
300
    if (rc)
413
0
      goto exit;
414
415
300
    rc = bounds_check_cond_rules(handle, p, global_avtab,
416
300
               &cur->false_avtab,
417
300
               node->false_list, child, parent,
418
300
               &args.bad, &args.numbad);
419
300
    if (rc)
420
0
      goto exit;
421
300
  }
422
423
734
  *numbad += args.numbad;
424
734
  *bad = args.bad;
425
426
734
exit:
427
734
  return rc;
428
734
}
429
430
int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
431
          uint32_t parent, avtab_ptr_t *bad, int *numbad)
432
734
{
433
734
  int rc = 0;
434
734
  avtab_t global_avtab;
435
734
  struct bounds_cond_info *cond_info = NULL;
436
437
734
  rc = bounds_expand_parent_rules(handle, p, &global_avtab, &cond_info,
438
734
          parent);
439
734
  if (rc)
440
0
    goto exit;
441
442
734
  rc = bounds_check_child_rules(handle, p, &global_avtab, cond_info,
443
734
              child, parent, bad, numbad);
444
445
734
  bounds_destroy_cond_info(cond_info);
446
734
  avtab_destroy(&global_avtab);
447
448
734
exit:
449
734
  return rc;
450
734
}
451
452
struct bounds_args {
453
  sepol_handle_t *handle;
454
  policydb_t *p;
455
  int numbad;
456
};
457
458
static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
459
        uint32_t parent, avtab_ptr_t cur)
460
62
{
461
62
  ERR(handle,
462
62
      "Child type %s exceeds bounds of parent %s in the following rules:",
463
62
      p->p_type_val_to_name[child - 1],
464
62
      p->p_type_val_to_name[parent - 1]);
465
139
  for (; cur; cur = cur->next) {
466
77
    char *permstr = sepol_av_to_string(p, cur->key.target_class,
467
77
               cur->datum.data);
468
469
77
    ERR(handle, "    %s %s : %s { %s }",
470
77
        p->p_type_val_to_name[cur->key.source_type - 1],
471
77
        p->p_type_val_to_name[cur->key.target_type - 1],
472
77
        p->p_class_val_to_name[cur->key.target_class - 1],
473
77
        permstr ?: "<format-failure>");
474
475
77
    free(permstr);
476
77
  }
477
62
}
478
479
void bounds_destroy_bad(avtab_ptr_t cur)
480
62
{
481
62
  avtab_ptr_t next;
482
483
139
  for (; cur; cur = next) {
484
77
    next = cur->next;
485
77
    cur->next = NULL;
486
77
    free(cur);
487
77
  }
488
62
}
489
490
static int bounds_check_type_callback(hashtab_key_t k __attribute__((unused)),
491
              hashtab_datum_t d, void *args)
492
1.67k
{
493
1.67k
  int rc = 0;
494
1.67k
  struct bounds_args *a = (struct bounds_args *)args;
495
1.67k
  type_datum_t *t = (type_datum_t *)d;
496
1.67k
  avtab_ptr_t bad = NULL;
497
498
1.67k
  if (t->bounds) {
499
734
    rc = bounds_check_type(a->handle, a->p, t->s.value, t->bounds,
500
734
               &bad, &a->numbad);
501
734
    if (bad) {
502
62
      bounds_report(a->handle, a->p, t->s.value, t->bounds,
503
62
              bad);
504
62
      bounds_destroy_bad(bad);
505
62
    }
506
734
  }
507
508
1.67k
  return rc;
509
1.67k
}
510
511
int bounds_check_types(sepol_handle_t *handle, policydb_t *p)
512
1.03k
{
513
1.03k
  int rc;
514
1.03k
  struct bounds_args args;
515
516
1.03k
  args.handle = handle;
517
1.03k
  args.p = p;
518
1.03k
  args.numbad = 0;
519
520
1.03k
  rc = hashtab_map(p->p_types.table, bounds_check_type_callback, &args);
521
1.03k
  if (rc)
522
0
    goto exit;
523
524
1.03k
  if (args.numbad > 0) {
525
39
    ERR(handle, "%d errors found during type bounds check",
526
39
        args.numbad);
527
39
    rc = SEPOL_ERR;
528
39
  }
529
530
1.03k
exit:
531
1.03k
  return rc;
532
1.03k
}
533
534
/* The role bounds is defined as: a child role cannot have a type that
535
 * its parent doesn't have.
536
 */
537
static int bounds_check_role_callback(hashtab_key_t k, hashtab_datum_t d,
538
              void *args)
539
1.23k
{
540
1.23k
  struct bounds_args *a = (struct bounds_args *)args;
541
1.23k
  role_datum_t *r = (role_datum_t *)d;
542
1.23k
  role_datum_t *rp = NULL;
543
544
1.23k
  if (!r->bounds)
545
1.09k
    return 0;
546
547
139
  rp = a->p->role_val_to_struct[r->bounds - 1];
548
549
139
  if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
550
53
    ERR(a->handle, "Role bounds violation, %s exceeds %s",
551
53
        (char *)k, a->p->p_role_val_to_name[rp->s.value - 1]);
552
53
    a->numbad++;
553
53
  }
554
555
139
  return 0;
556
1.23k
}
557
558
int bounds_check_roles(sepol_handle_t *handle, policydb_t *p)
559
1.03k
{
560
1.03k
  struct bounds_args args;
561
562
1.03k
  args.handle = handle;
563
1.03k
  args.p = p;
564
1.03k
  args.numbad = 0;
565
566
1.03k
  hashtab_map(p->p_roles.table, bounds_check_role_callback, &args);
567
568
1.03k
  if (args.numbad > 0) {
569
53
    ERR(handle, "%d errors found during role bounds check",
570
53
        args.numbad);
571
53
    return SEPOL_ERR;
572
53
  }
573
574
983
  return 0;
575
1.03k
}
576
577
/* The user bounds is defined as: a child user cannot have a role that
578
 * its parent doesn't have.
579
 */
580
static int bounds_check_user_callback(hashtab_key_t k, hashtab_datum_t d,
581
              void *args)
582
128
{
583
128
  struct bounds_args *a = (struct bounds_args *)args;
584
128
  user_datum_t *u = (user_datum_t *)d;
585
128
  user_datum_t *up = NULL;
586
587
128
  if (!u->bounds)
588
91
    return 0;
589
590
37
  up = a->p->user_val_to_struct[u->bounds - 1];
591
592
37
  if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
593
0
    ERR(a->handle, "User bounds violation, %s exceeds %s",
594
0
        (char *)k, a->p->p_user_val_to_name[up->s.value - 1]);
595
0
    a->numbad++;
596
0
  }
597
598
37
  return 0;
599
128
}
600
601
int bounds_check_users(sepol_handle_t *handle, policydb_t *p)
602
1.03k
{
603
1.03k
  struct bounds_args args;
604
605
1.03k
  args.handle = handle;
606
1.03k
  args.p = p;
607
1.03k
  args.numbad = 0;
608
609
1.03k
  hashtab_map(p->p_users.table, bounds_check_user_callback, &args);
610
611
1.03k
  if (args.numbad > 0) {
612
0
    ERR(handle, "%d errors found during user bounds check",
613
0
        args.numbad);
614
0
    return SEPOL_ERR;
615
0
  }
616
617
1.03k
  return 0;
618
1.03k
}
619
620
#define add_hierarchy_callback_template(prefix)                                  \
621
  int hierarchy_add_##prefix##_callback(hashtab_key_t k                    \
622
                __attribute__((unused)),           \
623
                hashtab_datum_t d, void *args)     \
624
3.44k
  {                                                                        \
625
3.44k
    struct bounds_args *a = (struct bounds_args *)args;              \
626
3.44k
    sepol_handle_t *handle = a->handle;                              \
627
3.44k
    policydb_t *p = a->p;                                            \
628
3.44k
    prefix##_datum_t *datum = (prefix##_datum_t *)d;                 \
629
3.44k
    prefix##_datum_t *parent;                                        \
630
3.44k
    char *parent_name, *datum_name, *tmp;                            \
631
3.44k
                                                                                 \
632
3.44k
    if (!datum->bounds) {                                            \
633
2.75k
      datum_name =                                             \
634
2.75k
        p->p_##prefix##_val_to_name[datum->s.value -     \
635
2.75k
                  1];                  \
636
2.75k
                                                                                 \
637
2.75k
      tmp = strrchr(datum_name, '.');                          \
638
2.75k
      /* no '.' means it has no parent */                      \
639
2.75k
      if (!tmp)                                                \
640
2.75k
        return 0;                                        \
641
2.75k
                                                                                 \
642
2.75k
      parent_name = strdup(datum_name);                        \
643
432
      if (!parent_name) {                                      \
644
0
        ERR(handle, "Insufficient memory");              \
645
0
        return SEPOL_ENOMEM;                             \
646
0
      }                                                        \
647
432
      parent_name[tmp - datum_name] = '\0';                    \
648
432
                                                                                 \
649
432
      parent = hashtab_search(p->p_##prefix##s.table,          \
650
432
            parent_name);                    \
651
432
      if (!parent) {                                           \
652
173
        /* Orphan type/role/user */                      \
653
173
        ERR(handle,                                      \
654
173
            "%s doesn't exist, %s is an orphan",         \
655
173
            parent_name,                                 \
656
173
            p->p_##prefix##_val_to_name[datum->s.value - \
657
173
                1]);             \
658
173
        free(parent_name);                               \
659
173
        a->numbad++;                                     \
660
173
        return 0;                                        \
661
173
      }                                                        \
662
432
      datum->bounds = parent->s.value;                         \
663
259
      free(parent_name);                                       \
664
259
    }                                                                \
665
3.44k
                                                                                 \
666
3.44k
    return 0;                                                        \
667
3.44k
  }
668
669
1.91k
static add_hierarchy_callback_template(type) static add_hierarchy_callback_template(
670
156
  role) static add_hierarchy_callback_template(user)
671
672
  int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p)
673
1.14k
{
674
1.14k
  int rc = 0;
675
1.14k
  struct bounds_args args;
676
677
1.14k
  args.handle = handle;
678
1.14k
  args.p = p;
679
1.14k
  args.numbad = 0;
680
681
1.14k
  rc = hashtab_map(p->p_users.table, hierarchy_add_user_callback, &args);
682
1.14k
  if (rc)
683
0
    goto exit;
684
685
1.14k
  rc = hashtab_map(p->p_roles.table, hierarchy_add_role_callback, &args);
686
1.14k
  if (rc)
687
0
    goto exit;
688
689
1.14k
  rc = hashtab_map(p->p_types.table, hierarchy_add_type_callback, &args);
690
1.14k
  if (rc)
691
0
    goto exit;
692
693
1.14k
  if (args.numbad > 0) {
694
108
    ERR(handle, "%d errors found while adding hierarchies",
695
108
        args.numbad);
696
108
    rc = SEPOL_ERR;
697
108
  }
698
699
1.14k
exit:
700
1.14k
  return rc;
701
1.14k
}
702
703
int hierarchy_check_constraints(sepol_handle_t *handle, policydb_t *p)
704
1.14k
{
705
1.14k
  int rc = 0;
706
1.14k
  int violation = 0;
707
708
1.14k
  rc = hierarchy_add_bounds(handle, p);
709
1.14k
  if (rc)
710
108
    goto exit;
711
712
1.03k
  rc = bounds_check_users(handle, p);
713
1.03k
  if (rc)
714
0
    violation = 1;
715
716
1.03k
  rc = bounds_check_roles(handle, p);
717
1.03k
  if (rc)
718
53
    violation = 1;
719
720
1.03k
  rc = bounds_check_types(handle, p);
721
1.03k
  if (rc) {
722
39
    if (rc == SEPOL_ERR)
723
39
      violation = 1;
724
0
    else
725
0
      goto exit;
726
39
  }
727
728
1.03k
  if (violation)
729
91
    rc = SEPOL_ERR;
730
731
1.14k
exit:
732
1.14k
  return rc;
733
1.03k
}