Coverage Report

Created: 2025-07-23 06:32

/src/selinux/libsepol/cil/src/cil_parser.c
Line
Count
Source (jump to first uncovered line)
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 <stdlib.h>
31
#include <stdio.h>
32
#include <string.h>
33
#include <stdint.h>
34
#include <sepol/errcodes.h>
35
36
#include "cil_internal.h"
37
#include "cil_log.h"
38
#include "cil_mem.h"
39
#include "cil_tree.h"
40
#include "cil_lexer.h"
41
#include "cil_parser.h"
42
#include "cil_strpool.h"
43
#include "cil_stack.h"
44
45
1.29M
#define CIL_PARSER_MAX_EXPR_DEPTH (0x1 << 12)
46
47
struct hll_info {
48
  uint32_t hll_offset;
49
  uint32_t hll_expand;
50
};
51
52
static void push_hll_info(struct cil_stack *stack, uint32_t hll_offset, uint32_t hll_expand)
53
18.4k
{
54
18.4k
  struct hll_info *new = cil_malloc(sizeof(*new));
55
56
18.4k
  new->hll_offset = hll_offset;
57
18.4k
  new->hll_expand = hll_expand;
58
59
18.4k
  cil_stack_push(stack, CIL_NONE, new);
60
18.4k
}
61
62
static void pop_hll_info(struct cil_stack *stack, uint32_t *hll_offset, uint32_t *hll_expand)
63
18.4k
{
64
18.4k
  struct cil_stack_item *curr = cil_stack_pop(stack);
65
18.4k
  struct hll_info *info;
66
67
18.4k
  if (!curr) {
68
0
    return;
69
0
  }
70
18.4k
  info = curr->data;
71
18.4k
  *hll_expand = info->hll_expand;
72
18.4k
  *hll_offset = info->hll_offset;
73
18.4k
  free(curr->data);
74
18.4k
}
75
76
static void create_node(struct cil_tree_node **node, struct cil_tree_node *current, uint32_t line, uint32_t hll_offset, void *value)
77
3.75M
{
78
3.75M
  cil_tree_node_init(node);
79
3.75M
  (*node)->parent = current;
80
3.75M
  (*node)->flavor = CIL_NODE;
81
3.75M
  (*node)->line = line;
82
3.75M
  (*node)->hll_offset = hll_offset;
83
3.75M
  (*node)->data = value;
84
3.75M
}
85
86
static void insert_node(struct cil_tree_node *node, struct cil_tree_node *current)
87
3.75M
{
88
3.75M
  if (current->cl_head == NULL) {
89
1.30M
    current->cl_head = node;
90
2.44M
  } else {
91
2.44M
    current->cl_tail->next = node;
92
2.44M
  }
93
3.75M
  current->cl_tail = node;
94
3.75M
}
95
96
static int add_hll_linemark(struct cil_tree_node **current, uint32_t *hll_offset, uint32_t *hll_expand, struct cil_stack *stack, char *path)
97
19.9k
{
98
19.9k
  char *hll_type;
99
19.9k
  struct cil_tree_node *node;
100
19.9k
  struct token tok;
101
19.9k
  uint32_t prev_hll_expand, prev_hll_offset;
102
103
19.9k
  cil_lexer_next(&tok);
104
19.9k
  if (tok.type != SYMBOL) {
105
7
    cil_log(CIL_ERR, "Invalid line mark syntax\n");
106
7
    goto exit;
107
7
  }
108
19.9k
  hll_type = cil_strpool_add(tok.value);
109
19.9k
  if (hll_type != CIL_KEY_SRC_HLL_LME && hll_type != CIL_KEY_SRC_HLL_LMS && hll_type != CIL_KEY_SRC_HLL_LMX) {
110
7
    cil_log(CIL_ERR, "Invalid line mark syntax\n");
111
7
    goto exit;
112
7
  }
113
19.9k
  if (hll_type == CIL_KEY_SRC_HLL_LME) {
114
1.50k
    if (cil_stack_is_empty(stack)) {
115
3
      cil_log(CIL_ERR, "Line mark end without start\n");
116
3
      goto exit;
117
3
    }
118
1.49k
    prev_hll_expand = *hll_expand;
119
1.49k
    prev_hll_offset = *hll_offset;
120
1.49k
    pop_hll_info(stack, hll_offset, hll_expand);
121
1.49k
    if (!*hll_expand) {
122
      /* This is needed if not going back to an lmx section. */
123
1.19k
      *hll_offset = prev_hll_offset;
124
1.19k
    }
125
1.49k
    if (prev_hll_expand && !*hll_expand) {
126
      /* This is needed to count the lme at the end of an lmx section
127
       * within an lms section (or within no hll section).
128
       */
129
962
      (*hll_offset)++;
130
962
    }
131
1.49k
    *current = (*current)->parent;
132
18.4k
  } else {
133
18.4k
    push_hll_info(stack, *hll_offset, *hll_expand);
134
18.4k
    if (cil_stack_number_of_items(stack) > CIL_PARSER_MAX_EXPR_DEPTH) {
135
2
      cil_log(CIL_ERR, "Number of active line marks exceeds limit of %d\n", CIL_PARSER_MAX_EXPR_DEPTH);
136
2
      goto exit;
137
2
    }
138
139
18.4k
    create_node(&node, *current, tok.line, *hll_offset, NULL);
140
18.4k
    insert_node(node, *current);
141
18.4k
    *current = node;
142
143
18.4k
    create_node(&node, *current, tok.line, *hll_offset, CIL_KEY_SRC_INFO);
144
18.4k
    insert_node(node, *current);
145
146
18.4k
    create_node(&node, *current, tok.line, *hll_offset, hll_type);
147
18.4k
    insert_node(node, *current);
148
149
18.4k
    cil_lexer_next(&tok);
150
18.4k
    if (tok.type != SYMBOL) {
151
22
      cil_log(CIL_ERR, "Invalid line mark syntax\n");
152
22
      goto exit;
153
22
    }
154
155
18.3k
    create_node(&node, *current, tok.line, *hll_offset, cil_strpool_add(tok.value));
156
18.3k
    insert_node(node, *current);
157
158
18.3k
    cil_lexer_next(&tok);
159
18.3k
    if (tok.type != SYMBOL && tok.type != QSTRING) {
160
7
      cil_log(CIL_ERR, "Invalid line mark syntax\n");
161
7
      goto exit;
162
7
    }
163
164
18.3k
    if (tok.type == QSTRING) {
165
2.00k
      tok.value[strlen(tok.value) - 1] = '\0';
166
2.00k
      tok.value = tok.value+1;
167
2.00k
    }
168
169
18.3k
    create_node(&node, *current, tok.line, *hll_offset, cil_strpool_add(tok.value));
170
18.3k
    insert_node(node, *current);
171
172
18.3k
    *hll_expand = (hll_type == CIL_KEY_SRC_HLL_LMX) ? 1 : 0;
173
18.3k
  }
174
175
19.8k
  cil_lexer_next(&tok);
176
19.8k
  if (tok.type != NEWLINE) {
177
16
    cil_log(CIL_ERR, "Invalid line mark syntax\n");
178
16
    goto exit;
179
16
  }
180
181
19.8k
  if (!*hll_expand) {
182
    /* Need to increment because of the NEWLINE */
183
1.74k
    (*hll_offset)++;
184
1.74k
  }
185
186
19.8k
  return SEPOL_OK;
187
188
64
exit:
189
64
  cil_log(CIL_ERR, "Problem with high-level line mark at line %u of %s\n", tok.line, path);
190
64
  return SEPOL_ERR;
191
19.8k
}
192
193
static void add_cil_path(struct cil_tree_node **current, char *path)
194
12.9k
{
195
12.9k
  struct cil_tree_node *node;
196
197
12.9k
  create_node(&node, *current, 0, 0, NULL);
198
12.9k
  insert_node(node, *current);
199
12.9k
  *current = node;
200
201
12.9k
  create_node(&node, *current, 0, 0, CIL_KEY_SRC_INFO);
202
12.9k
  insert_node(node, *current);
203
204
12.9k
  create_node(&node, *current, 0, 0, CIL_KEY_SRC_CIL);
205
12.9k
  insert_node(node, *current);
206
207
12.9k
  create_node(&node, *current, 0, 0, cil_strpool_add("1"));
208
12.9k
  insert_node(node, *current);
209
210
12.9k
  create_node(&node, *current, 0, 0, path);
211
12.9k
  insert_node(node, *current);
212
12.9k
}
213
214
int cil_parser(const char *_path, char *buffer, uint32_t size, struct cil_tree **parse_tree)
215
12.9k
{
216
217
12.9k
  int paren_count = 0;
218
219
12.9k
  struct cil_tree *tree = NULL;
220
12.9k
  struct cil_tree_node *node = NULL;
221
12.9k
  struct cil_tree_node *current = NULL;
222
12.9k
  char *path = cil_strpool_add(_path);
223
12.9k
  struct cil_stack *stack;
224
12.9k
  uint32_t hll_offset = 1;
225
12.9k
  uint32_t hll_expand = 0;
226
12.9k
  struct token tok;
227
12.9k
  int rc = SEPOL_OK;
228
229
12.9k
  cil_stack_init(&stack);
230
231
12.9k
  cil_lexer_setup(buffer, size);
232
233
12.9k
  tree = *parse_tree;
234
12.9k
  current = tree->root;
235
236
12.9k
  add_cil_path(&current, path);
237
238
5.81M
  do {
239
5.81M
    cil_lexer_next(&tok);
240
5.81M
    switch (tok.type) {
241
19.9k
    case HLL_LINEMARK:
242
19.9k
      rc = add_hll_linemark(&current, &hll_offset, &hll_expand, stack, path);
243
19.9k
      if (rc != SEPOL_OK) {
244
64
        goto exit;
245
64
      }
246
19.8k
      break;
247
1.27M
    case OPAREN:
248
1.27M
      paren_count++;
249
1.27M
      if (paren_count > CIL_PARSER_MAX_EXPR_DEPTH) {
250
7
        cil_log(CIL_ERR, "Number of open parenthesis exceeds limit of %d at line %d of %s\n", CIL_PARSER_MAX_EXPR_DEPTH, tok.line, path);
251
7
        goto exit;
252
7
      }
253
1.27M
      create_node(&node, current, tok.line, hll_offset, NULL);
254
1.27M
      insert_node(node, current);
255
1.27M
      current = node;
256
1.27M
      break;
257
1.19M
    case CPAREN:
258
1.19M
      paren_count--;
259
1.19M
      if (paren_count < 0) {
260
9
        cil_log(CIL_ERR, "Close parenthesis without matching open at line %d of %s\n", tok.line, path);
261
9
        goto exit;
262
9
      }
263
1.19M
      current = current->parent;
264
1.19M
      break;
265
24.4k
    case QSTRING:
266
24.4k
      tok.value[strlen(tok.value) - 1] = '\0';
267
24.4k
      tok.value = tok.value+1;
268
      /* FALLTHRU */
269
2.31M
    case SYMBOL:
270
2.31M
      if (paren_count == 0) {
271
36
        cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path);
272
36
        goto exit;
273
36
      }
274
275
2.31M
      create_node(&node, current, tok.line, hll_offset, cil_strpool_add(tok.value));
276
2.31M
      insert_node(node, current);
277
2.31M
      break;
278
753k
    case NEWLINE :
279
753k
      if (!hll_expand) {
280
750k
        hll_offset++;
281
750k
      }
282
753k
      break;
283
248k
    case COMMENT:
284
10.3M
      while (tok.type != NEWLINE && tok.type != END_OF_FILE) {
285
10.0M
        cil_lexer_next(&tok);
286
10.0M
      }
287
248k
      if (!hll_expand) {
288
243k
        hll_offset++;
289
243k
      }
290
248k
      if (tok.type != END_OF_FILE) {
291
244k
        break;
292
244k
      }
293
      /* FALLTHRU */
294
      // Fall through if EOF
295
12.7k
    case END_OF_FILE:
296
12.7k
      if (paren_count > 0) {
297
191
        cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path);
298
191
        goto exit;
299
191
      }
300
12.5k
      if (!cil_stack_is_empty(stack)) {
301
19
        cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path);
302
19
        goto exit;
303
19
      }
304
12.5k
      break;
305
12.5k
    case UNKNOWN:
306
116
      cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path);
307
116
      goto exit;
308
0
    default:
309
0
      cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path);
310
0
      goto exit;
311
5.81M
    }
312
5.81M
  }
313
5.81M
  while (tok.type != END_OF_FILE);
314
315
12.5k
  cil_lexer_destroy();
316
317
12.5k
  cil_stack_destroy(&stack);
318
319
12.5k
  *parse_tree = tree;
320
321
12.5k
  return SEPOL_OK;
322
323
442
exit:
324
17.3k
  while (!cil_stack_is_empty(stack)) {
325
16.9k
    pop_hll_info(stack, &hll_offset, &hll_expand);
326
16.9k
  }
327
442
  cil_lexer_destroy();
328
442
  cil_stack_destroy(&stack);
329
330
442
  return SEPOL_ERR;
331
12.9k
}