Coverage Report

Created: 2026-07-15 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/selinux/libsepol/cil/src/cil_tree.c
Line
Count
Source
1
/*
2
 * Copyright 2011 Tresys Technology, LLC. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions are met:
6
 * 
7
 *    1. Redistributions of source code must retain the above copyright notice,
8
 *       this list of conditions and the following disclaimer.
9
 * 
10
 *    2. Redistributions in binary form must reproduce the above copyright notice,
11
 *       this list of conditions and the following disclaimer in the documentation
12
 *       and/or other materials provided with the distribution.
13
 * 
14
 * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
15
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
 * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 * 
25
 * The views and conclusions contained in the software and documentation are those
26
 * of the authors and should not be interpreted as representing official policies,
27
 * either expressed or implied, of Tresys Technology, LLC.
28
 */
29
30
#include <stdio.h>
31
#include <stdarg.h>
32
#include <inttypes.h>
33
34
#include <sepol/policydb/conditional.h>
35
36
#include "cil_internal.h"
37
#include "cil_flavor.h"
38
#include "cil_log.h"
39
#include "cil_tree.h"
40
#include "cil_list.h"
41
#include "cil_parser.h"
42
#include "cil_strpool.h"
43
44
struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node,
45
               char **info_kind,
46
               uint32_t *hll_line, char **path)
47
0
{
48
0
  int rc;
49
50
0
  if (!node) {
51
0
    goto exit;
52
0
  }
53
54
0
  node = node->parent;
55
56
0
  while (node) {
57
0
    if (node->flavor == CIL_NODE && node->data == NULL) {
58
0
      if (node->cl_head &&
59
0
          node->cl_head->data == CIL_KEY_SRC_INFO) {
60
0
        if (!node->cl_head->next ||
61
0
            !node->cl_head->next->next ||
62
0
            !node->cl_head->next->next->next) {
63
0
          goto exit;
64
0
        }
65
        /* Parse Tree */
66
0
        *info_kind = node->cl_head->next->data;
67
0
        rc = cil_string_to_uint32(
68
0
          node->cl_head->next->next->data,
69
0
          hll_line, 10);
70
0
        if (rc != SEPOL_OK) {
71
0
          goto exit;
72
0
        }
73
0
        *path = node->cl_head->next->next->next->data;
74
0
        return node;
75
0
      }
76
0
      node = node->parent;
77
0
    } else if (node->flavor == CIL_SRC_INFO) {
78
      /* AST */
79
0
      struct cil_src_info *info = node->data;
80
0
      *info_kind = info->kind;
81
0
      *hll_line = info->hll_line;
82
0
      *path = info->path;
83
0
      return node;
84
0
    } else {
85
0
      if (node->flavor == CIL_CALL) {
86
0
        struct cil_call *call = node->data;
87
0
        node = NODE(call->macro);
88
0
      } else if (node->flavor == CIL_BLOCKINHERIT) {
89
0
        struct cil_blockinherit *inherit = node->data;
90
0
        node = NODE(inherit->block);
91
0
      } else {
92
0
        node = node->parent;
93
0
      }
94
0
    }
95
0
  }
96
97
0
exit:
98
0
  *info_kind = NULL;
99
0
  *hll_line = 0;
100
0
  *path = NULL;
101
0
  return NULL;
102
0
}
103
104
char *cil_tree_get_cil_path(struct cil_tree_node *node)
105
0
{
106
0
  char *info_kind;
107
0
  uint32_t hll_line;
108
0
  char *path;
109
110
0
  while (node) {
111
0
    node = cil_tree_get_next_path(node, &info_kind, &hll_line,
112
0
                &path);
113
0
    if (node && info_kind == CIL_KEY_SRC_CIL) {
114
0
      return path;
115
0
    }
116
0
  }
117
118
0
  return NULL;
119
0
}
120
121
__attribute__((format(printf, 3, 4))) void
122
cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl,
123
       const char *msg, ...)
124
0
{
125
0
  va_list ap;
126
127
0
  va_start(ap, msg);
128
0
  cil_vlog(lvl, msg, ap);
129
0
  va_end(ap);
130
131
0
  if (node) {
132
0
    char *path = NULL;
133
0
    uint32_t hll_offset = node->hll_offset;
134
135
0
    path = cil_tree_get_cil_path(node);
136
137
0
    if (path != NULL) {
138
0
      cil_log(lvl, " at %s:%u", path, node->line);
139
0
    }
140
141
0
    while (node) {
142
0
      do {
143
0
        char *info_kind;
144
0
        uint32_t hll_line;
145
146
0
        node = cil_tree_get_next_path(node, &info_kind,
147
0
                    &hll_line, &path);
148
0
        if (!node || info_kind == CIL_KEY_SRC_CIL) {
149
0
          break;
150
0
        }
151
0
        if (info_kind == CIL_KEY_SRC_HLL_LMS) {
152
0
          hll_line += hll_offset -
153
0
                node->hll_offset - 1;
154
0
        }
155
156
0
        cil_log(lvl, " from %s:%u", path, hll_line);
157
0
      } while (1);
158
0
    }
159
0
  }
160
161
0
  cil_log(lvl, "\n");
162
0
}
163
164
int cil_tree_subtree_has_decl(struct cil_tree_node *node)
165
0
{
166
0
  while (node) {
167
0
    if (node->flavor >= CIL_MIN_DECLARATIVE) {
168
0
      return CIL_TRUE;
169
0
    }
170
0
    if (node->cl_head != NULL) {
171
0
      if (cil_tree_subtree_has_decl(node->cl_head))
172
0
        return CIL_TRUE;
173
0
    }
174
0
    node = node->next;
175
0
  }
176
177
0
  return CIL_FALSE;
178
0
}
179
180
int cil_tree_init(struct cil_tree **tree)
181
0
{
182
0
  struct cil_tree *new_tree = cil_malloc(sizeof(*new_tree));
183
184
0
  cil_tree_node_init(&new_tree->root);
185
186
0
  *tree = new_tree;
187
188
0
  return SEPOL_OK;
189
0
}
190
191
void cil_tree_destroy(struct cil_tree **tree)
192
0
{
193
0
  if (tree == NULL || *tree == NULL) {
194
0
    return;
195
0
  }
196
197
0
  cil_tree_subtree_destroy((*tree)->root);
198
0
  free(*tree);
199
0
  *tree = NULL;
200
0
}
201
202
void cil_tree_subtree_destroy(struct cil_tree_node *node)
203
0
{
204
0
  cil_tree_children_destroy(node);
205
0
  cil_tree_node_destroy(&node);
206
0
}
207
208
void cil_tree_children_destroy(struct cil_tree_node *node)
209
0
{
210
0
  struct cil_tree_node *curr, *next;
211
212
0
  if (!node) {
213
0
    return;
214
0
  }
215
216
0
  curr = node->cl_head;
217
0
  while (curr) {
218
0
    next = curr->next;
219
0
    cil_tree_children_destroy(curr);
220
0
    cil_tree_node_destroy(&curr);
221
0
    curr = next;
222
0
  }
223
0
  node->cl_head = NULL;
224
0
  node->cl_tail = NULL;
225
0
}
226
227
void cil_tree_node_init(struct cil_tree_node **node)
228
0
{
229
0
  struct cil_tree_node *new_node = cil_malloc(sizeof(*new_node));
230
0
  new_node->cl_head = NULL;
231
0
  new_node->cl_tail = NULL;
232
0
  new_node->parent = NULL;
233
0
  new_node->data = NULL;
234
0
  new_node->next = NULL;
235
0
  new_node->flavor = CIL_ROOT;
236
0
  new_node->line = 0;
237
0
  new_node->hll_offset = 0;
238
239
0
  *node = new_node;
240
0
}
241
242
void cil_tree_node_destroy(struct cil_tree_node **node)
243
0
{
244
0
  struct cil_symtab_datum *datum;
245
246
0
  if (node == NULL || *node == NULL) {
247
0
    return;
248
0
  }
249
250
0
  if ((*node)->flavor >= CIL_MIN_DECLARATIVE) {
251
0
    datum = (*node)->data;
252
0
    cil_symtab_datum_remove_node(datum, *node);
253
0
    if (datum->nodes == NULL) {
254
0
      cil_destroy_data(&(*node)->data, (*node)->flavor);
255
0
    }
256
0
  } else {
257
0
    cil_destroy_data(&(*node)->data, (*node)->flavor);
258
0
  }
259
0
  free(*node);
260
0
  *node = NULL;
261
0
}
262
263
void cil_tree_node_remove(struct cil_tree_node *node)
264
0
{
265
0
  struct cil_tree_node *parent, *curr;
266
267
0
  if (node == NULL || node->parent == NULL) {
268
0
    return;
269
0
  }
270
271
0
  parent = node->parent;
272
273
0
  if (parent->cl_head == node) {
274
0
    if (parent->cl_tail == node) {
275
0
      parent->cl_tail = NULL;
276
0
    }
277
0
    parent->cl_head = node->next;
278
0
    cil_tree_node_destroy(&node);
279
0
    return;
280
0
  }
281
282
0
  curr = parent->cl_head;
283
0
  while (curr && curr->next != node) {
284
0
    curr = curr->next;
285
0
  }
286
287
0
  if (curr == NULL) {
288
0
    return;
289
0
  }
290
291
0
  if (parent->cl_tail == node) {
292
0
    parent->cl_tail = curr;
293
0
  }
294
0
  curr->next = node->next;
295
0
  cil_tree_node_destroy(&node);
296
0
}
297
298
/* Perform depth-first walk of the tree
299
   Parameters:
300
   start_node:          root node to start walking from
301
   process_node:        function to call when visiting a node
302
                        Takes parameters:
303
                            node:     node being visited
304
                            finished: boolean indicating to the tree walker that it should move on from this branch
305
                            extra_args:    additional data
306
   first_child:   Function to call before entering list of children
307
                        Takes parameters:
308
                            node:     node of first child
309
                            extra args:     additional data
310
   last_child:    Function to call when finished with the last child of a node's children
311
   extra_args:               any additional data to be passed to the helper functions
312
*/
313
314
static int cil_tree_walk_core(
315
  struct cil_tree_node *node,
316
  int (*process_node)(struct cil_tree_node *node, uint32_t *finished,
317
          void *extra_args),
318
  int (*first_child)(struct cil_tree_node *node, void *extra_args),
319
  int (*last_child)(struct cil_tree_node *node, void *extra_args),
320
  void *extra_args)
321
0
{
322
0
  int rc = SEPOL_ERR;
323
324
0
  while (node) {
325
0
    uint32_t finished = CIL_TREE_SKIP_NOTHING;
326
327
0
    if (process_node != NULL) {
328
0
      rc = (*process_node)(node, &finished, extra_args);
329
0
      if (rc != SEPOL_OK) {
330
0
        cil_tree_log(node, CIL_INFO, "Problem");
331
0
        return rc;
332
0
      }
333
0
    }
334
335
0
    if (finished & CIL_TREE_SKIP_NEXT) {
336
0
      return SEPOL_OK;
337
0
    }
338
339
0
    if (node->cl_head != NULL && !(finished & CIL_TREE_SKIP_HEAD)) {
340
0
      rc = cil_tree_walk(node, process_node, first_child,
341
0
             last_child, extra_args);
342
0
      if (rc != SEPOL_OK) {
343
0
        return rc;
344
0
      }
345
0
    }
346
347
0
    node = node->next;
348
0
  }
349
350
0
  return SEPOL_OK;
351
0
}
352
353
int cil_tree_walk(struct cil_tree_node *node,
354
      int (*process_node)(struct cil_tree_node *node,
355
              uint32_t *finished, void *extra_args),
356
      int (*first_child)(struct cil_tree_node *node,
357
             void *extra_args),
358
      int (*last_child)(struct cil_tree_node *node,
359
            void *extra_args),
360
      void *extra_args)
361
0
{
362
0
  int rc = SEPOL_ERR;
363
364
0
  if (!node || !node->cl_head) {
365
0
    return SEPOL_OK;
366
0
  }
367
368
0
  if (first_child != NULL) {
369
0
    rc = (*first_child)(node->cl_head, extra_args);
370
0
    if (rc != SEPOL_OK) {
371
0
      cil_tree_log(node, CIL_INFO, "Problem");
372
0
      return rc;
373
0
    }
374
0
  }
375
376
0
  rc = cil_tree_walk_core(node->cl_head, process_node, first_child,
377
0
        last_child, extra_args);
378
0
  if (rc != SEPOL_OK) {
379
0
    return rc;
380
0
  }
381
382
0
  if (last_child != NULL) {
383
0
    rc = (*last_child)(node->cl_tail, extra_args);
384
0
    if (rc != SEPOL_OK) {
385
0
      cil_tree_log(node, CIL_INFO, "Problem");
386
0
      return rc;
387
0
    }
388
0
  }
389
390
0
  return SEPOL_OK;
391
0
}