• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

drakenclimber / libseccomp / 6029966751

09 May 2023 05:56PM UTC coverage: 89.474% (-0.3%) from 89.724%
6029966751

push

github

pcmoore
tools: update astyle config for astyle v3.2.x

It appears that '--indent-preprocessor' and
'--max-instatement-indent' are no longer supported command line
options, remove them.

Minor tweak to db_col_init() to appease astyle, no functional
changes.

Signed-off-by: Paul Moore <paul@paul-moore.com>

3 of 3 new or added lines in 1 file covered. (100.0%)

2669 of 2983 relevant lines covered (89.47%)

302128.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.56
/src/db.c
1
/**
2
 * Enhanced Seccomp Filter DB
3
 *
4
 * Copyright (c) 2012,2016,2018 Red Hat <pmoore@redhat.com>
5
 * Copyright (c) 2019 Cisco Systems, Inc. <pmoore2@cisco.com>
6
 * Copyright (c) 2022 Microsoft Corporation <paulmoore@microsoft.com>
7
 * Author: Paul Moore <paul@paul-moore.com>
8
 */
9

10
/*
11
 * This library is free software; you can redistribute it and/or modify it
12
 * under the terms of version 2.1 of the GNU Lesser General Public License as
13
 * published by the Free Software Foundation.
14
 *
15
 * This library is distributed in the hope that it will be useful, but WITHOUT
16
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
18
 * for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with this library; if not, see <http://www.gnu.org/licenses>.
22
 */
23

24
#include <assert.h>
25
#include <errno.h>
26
#include <inttypes.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <stdarg.h>
30

31
#include <seccomp.h>
32

33
#include "arch.h"
34
#include "db.h"
35
#include "system.h"
36
#include "helper.h"
37

38
/* state values */
39
#define _DB_STA_VALID                        0xA1B2C3D4
40
#define _DB_STA_FREED                        0x1A2B3C4D
41

42
/* the priority field is fairly simple - without any user hints, or in the case
43
 * of a hint "tie", we give higher priority to syscalls with less chain nodes
44
 * (filter is easier to evaluate) */
45
#define _DB_PRI_MASK_CHAIN                0x0000FFFF
46
#define _DB_PRI_MASK_USER                0x00FF0000
47
#define _DB_PRI_USER(x)                        (((x) << 16) & _DB_PRI_MASK_USER)
48

49
/* prove information about the sub-tree check results */
50
struct db_iter_state {
51
#define _DB_IST_NONE                        0x00000000
52
#define _DB_IST_MATCH                        0x00000001
53
#define _DB_IST_MATCH_ONCE                0x00000002
54
#define _DB_IST_X_FINISHED                0x00000010
55
#define _DB_IST_N_FINISHED                0x00000020
56
#define _DB_IST_X_PREFIX                0x00000100
57
#define _DB_IST_N_PREFIX                0x00000200
58
#define _DB_IST_M_MATCHSET                (_DB_IST_MATCH|_DB_IST_MATCH_ONCE)
59
#define _DB_IST_M_REDUNDANT                (_DB_IST_MATCH| \
60
                                         _DB_IST_X_FINISHED| \
61
                                         _DB_IST_N_PREFIX)
62
        unsigned int flags;
63
        uint32_t action;
64
        struct db_sys_list *sx;
65
};
66

67
static unsigned int _db_node_put(struct db_arg_chain_tree **node);
68

69
/**
70
 * Define the syscall argument priority for nodes on the same level of the tree
71
 * @param a tree node
72
 *
73
 * Prioritize the syscall argument value, taking into account hi/lo words.
74
 * Should only ever really be called by _db_chain_{lt,eq}().  Returns an
75
 * arbitrary value indicating priority.
76
 *
77
 */
78
static unsigned int __db_chain_arg_priority(const struct db_arg_chain_tree *a)
2,181,820✔
79
{
80
        return (a->arg << 1) + (a->arg_h_flg ? 1 : 0);
3,272,730✔
81
}
82

83
/**
84
 * Define the "op" priority for nodes on the same level of the tree
85
 * @param op the argument operator
86
 *
87
 * Prioritize the syscall argument comparison operator.  Should only ever
88
 * really be called by _db_chain_{lt,eq}().  Returns an arbitrary value
89
 * indicating priority.
90
 *
91
 */
92
static unsigned int __db_chain_op_priority(enum scmp_compare op)
857,544✔
93
{
94
        /* the distinction between LT/LT and GT/GE is mostly to make the
95
         * ordering as repeatable as possible regardless of the order in which
96
         * the rules are added */
97
        switch (op) {
857,544✔
98
        case SCMP_CMP_MASKED_EQ:
99
        case SCMP_CMP_EQ:
100
        case SCMP_CMP_NE:
101
                return 3;
102
        case SCMP_CMP_LE:
5,776✔
103
        case SCMP_CMP_LT:
104
                return 2;
5,776✔
105
        case SCMP_CMP_GE:
3,372✔
106
        case SCMP_CMP_GT:
107
                return 1;
3,372✔
108
        default:
×
109
                return 0;
×
110
        }
111
}
112

113
/**
114
 * Determine if node "a" is less than node "b"
115
 * @param a tree node
116
 * @param b tree node
117
 *
118
 * The logic is best explained by looking at the comparison code in the
119
 * function.
120
 *
121
 */
122
static bool _db_chain_lt(const struct db_arg_chain_tree *a,
454,326✔
123
                         const struct db_arg_chain_tree *b)
124
{
125
        unsigned int a_arg, b_arg;
454,326✔
126
        unsigned int a_op, b_op;
454,326✔
127

128
        a_arg = __db_chain_arg_priority(a);
454,326✔
129
        b_arg = __db_chain_arg_priority(b);
454,326✔
130
        if (a_arg < b_arg)
454,326✔
131
                return true;
132
        else if (a_arg > b_arg)
442,268✔
133
                return false;
134

135
        a_op = __db_chain_op_priority(a->op_orig);
428,772✔
136
        b_op = __db_chain_op_priority(b->op_orig);
428,772✔
137
        if (a_op < b_op)
428,772✔
138
                return true;
139
        else if (a_op > b_op)
428,112✔
140
                return false;
141

142
        /* NOTE: at this point the arg and op priorities are equal */
143

144
        switch (a->op_orig) {
426,428✔
145
        case SCMP_CMP_LE:
2,184✔
146
        case SCMP_CMP_LT:
147
                /* in order to ensure proper ordering for LT/LE comparisons we
148
                 * need to invert the argument value so smaller values come
149
                 * first */
150
                if (a->datum > b->datum)
2,184✔
151
                        return true;
×
152
                break;
153
        default:
424,244✔
154
                if (a->datum < b->datum)
424,244✔
155
                        return true;
394,092✔
156
                break;
157
        }
158

159
        return false;
160
}
161

162
/**
163
 * Determine if two nodes have equal argument datum values
164
 * @param a tree node
165
 * @param b tree node
166
 *
167
 * In order to return true the nodes must have the same datum and mask for the
168
 * same argument.
169
 *
170
 */
171
static bool _db_chain_eq(const struct db_arg_chain_tree *a,
636,584✔
172
                         const struct db_arg_chain_tree *b)
173
{
174
        unsigned int a_arg, b_arg;
636,584✔
175

176
        a_arg = __db_chain_arg_priority(a);
636,584✔
177
        b_arg = __db_chain_arg_priority(b);
636,584✔
178

179
        return ((a_arg == b_arg) && (a->op == b->op) &&
611,030✔
180
                (a->datum == b->datum) && (a->mask == b->mask));
1,223,990✔
181
}
182

183
/**
184
 * Determine if a given tree node is a leaf node
185
 * @param iter the node to test
186
 *
187
 * A leaf node is a node with no other nodes beneath it.
188
 *
189
 */
190
static bool _db_chain_leaf(const struct db_arg_chain_tree *iter)
11,370✔
191
{
192
        return (iter->nxt_t == NULL && iter->nxt_f == NULL);
10,278✔
193
}
194

195
/**
196
 * Determine if a given tree node is a zombie node
197
 * @param iter the node to test
198
 *
199
 * A zombie node is a leaf node that also has no true or false actions.
200
 *
201
 */
202
static bool _db_chain_zombie(const struct db_arg_chain_tree *iter)
9,152✔
203
{
204
        return (_db_chain_leaf(iter) &&
18,304✔
205
                !(iter->act_t_flg) && !(iter->act_f_flg));
9,152✔
206
}
207

208
/**
209
 * Get a node reference
210
 * @param node pointer to a node
211
 *
212
 * This function gets a reference to an individual node.  Returns a pointer
213
 * to the node.
214
 *
215
 */
216
static struct db_arg_chain_tree *_db_node_get(struct db_arg_chain_tree *node)
635,248✔
217
{
218
        if (node != NULL)
635,248✔
219
                node->refcnt++;
122,312✔
220
        return node;
572,512✔
221
}
222

223
/**
224
 * Garbage collect a level of the tree
225
 * @param node tree node
226
 *
227
 * Check the entire level on which @node resides, if there is no other part of
228
 * the tree which points to a node on this level, remove the entire level.
229
 * Returns the number of nodes removed.
230
 *
231
 */
232
static unsigned int _db_level_clean(struct db_arg_chain_tree *node)
112,970✔
233
{
234
        int cnt = 0;
112,970✔
235
        unsigned int links;
112,970✔
236
        struct db_arg_chain_tree *n = node;
112,970✔
237
        struct db_arg_chain_tree *start;
112,970✔
238

239
        while (n->lvl_prv)
121,992✔
240
                n = n->lvl_prv;
9,022✔
241
        start = n;
218,606✔
242

243
        while (n != NULL) {
218,606✔
244
                links = 0;
179,918✔
245
                if (n->lvl_prv)
179,918✔
246
                        links++;
66,948✔
247
                if (n->lvl_nxt)
179,918✔
248
                        links++;
133,896✔
249

250
                if (n->refcnt > links)
179,918✔
251
                        return cnt;
252

253
                n = n->lvl_nxt;
105,636✔
254
        }
255

256
        n = start;
38,688✔
257
        while (n != NULL)
105,636✔
258
                cnt += _db_node_put(&n);
66,948✔
259

260
        return cnt;
38,688✔
261
}
262

263
/**
264
 * Free a syscall filter argument chain tree
265
 * @param tree the argument chain list
266
 *
267
 * This function drops a reference to the tree pointed to by @tree and garbage
268
 * collects the top level.  Returns the number of nodes removed.
269
 *
270
 */
271
static unsigned int _db_tree_put(struct db_arg_chain_tree **tree)
1,132,390✔
272
{
273
        unsigned int cnt;
1,132,390✔
274

275
        cnt = _db_node_put(tree);
1,132,390✔
276
        if (*tree)
1,132,390✔
277
                cnt += _db_level_clean(*tree);
112,970✔
278

279
        return cnt;
1,132,390✔
280
}
281

282
/**
283
 * Release a node reference
284
 * @param node pointer to a node
285
 *
286
 * This function drops a reference to an individual node, unless this is the
287
 * last reference in which the entire sub-tree is affected.  Returns the number
288
 * of nodes freed.
289
 *
290
 */
291
static unsigned int _db_node_put(struct db_arg_chain_tree **node)
1,638,190✔
292
{
293
        unsigned int cnt = 0;
1,638,190✔
294
        struct db_arg_chain_tree *n = *node;
1,638,190✔
295
        struct db_arg_chain_tree *lvl_p, *lvl_n, *nxt_t, *nxt_f;
1,638,190✔
296

297
        if (n == NULL)
1,638,190✔
298
                return 0;
299

300
        if (--(n->refcnt) == 0) {
920,916✔
301
                lvl_p = n->lvl_prv;
423,560✔
302
                lvl_n = n->lvl_nxt;
423,560✔
303
                nxt_t = n->nxt_t;
423,560✔
304
                nxt_f = n->nxt_f;
423,560✔
305

306
                /* split the current level */
307
                /* NOTE: we still hold a ref for both lvl_p and lvl_n */
308
                if (lvl_p)
423,560✔
309
                        lvl_p->lvl_nxt = NULL;
×
310
                if (lvl_n)
423,560✔
311
                        lvl_n->lvl_prv = NULL;
66,948✔
312

313
                /* drop refcnts on the current level */
314
                if (lvl_p)
423,560✔
315
                        cnt += _db_node_put(&lvl_p);
×
316
                if (lvl_n)
423,560✔
317
                        cnt += _db_node_put(&lvl_n);
66,948✔
318

319
                /* re-link current level if it still exists */
320
                if (lvl_p)
423,560✔
321
                        lvl_p->lvl_nxt = _db_node_get(lvl_n);
×
322
                if (lvl_n)
423,560✔
323
                        lvl_n->lvl_prv = _db_node_get(lvl_p);
28,260✔
324

325
                /* update caller's pointer */
326
                if (lvl_p)
423,560✔
327
                        *node = lvl_p;
×
328
                else if (lvl_n)
423,560✔
329
                        *node = lvl_n;
28,260✔
330
                else
331
                        *node = NULL;
395,300✔
332

333
                /* drop the next level(s) */
334
                cnt += _db_tree_put(&nxt_t);
423,560✔
335
                cnt += _db_tree_put(&nxt_f);
423,560✔
336

337
                /* cleanup and accounting */
338
                free(n);
423,560✔
339
                cnt++;
423,560✔
340
        }
341

342
        return cnt;
343
}
344

345
/**
346
 * Remove a node from an argument chain tree
347
 * @param tree the pointer to the tree
348
 * @param node the node to remove
349
 *
350
 * This function searches the tree looking for the node and removes it as well
351
 * as any sub-trees beneath it.  Returns the number of nodes freed.
352
 *
353
 */
354
static unsigned int _db_tree_remove(struct db_arg_chain_tree **tree,
20,592✔
355
                                    struct db_arg_chain_tree *node)
356
{
357
        int cnt = 0;
20,592✔
358
        struct db_arg_chain_tree *c_iter;
20,592✔
359

360
        if (tree == NULL || *tree == NULL || node == NULL)
20,592✔
361
                return 0;
362

363
        c_iter = *tree;
11,440✔
364
        while (c_iter->lvl_prv != NULL)
11,440✔
365
                c_iter = c_iter->lvl_prv;
×
366

367
        do {
11,440✔
368
                /* current node? */
369
                if (c_iter == node)
11,440✔
370
                        goto remove;
2,288✔
371

372
                /* check the sub-trees */
373
                cnt += _db_tree_remove(&(c_iter->nxt_t), node);
9,152✔
374
                cnt += _db_tree_remove(&(c_iter->nxt_f), node);
9,152✔
375

376
                /* check for empty/zombie nodes */
377
                if (_db_chain_zombie(c_iter))
18,304✔
378
                        goto remove;
9,152✔
379

380
                /* next node on this level */
381
                c_iter = c_iter->lvl_nxt;
×
382
        } while (c_iter != NULL && cnt == 0);
×
383

384
        return cnt;
385

386
remove:
11,440✔
387
        /* reset the tree pointer if needed */
388
        if (c_iter == *tree) {
11,440✔
389
                if (c_iter->lvl_prv != NULL)
11,440✔
390
                        *tree = c_iter->lvl_prv;
×
391
                else
392
                        *tree = c_iter->lvl_nxt;
11,440✔
393
        }
394

395
        /* remove the node from the current level */
396
        if (c_iter->lvl_prv)
11,440✔
397
                c_iter->lvl_prv->lvl_nxt = c_iter->lvl_nxt;
×
398
        if (c_iter->lvl_nxt)
11,440✔
399
                c_iter->lvl_nxt->lvl_prv = c_iter->lvl_prv;
×
400
        c_iter->lvl_prv = NULL;
11,440✔
401
        c_iter->lvl_nxt = NULL;
11,440✔
402

403
        /* free the node and any sub-trees */
404
        cnt += _db_node_put(&c_iter);
11,440✔
405

406
        return cnt;
11,440✔
407
}
408

409
/**
410
 * Traverse a tree checking the action values
411
 * @param tree the pointer to the tree
412
 * @param action the action
413
 *
414
 * Traverse the tree inspecting each action to see if it matches the given
415
 * action.  Returns zero if all actions match the given action, negative values
416
 * on failure.
417
 *
418
 */
419
static int _db_tree_act_check(struct db_arg_chain_tree *tree, uint32_t action)
7,784,680✔
420
{
421
        int rc;
7,784,680✔
422
        struct db_arg_chain_tree *c_iter;
7,784,680✔
423

424
        if (tree == NULL)
7,784,680✔
425
                return 0;
426

427
        c_iter = tree;
428
        while (c_iter->lvl_prv != NULL)
3,357,510✔
429
                c_iter = c_iter->lvl_prv;
430

431
        do {
3,816,650✔
432
                if (c_iter->act_t_flg && c_iter->act_t != action)
3,816,650✔
433
                        return -EEXIST;
434
                if (c_iter->act_f_flg && c_iter->act_f != action)
3,806,200✔
435
                        return -EEXIST;
436

437
                rc = _db_tree_act_check(c_iter->nxt_t, action);
3,806,050✔
438
                if (rc < 0)
3,806,050✔
439
                        return rc;
16,220✔
440
                rc = _db_tree_act_check(c_iter->nxt_f, action);
3,789,830✔
441
                if (rc < 0)
3,789,830✔
442
                        return rc;
156✔
443

444
                c_iter = c_iter->lvl_nxt;
3,789,670✔
445
        } while (c_iter != NULL);
3,789,670✔
446

447
        return 0;
448
}
449

450
/**
451
 * Checks for a sub-tree match in an existing tree and prunes the tree
452
 * @param existing pointer to the existing tree
453
 * @param new pointer to the new tree
454
 * @param state pointer to a state structure
455
 *
456
 * This function searches the existing tree trying to prune it based on the
457
 * new tree.  Returns the number of nodes removed from the tree on success,
458
 * zero if no changes were made.
459
 *
460
 */
461
static int _db_tree_prune(struct db_arg_chain_tree **existing,
462
                          struct db_arg_chain_tree *new,
463
                          struct db_iter_state *state)
464
{
465
        int cnt = 0;
466
        struct db_iter_state state_nxt;
467
        struct db_iter_state state_new = *state;
468
        struct db_arg_chain_tree *x_iter_next;
469
        struct db_arg_chain_tree *x_iter = *existing;
470
        struct db_arg_chain_tree *n_iter = new;
471

472
        /* check if either tree is finished */
473
        if (n_iter == NULL || x_iter == NULL)
474
                goto prune_return;
475

476
        /* bail out if we have a broken match */
477
        if ((state->flags & _DB_IST_M_MATCHSET) == _DB_IST_MATCH_ONCE)
478
                goto prune_return;
479

480
        /* get to the start of the existing level */
481
        while (x_iter->lvl_prv)
482
                x_iter = x_iter->lvl_prv;
483

484
        /* NOTE: a few comments on the code below ...
485
         * 1) we need to take a reference before we go down a level in case
486
         *    we end up dropping the sub-tree (see the _db_node_get() calls)
487
         * 2) since the new tree really only has one branch, we can only ever
488
         *    match on one branch in the existing tree, if we "hit" then we
489
         *    can bail on the other branches */
490

491
        do {
492
                /* store this now in case we remove x_iter */
493
                x_iter_next = x_iter->lvl_nxt;
494

495
                /* compare the two nodes */
496
                if (_db_chain_eq(x_iter, n_iter)) {
497
                        /* we have a match */
498
                        state_new.flags |= _DB_IST_M_MATCHSET;
499

500
                        /* check if either tree is finished */
501
                        if (_db_chain_leaf(n_iter))
502
                                state_new.flags |= _DB_IST_N_FINISHED;
503
                        if (_db_chain_leaf(x_iter))
504
                                state_new.flags |= _DB_IST_X_FINISHED;
505

506
                        /* don't remove nodes if we have more actions/levels */
507
                        if ((x_iter->act_t_flg || x_iter->nxt_t) &&
508
                            !(n_iter->act_t_flg || n_iter->nxt_t))
509
                                goto prune_return;
510
                        if ((x_iter->act_f_flg || x_iter->nxt_f) &&
511
                            !(n_iter->act_f_flg || n_iter->nxt_f))
512
                                goto prune_return;
513

514
                        /* if finished, compare actions */
515
                        if ((state_new.flags & _DB_IST_N_FINISHED) &&
516
                            (state_new.flags & _DB_IST_X_FINISHED)) {
517
                                if (n_iter->act_t_flg != x_iter->act_t_flg)
518
                                        goto prune_return;
519
                                if (n_iter->act_t != x_iter->act_t)
520
                                        goto prune_return;
521

522
                                if (n_iter->act_f_flg != x_iter->act_f_flg)
523
                                        goto prune_return;
524
                                if (n_iter->act_f != x_iter->act_f)
525
                                        goto prune_return;
526
                        }
527

528
                        /* check next level */
529
                        if (n_iter->nxt_t) {
530
                                _db_node_get(x_iter);
531
                                state_nxt = *state;
532
                                state_nxt.flags |= _DB_IST_M_MATCHSET;
533
                                cnt += _db_tree_prune(&x_iter->nxt_t,
534
                                                      n_iter->nxt_t,
535
                                                      &state_nxt);
536
                                cnt += _db_node_put(&x_iter);
537
                                if (state_nxt.flags & _DB_IST_MATCH) {
538
                                        state_new.flags |= state_nxt.flags;
539
                                        /* don't return yet, we need to check
540
                                         * the current node */
541
                                }
542
                                if (x_iter == NULL)
543
                                        goto prune_next_node;
544
                        }
545
                        if (n_iter->nxt_f) {
546
                                _db_node_get(x_iter);
547
                                state_nxt = *state;
548
                                state_nxt.flags |= _DB_IST_M_MATCHSET;
549
                                cnt += _db_tree_prune(&x_iter->nxt_f,
550
                                                      n_iter->nxt_f,
551
                                                      &state_nxt);
552
                                cnt += _db_node_put(&x_iter);
553
                                if (state_nxt.flags & _DB_IST_MATCH) {
554
                                        state_new.flags |= state_nxt.flags;
555
                                        /* don't return yet, we need to check
556
                                         * the current node */
557
                                }
558
                                if (x_iter == NULL)
559
                                        goto prune_next_node;
560
                        }
561

562
                        /* remove the node? */
563
                        if (!_db_tree_act_check(x_iter, state_new.action) &&
564
                            (state_new.flags & _DB_IST_MATCH) &&
565
                            (state_new.flags & _DB_IST_N_FINISHED) &&
566
                            (state_new.flags & _DB_IST_X_PREFIX)) {
567
                                /* yes - the new tree is "shorter" */
568
                                cnt += _db_tree_remove(&state->sx->chains,
569
                                                       x_iter);
570
                                if (state->sx->chains == NULL)
571
                                        goto prune_return;
572
                        } else if (!_db_tree_act_check(x_iter, state_new.action)
573
                                   && (state_new.flags & _DB_IST_MATCH) &&
574
                                   (state_new.flags & _DB_IST_X_FINISHED) &&
575
                                   (state_new.flags & _DB_IST_N_PREFIX)) {
576
                                /* no - the new tree is "longer" */
577
                                goto prune_return;
578
                        }
579
                } else if (_db_chain_lt(x_iter, n_iter)) {
580
                        /* bail if we have a prefix on the new tree */
581
                        if (state->flags & _DB_IST_N_PREFIX)
582
                                goto prune_return;
583

584
                        /* check the next level in the existing tree */
585
                        if (x_iter->nxt_t) {
586
                                _db_node_get(x_iter);
587
                                state_nxt = *state;
588
                                state_nxt.flags &= ~_DB_IST_MATCH;
589
                                state_nxt.flags |= _DB_IST_X_PREFIX;
590
                                cnt += _db_tree_prune(&x_iter->nxt_t, n_iter,
591
                                                      &state_nxt);
592
                                cnt += _db_node_put(&x_iter);
593
                                if (state_nxt.flags & _DB_IST_MATCH) {
594
                                        state_new.flags |= state_nxt.flags;
595
                                        goto prune_return;
596
                                }
597
                                if (x_iter == NULL)
598
                                        goto prune_next_node;
599
                        }
600
                        if (x_iter->nxt_f) {
601
                                _db_node_get(x_iter);
602
                                state_nxt = *state;
603
                                state_nxt.flags &= ~_DB_IST_MATCH;
604
                                state_nxt.flags |= _DB_IST_X_PREFIX;
605
                                cnt += _db_tree_prune(&x_iter->nxt_f, n_iter,
606
                                                      &state_nxt);
607
                                cnt += _db_node_put(&x_iter);
608
                                if (state_nxt.flags & _DB_IST_MATCH) {
609
                                        state_new.flags |= state_nxt.flags;
610
                                        goto prune_return;
611
                                }
612
                                if (x_iter == NULL)
613
                                        goto prune_next_node;
614
                        }
615
                } else {
616
                        /* bail if we have a prefix on the existing tree */
617
                        if (state->flags & _DB_IST_X_PREFIX)
618
                                goto prune_return;
619

620
                        /* check the next level in the new tree */
621
                        if (n_iter->nxt_t) {
622
                                _db_node_get(x_iter);
623
                                state_nxt = *state;
624
                                state_nxt.flags &= ~_DB_IST_MATCH;
625
                                state_nxt.flags |= _DB_IST_N_PREFIX;
626
                                cnt += _db_tree_prune(&x_iter, n_iter->nxt_t,
627
                                                      &state_nxt);
628
                                cnt += _db_node_put(&x_iter);
629
                                if (state_nxt.flags & _DB_IST_MATCH) {
630
                                        state_new.flags |= state_nxt.flags;
631
                                        goto prune_return;
632
                                }
633
                                if (x_iter == NULL)
634
                                        goto prune_next_node;
635
                        }
636
                        if (n_iter->nxt_f) {
637
                                _db_node_get(x_iter);
638
                                state_nxt = *state;
639
                                state_nxt.flags &= ~_DB_IST_MATCH;
640
                                state_nxt.flags |= _DB_IST_N_PREFIX;
641
                                cnt += _db_tree_prune(&x_iter, n_iter->nxt_f,
642
                                                      &state_nxt);
643
                                cnt += _db_node_put(&x_iter);
644
                                if (state_nxt.flags & _DB_IST_MATCH) {
645
                                        state_new.flags |= state_nxt.flags;
646
                                        goto prune_return;
647
                                }
648
                                if (x_iter == NULL)
649
                                        goto prune_next_node;
650
                        }
651
                }
652

653
prune_next_node:
654
                /* check next node on this level */
655
                x_iter = x_iter_next;
656
        } while (x_iter);
657

658
        /* if we are falling through, we clearly didn't match on anything */
659
        state_new.flags &= ~_DB_IST_MATCH;
660

661
prune_return:
662
        /* no more nodes on this level, return to the level above */
663
        if (state_new.flags & _DB_IST_MATCH)
664
                state->flags |= state_new.flags;
665
        else
666
                state->flags &= ~_DB_IST_MATCH;
667
        return cnt;
668
}
669

670
/**
671
 * Add a new tree into an existing tree
672
 * @param existing pointer to the existing tree
673
 * @param new pointer to the new tree
674
 * @param state pointer to a state structure
675
 *
676
 * This function adds the new tree into the existing tree, fetching additional
677
 * references as necessary.  Returns zero on success, negative values on
678
 * failure.
679
 *
680
 */
681
static int _db_tree_add(struct db_arg_chain_tree **existing,
145,466✔
682
                        struct db_arg_chain_tree *new,
683
                        struct db_iter_state *state)
684
{
685
        int rc;
145,466✔
686
        struct db_arg_chain_tree *x_iter = *existing;
145,466✔
687
        struct db_arg_chain_tree *n_iter = new;
145,466✔
688

689
        do {
159,884✔
690
                if (_db_chain_eq(x_iter, n_iter)) {
159,884✔
691
                        if (n_iter->act_t_flg) {
78,518✔
692
                                if (!x_iter->act_t_flg) {
1,066✔
693
                                        /* new node has a true action */
694

695
                                        /* do the actions match? */
696
                                        rc = _db_tree_act_check(x_iter->nxt_t,
282✔
697
                                                                n_iter->act_t);
698
                                        if (rc != 0)
282✔
699
                                                return rc;
700

701
                                        /* update with the new action */
702
                                        rc = _db_node_put(&x_iter->nxt_t);
282✔
703
                                        x_iter->nxt_t = NULL;
282✔
704
                                        x_iter->act_t = n_iter->act_t;
282✔
705
                                        x_iter->act_t_flg = true;
282✔
706
                                        state->sx->node_cnt -= rc;
282✔
707
                                } else if (n_iter->act_t != x_iter->act_t) {
784✔
708
                                        /* if we are dealing with a 64-bit
709
                                         * comparison, we need to adjust our
710
                                         * action based on the full 64-bit
711
                                         * value to ensure we handle GT/GE
712
                                         * comparisons correctly */
713
                                        if (n_iter->arg_h_flg &&
580✔
714
                                            (n_iter->datum_full >
546✔
715
                                             x_iter->datum_full))
546✔
716
                                                x_iter->act_t = n_iter->act_t;
546✔
717
                                        if (_db_chain_leaf(x_iter) ||
1,706✔
718
                                            _db_chain_leaf(n_iter))
546✔
719
                                                return -EEXIST;
720
                                }
721
                        }
722
                        if (n_iter->act_f_flg) {
78,484✔
723
                                if (!x_iter->act_f_flg) {
5,744✔
724
                                        /* new node has a false action */
725

726
                                        /* do the actions match? */
727
                                        rc = _db_tree_act_check(x_iter->nxt_f,
5,198✔
728
                                                                n_iter->act_f);
729
                                        if (rc != 0)
5,198✔
730
                                                return rc;
731

732
                                        /* update with the new action */
733
                                        rc = _db_node_put(&x_iter->nxt_f);
5,198✔
734
                                        x_iter->nxt_f = NULL;
5,198✔
735
                                        x_iter->act_f = n_iter->act_f;
5,198✔
736
                                        x_iter->act_f_flg = true;
5,198✔
737
                                        state->sx->node_cnt -= rc;
5,198✔
738
                                } else if (n_iter->act_f != x_iter->act_f) {
546✔
739
                                        /* if we are dealing with a 64-bit
740
                                         * comparison, we need to adjust our
741
                                         * action based on the full 64-bit
742
                                         * value to ensure we handle LT/LE
743
                                         * comparisons correctly */
744
                                        if (n_iter->arg_h_flg &&
546✔
745
                                            (n_iter->datum_full <
546✔
746
                                             x_iter->datum_full))
546✔
747
                                                x_iter->act_t = n_iter->act_t;
546✔
748
                                        if (_db_chain_leaf(x_iter) ||
1,638✔
749
                                            _db_chain_leaf(n_iter))
546✔
750
                                                return -EEXIST;
751
                                }
752
                        }
753

754
                        if (n_iter->nxt_t) {
78,484✔
755
                                if (x_iter->nxt_t) {
73,936✔
756
                                        /* compare the next level */
757
                                        rc = _db_tree_add(&x_iter->nxt_t,
72,724✔
758
                                                          n_iter->nxt_t,
759
                                                          state);
760
                                        if (rc != 0)
72,724✔
761
                                                return rc;
762
                                } else if (!x_iter->act_t_flg) {
1,212✔
763
                                        /* add a new sub-tree */
764
                                        x_iter->nxt_t = _db_node_get(n_iter->nxt_t);
1,144✔
765
                                } else
766
                                        /* done - existing tree is "shorter" */
767
                                        return 0;
768
                        }
769
                        if (n_iter->nxt_f) {
78,382✔
770
                                if (x_iter->nxt_f) {
2,044✔
771
                                        /* compare the next level */
772
                                        rc = _db_tree_add(&x_iter->nxt_f,
1,636✔
773
                                                          n_iter->nxt_f,
774
                                                          state);
775
                                        if (rc != 0)
1,636✔
776
                                                return rc;
777
                                } else if (!x_iter->act_f_flg) {
408✔
778
                                        /* add a new sub-tree */
779
                                        x_iter->nxt_f = _db_node_get(n_iter->nxt_f);
136✔
780
                                } else
781
                                        /* done - existing tree is "shorter" */
782
                                        return 0;
783
                        }
784

785
                        return 0;
78,110✔
786
                } else if (!_db_chain_lt(x_iter, n_iter)) {
81,366✔
787
                        /* try to move along the current level */
788
                        if (x_iter->lvl_nxt == NULL) {
18,630✔
789
                                /* add to the end of this level */
790
                                n_iter->lvl_prv = _db_node_get(x_iter);
4,212✔
791
                                x_iter->lvl_nxt = _db_node_get(n_iter);
4,212✔
792
                                return 0;
4,212✔
793
                        } else
794
                                /* next */
795
                                x_iter = x_iter->lvl_nxt;
14,418✔
796
                } else {
797
                        /* add before the existing node on this level*/
798
                        if (x_iter->lvl_prv != NULL) {
62,736✔
799
                                x_iter->lvl_prv->lvl_nxt = _db_node_get(n_iter);
3,160✔
800
                                n_iter->lvl_prv = x_iter->lvl_prv;
3,160✔
801
                                x_iter->lvl_prv = _db_node_get(n_iter);
3,160✔
802
                                n_iter->lvl_nxt = x_iter;
3,160✔
803
                        } else {
804
                                x_iter->lvl_prv = _db_node_get(n_iter);
59,576✔
805
                                n_iter->lvl_nxt = _db_node_get(x_iter);
59,576✔
806
                        }
807
                        if (*existing == x_iter) {
62,736✔
808
                                *existing = _db_node_get(n_iter);
59,576✔
809
                                _db_node_put(&x_iter);
59,576✔
810
                        }
811
                        return 0;
62,736✔
812
                }
813
        } while (x_iter);
14,418✔
814

815
        return 0;
816
}
817

818
/**
819
 * Free and reset the seccomp filter DB
820
 * @param db the seccomp filter DB
821
 *
822
 * This function frees any existing filters and resets the filter DB to a
823
 * default state; only the DB architecture is preserved.
824
 *
825
 */
826
static void _db_reset(struct db_filter *db)
75,316✔
827
{
828
        struct db_sys_list *s_iter;
75,316✔
829
        struct db_api_rule_list *r_iter;
75,316✔
830

831
        if (db == NULL)
75,316✔
832
                return;
833

834
        /* free any filters */
835
        if (db->syscalls != NULL) {
75,316✔
836
                s_iter = db->syscalls;
837
                while (s_iter != NULL) {
242,413✔
838
                        db->syscalls = s_iter->next;
208,475✔
839
                        _db_tree_put(&s_iter->chains);
208,475✔
840
                        free(s_iter);
208,475✔
841
                        s_iter = db->syscalls;
208,475✔
842
                }
843
                db->syscalls = NULL;
33,938✔
844
        }
845
        db->syscall_cnt = 0;
75,316✔
846

847
        /* free any rules */
848
        if (db->rules != NULL) {
75,316✔
849
                /* split the loop first then loop and free */
850
                db->rules->prev->next = NULL;
34,679✔
851
                r_iter = db->rules;
34,679✔
852
                while (r_iter != NULL) {
297,634✔
853
                        db->rules = r_iter->next;
262,955✔
854
                        free(r_iter);
262,955✔
855
                        r_iter = db->rules;
262,955✔
856
                }
857
                db->rules = NULL;
34,679✔
858
        }
859
}
860

861
/**
862
 * Intitalize a seccomp filter DB
863
 * @param arch the architecture definition
864
 *
865
 * This function initializes a seccomp filter DB and readies it for use.
866
 * Returns a pointer to the DB on success, NULL on failure.
867
 *
868
 */
869
static struct db_filter *_db_init(const struct arch_def *arch)
37,658✔
870
{
871
        struct db_filter *db;
37,658✔
872

873
        db = zmalloc(sizeof(*db));
37,658✔
874
        if (db == NULL)
37,658✔
875
                return NULL;
876

877
        /* set the arch and reset the DB to a known state */
878
        db->arch = arch;
37,658✔
879
        _db_reset(db);
37,658✔
880

881
        return db;
37,658✔
882
}
883

884
/**
885
 * Destroy a seccomp filter DB
886
 * @param db the seccomp filter DB
887
 *
888
 * This function destroys a seccomp filter DB.  After calling this function,
889
 * the filter should no longer be referenced.
890
 *
891
 */
892
static void _db_release(struct db_filter *db)
37,658✔
893
{
894
        if (db == NULL)
37,658✔
895
                return;
896

897
        /* free and reset the DB */
898
        _db_reset(db);
16,058✔
899
        free(db);
32,645✔
900
}
901

902
/**
903
 * Destroy a seccomp filter snapshot
904
 * @param snap the seccomp filter snapshot
905
 *
906
 * This function destroys a seccomp filter snapshot.  After calling this
907
 * function, the snapshot should no longer be referenced.
908
 *
909
 */
910
static void _db_snap_release(struct db_filter_snap *snap)
6,392✔
911
{
912
        unsigned int iter;
6,392✔
913

914
        if (snap == NULL)
6,392✔
915
                return;
916

917
        if (snap->filter_cnt > 0) {
6,392✔
918
                for (iter = 0; iter < snap->filter_cnt; iter++) {
22,979✔
919
                        if (snap->filters[iter])
16,587✔
920
                                _db_release(snap->filters[iter]);
33,174✔
921
                }
922
                free(snap->filters);
6,392✔
923
        }
924
        free(snap);
6,392✔
925
}
926

927
/**
928
 * Update the user specified portion of the syscall priority
929
 * @param db the seccomp filter db
930
 * @param syscall the syscall number
931
 * @param priority the syscall priority
932
 *
933
 * This function sets, or updates, the syscall priority; the highest priority
934
 * value between the existing and specified value becomes the new syscall
935
 * priority.  If the syscall entry does not already exist, a new phantom
936
 * syscall entry is created as a placeholder.  Returns zero on success,
937
 * negative values on failure.
938
 *
939
 */
940
static int _db_syscall_priority(struct db_filter *db,
79✔
941
                                int syscall, uint8_t priority)
942
{
943
        unsigned int sys_pri = _DB_PRI_USER(priority);
79✔
944
        struct db_sys_list *s_new, *s_iter, *s_prev = NULL;
79✔
945

946
        assert(db != NULL);
79✔
947

948
        s_iter = db->syscalls;
79✔
949
        while (s_iter != NULL && s_iter->num < syscall) {
189✔
950
                s_prev = s_iter;
110✔
951
                s_iter = s_iter->next;
110✔
952
        }
953

954
        /* matched an existing syscall entry */
955
        if (s_iter != NULL && s_iter->num == syscall) {
79✔
956
                if (sys_pri > (s_iter->priority & _DB_PRI_MASK_USER)) {
30✔
957
                        s_iter->priority &= (~_DB_PRI_MASK_USER);
30✔
958
                        s_iter->priority |= sys_pri;
30✔
959
                }
960
                return 0;
30✔
961
        }
962

963
        /* no existing syscall entry - create a phantom entry */
964
        s_new = zmalloc(sizeof(*s_new));
49✔
965
        if (s_new == NULL)
49✔
966
                return -ENOMEM;
967
        s_new->num = syscall;
49✔
968
        s_new->priority = sys_pri;
49✔
969
        s_new->valid = false;
49✔
970

971
        /* add it before s_iter */
972
        if (s_prev != NULL) {
49✔
973
                s_new->next = s_prev->next;
29✔
974
                s_prev->next = s_new;
29✔
975
        } else {
976
                s_new->next = db->syscalls;
20✔
977
                db->syscalls = s_new;
20✔
978
        }
979

980
        return 0;
981
}
982

983
/**
984
 * Create a new rule
985
 * @param strict the strict value
986
 * @param action the rule's action
987
 * @param syscall the syscall number
988
 * @param chain the syscall argument filter
989
 *
990
 * This function creates a new rule structure based on the given arguments.
991
 * Returns a pointer to the new rule on success, NULL on failure.
992
 *
993
 */
994
static struct db_api_rule_list *_db_rule_new(bool strict,
131,833✔
995
                                             uint32_t action, int syscall,
996
                                             struct db_api_arg *chain)
997
{
998
        struct db_api_rule_list *rule;
131,833✔
999

1000
        rule = zmalloc(sizeof(*rule));
131,833✔
1001
        if (rule == NULL)
131,833✔
1002
                return NULL;
1003
        rule->action = action;
131,833✔
1004
        rule->syscall = syscall;
131,833✔
1005
        rule->strict = strict;
131,833✔
1006
        memcpy(rule->args, chain, sizeof(*chain) * ARG_COUNT_MAX);
131,833✔
1007

1008
        return rule;
131,833✔
1009
}
1010

1011
/**
1012
 * Duplicate an existing filter rule
1013
 * @param src the rule to duplicate
1014
 *
1015
 * This function makes an exact copy of the given rule, but does not add it
1016
 * to any lists.  Returns a pointer to the new rule on success, NULL on
1017
 * failure.
1018
 *
1019
 */
1020
struct db_api_rule_list *db_rule_dup(const struct db_api_rule_list *src)
420,071✔
1021
{
1022
        struct db_api_rule_list *dest;
420,071✔
1023

1024
        dest = malloc(sizeof(*dest));
420,071✔
1025
        if (dest == NULL)
420,071✔
1026
                return NULL;
1027
        memcpy(dest, src, sizeof(*dest));
420,071✔
1028
        dest->prev = NULL;
420,071✔
1029
        dest->next = NULL;
420,071✔
1030

1031
        return dest;
420,071✔
1032
}
1033

1034
/**
1035
 * Free and reset the seccomp filter collection
1036
 * @param col the seccomp filter collection
1037
 * @param def_action the default filter action
1038
 *
1039
 * This function frees any existing filter DBs and resets the collection to a
1040
 * default state.  In the case of failure the filter collection may be in an
1041
 * unknown state and should be released.  Returns zero on success, negative
1042
 * values on failure.
1043
 *
1044
 */
1045
int db_col_reset(struct db_filter_col *col, uint32_t def_action)
8,187✔
1046
{
1047
        unsigned int iter;
8,187✔
1048
        struct db_filter *db;
8,187✔
1049
        struct db_filter_snap *snap;
8,187✔
1050

1051
        if (col == NULL)
8,187✔
1052
                return -EINVAL;
1053

1054
        /* free any filters */
1055
        for (iter = 0; iter < col->filter_cnt; iter++)
8,552✔
1056
                _db_release(col->filters[iter]);
730✔
1057
        col->filter_cnt = 0;
8,187✔
1058
        if (col->filters)
8,187✔
1059
                free(col->filters);
365✔
1060
        col->filters = NULL;
8,187✔
1061

1062
        /* set the endianness to undefined */
1063
        col->endian = 0;
8,187✔
1064

1065
        /* set the default attribute values */
1066
        col->attr.act_default = def_action;
8,187✔
1067
        col->attr.act_badarch = SCMP_ACT_KILL;
8,187✔
1068
        col->attr.nnp_enable = 1;
8,187✔
1069
        col->attr.tsync_enable = 0;
8,187✔
1070
        col->attr.api_tskip = 0;
8,187✔
1071
        col->attr.log_enable = 0;
8,187✔
1072
        col->attr.spec_allow = 0;
8,187✔
1073
        col->attr.optimize = 1;
8,187✔
1074
        col->attr.api_sysrawrc = 0;
8,187✔
1075
        col->attr.wait_killable_recv = 0;
8,187✔
1076

1077
        /* set the state */
1078
        col->state = _DB_STA_VALID;
8,187✔
1079
        if (def_action == SCMP_ACT_NOTIFY)
8,187✔
1080
                col->notify_used = true;
×
1081
        else
1082
                col->notify_used = false;
8,187✔
1083

1084
        /* reset the initial db */
1085
        db = _db_init(arch_def_native);
8,187✔
1086
        if (db == NULL)
8,187✔
1087
                return -ENOMEM;
1088
        if (db_col_db_add(col, db) < 0) {
8,187✔
1089
                _db_release(db);
×
1090
                return -ENOMEM;
×
1091
        }
1092

1093
        /* reset the transactions */
1094
        while (col->snapshots) {
8,552✔
1095
                snap = col->snapshots;
365✔
1096
                col->snapshots = snap->next;
365✔
1097
                for (iter = 0; iter < snap->filter_cnt; iter++)
730✔
1098
                        _db_release(snap->filters[iter]);
730✔
1099
                free(snap->filters);
365✔
1100
                free(snap);
365✔
1101
        }
1102

1103
        /* reset the precomputed programs */
1104
        db_col_precompute_reset(col);
16,374✔
1105

1106
        return 0;
1107
}
1108

1109
/**
1110
 * Intitalize a seccomp filter collection
1111
 * @param def_action the default filter action
1112
 *
1113
 * This function initializes a seccomp filter collection and readies it for
1114
 * use.  Returns a pointer to the collection on success, NULL on failure.
1115
 *
1116
 */
1117
struct db_filter_col *db_col_init(uint32_t def_action)
7,822✔
1118
{
1119
        struct db_filter_col *col;
7,822✔
1120

1121
        col = zmalloc(sizeof(*col));
7,822✔
1122
        if (col == NULL)
7,822✔
1123
                return NULL;
1124

1125
        /* reset the DB to a known state */
1126
        if (db_col_reset(col, def_action) < 0) {
7,822✔
1127
                db_col_release(col);
×
1128
                return NULL;
×
1129
        }
1130

1131
        return col;
1132
}
1133

1134
/**
1135
 * Destroy a seccomp filter collection
1136
 * @param col the seccomp filter collection
1137
 *
1138
 * This function destroys a seccomp filter collection.  After calling this
1139
 * function, the filter should no longer be referenced.
1140
 *
1141
 */
1142
void db_col_release(struct db_filter_col *col)
7,822✔
1143
{
1144
        unsigned int iter;
7,822✔
1145
        struct db_filter_snap *snap;
7,822✔
1146

1147
        if (col == NULL)
7,822✔
1148
                return;
1149

1150
        /* set the state, just in case */
1151
        col->state = _DB_STA_FREED;
7,822✔
1152

1153
        /* free any snapshots */
1154
        while (col->snapshots != NULL) {
14,214✔
1155
                snap = col->snapshots;
6,392✔
1156
                col->snapshots = snap->next;
6,392✔
1157
                _db_snap_release(snap);
6,392✔
1158
        }
1159

1160
        /* free any filters */
1161
        for (iter = 0; iter < col->filter_cnt; iter++)
22,737✔
1162
                _db_release(col->filters[iter]);
29,830✔
1163
        col->filter_cnt = 0;
7,822✔
1164
        if (col->filters)
7,822✔
1165
                free(col->filters);
7,822✔
1166
        col->filters = NULL;
7,822✔
1167

1168
        /* free any precompute */
1169
        db_col_precompute_reset(col);
15,644✔
1170

1171
        /* free the collection */
1172
        free(col);
7,822✔
1173
}
1174

1175
/**
1176
 * Validate a filter collection
1177
 * @param col the seccomp filter collection
1178
 *
1179
 * This function validates a seccomp filter collection.  Returns zero if the
1180
 * collection is valid, negative values on failure.
1181
 *
1182
 */
1183
int db_col_valid(struct db_filter_col *col)
61,621✔
1184
{
1185
        if (col != NULL && col->state == _DB_STA_VALID && col->filter_cnt > 0)
61,621✔
1186
                return 0;
61,613✔
1187
        return -EINVAL;
1188
}
1189

1190
/**
1191
 * Validate the seccomp action
1192
 * @param col the seccomp filter collection
1193
 * @param action the seccomp action
1194
 *
1195
 * Verify that the given action is a valid seccomp action; return zero if
1196
 * valid, -EINVAL if invalid.
1197
 */
1198
int db_col_action_valid(const struct db_filter_col *col, uint32_t action)
61,309✔
1199
{
1200
        if (col != NULL) {
61,309✔
1201
                /* NOTE: in some cases we don't have a filter collection yet,
1202
                 *       but when we do we need to do the following checks */
1203

1204
                /* kernel disallows TSYNC and NOTIFY in one filter unless we
1205
                 * have the TSYNC_ESRCH flag */
1206
                if (sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH) < 1 &&
53,121✔
1207
                    col->attr.tsync_enable && action == SCMP_ACT_NOTIFY)
2,152✔
1208
                        return -EINVAL;
1209
        }
1210

1211
        if (sys_chk_seccomp_action(action) == 1)
61,309✔
1212
                return 0;
61,305✔
1213
        return -EINVAL;
1214
}
1215

1216
/**
1217
 * Merge two filter collections
1218
 * @param col_dst the destination filter collection
1219
 * @param col_src the source filter collection
1220
 *
1221
 * This function merges two filter collections into the given destination
1222
 * collection.  The source filter collection is no longer valid if the function
1223
 * returns successfully.  Returns zero on success, negative values on failure.
1224
 *
1225
 */
1226
int db_col_merge(struct db_filter_col *col_dst, struct db_filter_col *col_src)
26✔
1227
{
1228
        unsigned int iter_a, iter_b;
26✔
1229
        struct db_filter **dbs;
26✔
1230

1231
        /* verify that the endianness is a match */
1232
        if (col_dst->endian != col_src->endian)
26✔
1233
                return -EDOM;
1234

1235
        /* make sure we don't have any arch/filter collisions */
1236
        for (iter_a = 0; iter_a < col_dst->filter_cnt; iter_a++) {
52✔
1237
                for (iter_b = 0; iter_b < col_src->filter_cnt; iter_b++) {
52✔
1238
                        if (col_dst->filters[iter_a]->arch->token ==
26✔
1239
                            col_src->filters[iter_b]->arch->token)
26✔
1240
                                return -EEXIST;
1241
                }
1242
        }
1243

1244
        /* expand the destination */
1245
        dbs = realloc(col_dst->filters,
26✔
1246
                      sizeof(struct db_filter *) *
1247
                      (col_dst->filter_cnt + col_src->filter_cnt));
26✔
1248
        if (dbs == NULL)
26✔
1249
                return -ENOMEM;
1250
        col_dst->filters = dbs;
26✔
1251

1252
        /* transfer the architecture filters */
1253
        for (iter_a = col_dst->filter_cnt, iter_b = 0;
26✔
1254
             iter_b < col_src->filter_cnt; iter_a++, iter_b++) {
52✔
1255
                col_dst->filters[iter_a] = col_src->filters[iter_b];
26✔
1256
                col_dst->filter_cnt++;
26✔
1257
        }
1258

1259
        /* reset the precompute */
1260
        db_col_precompute_reset(col_dst);
52✔
1261

1262
        /* free the source */
1263
        col_src->filter_cnt = 0;
26✔
1264
        db_col_release(col_src);
26✔
1265

1266
        return 0;
26✔
1267
}
1268

1269
/**
1270
 * Check to see if an architecture filter exists in the filter collection
1271
 * @param col the seccomp filter collection
1272
 * @param arch_token the architecture token
1273
 *
1274
 * Iterate through the given filter collection checking to see if a filter
1275
 * exists for the specified architecture.  Returns -EEXIST if a filter is found,
1276
 * zero if a matching filter does not exist.
1277
 *
1278
 */
1279
int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token)
37,976✔
1280
{
1281
        unsigned int iter;
37,976✔
1282

1283
        for (iter = 0; iter < col->filter_cnt; iter++)
153,969✔
1284
                if (col->filters[iter]->arch->token == arch_token)
121,288✔
1285
                        return -EEXIST;
1286

1287
        return 0;
1288
}
1289

1290
/**
1291
 * Get a filter attribute
1292
 * @param col the seccomp filter collection
1293
 * @param attr the filter attribute
1294
 * @param value the filter attribute value
1295
 *
1296
 * Get the requested filter attribute and provide it via @value.  Returns zero
1297
 * on success, negative values on failure.
1298
 *
1299
 */
1300
int db_col_attr_get(const struct db_filter_col *col,
15✔
1301
                    enum scmp_filter_attr attr, uint32_t *value)
1302
{
1303
        int rc = 0;
15✔
1304

1305
        switch (attr) {
15✔
1306
        case SCMP_FLTATR_ACT_DEFAULT:
1✔
1307
                *value = col->attr.act_default;
1✔
1308
                break;
1✔
1309
        case SCMP_FLTATR_ACT_BADARCH:
1✔
1310
                *value = col->attr.act_badarch;
1✔
1311
                break;
1✔
1312
        case SCMP_FLTATR_CTL_NNP:
1✔
1313
                *value = col->attr.nnp_enable;
1✔
1314
                break;
1✔
1315
        case SCMP_FLTATR_CTL_TSYNC:
1✔
1316
                *value = col->attr.tsync_enable;
1✔
1317
                break;
1✔
1318
        case SCMP_FLTATR_API_TSKIP:
1✔
1319
                *value = col->attr.api_tskip;
1✔
1320
                break;
1✔
1321
        case SCMP_FLTATR_CTL_LOG:
1✔
1322
                *value = col->attr.log_enable;
1✔
1323
                break;
1✔
1324
        case SCMP_FLTATR_CTL_SSB:
1✔
1325
                *value = col->attr.spec_allow;
1✔
1326
                break;
1✔
1327
        case SCMP_FLTATR_CTL_OPTIMIZE:
1✔
1328
                *value = col->attr.optimize;
1✔
1329
                break;
1✔
1330
        case SCMP_FLTATR_API_SYSRAWRC:
5✔
1331
                *value = col->attr.api_sysrawrc;
5✔
1332
                break;
5✔
1333
        case SCMP_FLTATR_CTL_WAITKILL:
1✔
1334
                *value = col->attr.wait_killable_recv;
1✔
1335
                break;
1✔
1336
        default:
1337
                rc = -EINVAL;
1338
                break;
1339
        }
1340

1341
        return rc;
15✔
1342
}
1343

1344
/**
1345
 * Get a filter attribute
1346
 * @param col the seccomp filter collection
1347
 * @param attr the filter attribute
1348
 *
1349
 * Returns the requested filter attribute value with zero on any error.
1350
 * Special care must be given with this function as error conditions can be
1351
 * hidden from the caller.
1352
 *
1353
 */
1354
uint32_t db_col_attr_read(const struct db_filter_col *col,
4✔
1355
                          enum scmp_filter_attr attr)
1356
{
1357
        uint32_t value = 0;
4✔
1358

1359
        db_col_attr_get(col, attr, &value);
4✔
1360
        return value;
4✔
1361
}
1362

1363
/**
1364
 * Set a filter attribute
1365
 * @param col the seccomp filter collection
1366
 * @param attr the filter attribute
1367
 * @param value the filter attribute value
1368
 *
1369
 * Set the requested filter attribute with the given value.  Returns zero on
1370
 * success, negative values on failure.
1371
 *
1372
 */
1373
int db_col_attr_set(struct db_filter_col *col,
529✔
1374
                    enum scmp_filter_attr attr, uint32_t value)
1375
{
1376
        int rc = 0;
529✔
1377

1378
        switch (attr) {
529✔
1379
        case SCMP_FLTATR_ACT_DEFAULT:
1380
                /* read only */
1381
                return -EACCES;
1382
                break;
1✔
1383
        case SCMP_FLTATR_ACT_BADARCH:
1✔
1384
                if (db_col_action_valid(col, value) == 0)
1✔
1385
                        col->attr.act_badarch = value;
1✔
1386
                else
1387
                        return -EINVAL;
1388
                db_col_precompute_reset(col);
530✔
1389
                break;
1390
        case SCMP_FLTATR_CTL_NNP:
1✔
1391
                col->attr.nnp_enable = (value ? 1 : 0);
1✔
1392
                break;
1✔
1393
        case SCMP_FLTATR_CTL_TSYNC:
2✔
1394
                rc = sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC);
2✔
1395
                if (rc == 1) {
2✔
1396
                        /* supported */
1397
                        rc = 0;
2✔
1398
                        /* kernel disallows TSYNC and NOTIFY in one filter
1399
                         * unless we have TSYNC_ESRCH */
1400
                        if (sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH) < 1 &&
2✔
1401
                            value && col->notify_used)
1✔
1402
                                return -EINVAL;
1403
                        col->attr.tsync_enable = (value ? 1 : 0);
2✔
1404
                } else if (rc == 0)
×
1405
                        /* unsupported */
1406
                        rc = -EOPNOTSUPP;
×
1407
                break;
1408
        case SCMP_FLTATR_API_TSKIP:
4✔
1409
                col->attr.api_tskip = (value ? 1 : 0);
4✔
1410
                db_col_precompute_reset(col);
533✔
1411
                break;
1412
        case SCMP_FLTATR_CTL_LOG:
2✔
1413
                rc = sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_LOG);
2✔
1414
                if (rc == 1) {
2✔
1415
                        /* supported */
1416
                        rc = 0;
2✔
1417
                        col->attr.log_enable = (value ? 1 : 0);
2✔
1418
                } else if (rc == 0) {
×
1419
                        /* unsupported */
1420
                        rc = -EOPNOTSUPP;
×
1421
                }
1422
                break;
1423
        case SCMP_FLTATR_CTL_SSB:
2✔
1424
                rc = sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW);
2✔
1425
                if (rc == 1) {
2✔
1426
                        /* supported */
1427
                        rc = 0;
2✔
1428
                        col->attr.spec_allow = (value ? 1 : 0);
2✔
1429
                } else if (rc == 0) {
×
1430
                        /* unsupported */
1431
                        rc = -EOPNOTSUPP;
×
1432
                }
1433
                break;
1434
        case SCMP_FLTATR_CTL_OPTIMIZE:
512✔
1435
                switch (value) {
512✔
1436
                case 1:
512✔
1437
                case 2:
1438
                        col->attr.optimize = value;
512✔
1439
                        break;
512✔
1440
                default:
1441
                        rc = -EOPNOTSUPP;
1442
                        break;
1443
                }
1444
                db_col_precompute_reset(col);
1,041✔
1445
                break;
1446
        case SCMP_FLTATR_API_SYSRAWRC:
2✔
1447
                col->attr.api_sysrawrc = (value ? 1 : 0);
2✔
1448
                break;
2✔
1449
        case SCMP_FLTATR_CTL_WAITKILL:
1✔
1450
                col->attr.wait_killable_recv = (value ? 1 : 0);
1✔
1451
                break;
1✔
1452
        default:
1453
                rc = -EINVAL;
1454
                break;
1455
        }
1456

1457
        return rc;
1458
}
1459

1460
/**
1461
 * Add a new architecture filter to a filter collection
1462
 * @param col the seccomp filter collection
1463
 * @param arch the architecture
1464
 *
1465
 * This function adds a new architecture filter DB to an existing seccomp
1466
 * filter collection assuming there isn't a filter DB already present with the
1467
 * same architecture.  Returns zero on success, negative values on failure.
1468
 *
1469
 */
1470
int db_col_db_new(struct db_filter_col *col, const struct arch_def *arch)
12,106✔
1471
{
1472
        int rc;
12,106✔
1473
        struct db_filter *db;
12,106✔
1474

1475
        db = _db_init(arch);
12,106✔
1476
        if (db == NULL)
12,106✔
1477
                return -ENOMEM;
1478
        rc = db_col_db_add(col, db);
12,106✔
1479
        if (rc < 0)
12,106✔
1480
                _db_release(db);
×
1481
        else
1482
                db_col_precompute_reset(col);
24,212✔
1483

1484
        return rc;
1485
}
1486

1487
/**
1488
 * Add a new filter DB to a filter collection
1489
 * @param col the seccomp filter collection
1490
 * @param db the seccomp filter DB
1491
 *
1492
 * This function adds an existing seccomp filter DB to an existing seccomp
1493
 * filter collection assuming there isn't a filter DB already present with the
1494
 * same architecture.  Returns zero on success, negative values on failure.
1495
 *
1496
 */
1497
int db_col_db_add(struct db_filter_col *col, struct db_filter *db)
20,293✔
1498
{
1499
        struct db_filter **dbs;
20,293✔
1500

1501
        if (col->endian != 0 && col->endian != db->arch->endian)
20,293✔
1502
                return -EDOM;
1503

1504
        if (db_col_arch_exist(col, db->arch->token))
40,586✔
1505
                return -EEXIST;
1506

1507
        dbs = realloc(col->filters,
20,293✔
1508
                      sizeof(struct db_filter *) * (col->filter_cnt + 1));
20,293✔
1509
        if (dbs == NULL)
20,293✔
1510
                return -ENOMEM;
1511
        col->filters = dbs;
20,293✔
1512
        col->filter_cnt++;
20,293✔
1513
        col->filters[col->filter_cnt - 1] = db;
20,293✔
1514
        if (col->endian == 0)
20,293✔
1515
                col->endian = db->arch->endian;
10,098✔
1516

1517
        return 0;
1518
}
1519

1520
/**
1521
 * Remove a filter DB from a filter collection
1522
 * @param col the seccomp filter collection
1523
 * @param arch_token the architecture token
1524
 *
1525
 * This function removes an existing seccomp filter DB from an existing seccomp
1526
 * filter collection.  Returns zero on success, negative values on failure.
1527
 *
1528
 */
1529
int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token)
5,013✔
1530
{
1531
        unsigned int iter;
5,013✔
1532
        unsigned int found;
5,013✔
1533
        struct db_filter **dbs;
5,013✔
1534

1535
        if ((col->filter_cnt <= 0) || (db_col_arch_exist(col, arch_token) == 0))
10,026✔
1536
                return -EINVAL;
1537

1538
        for (found = 0, iter = 0; iter < col->filter_cnt; iter++) {
28,638✔
1539
                if (found)
23,625✔
1540
                        col->filters[iter - 1] = col->filters[iter];
18,612✔
1541
                else if (col->filters[iter]->arch->token == arch_token) {
5,013✔
1542
                        _db_release(col->filters[iter]);
5,013✔
1543
                        found = 1;
5,013✔
1544
                }
1545
        }
1546
        col->filters[--col->filter_cnt] = NULL;
5,013✔
1547

1548
        if (col->filter_cnt > 0) {
5,013✔
1549
                /* NOTE: if we can't do the realloc it isn't fatal, we just
1550
                 *       have some extra space allocated */
1551
                dbs = realloc(col->filters,
3,102✔
1552
                              sizeof(struct db_filter *) * col->filter_cnt);
1553
                if (dbs != NULL)
3,102✔
1554
                        col->filters = dbs;
3,102✔
1555
        } else {
1556
                /* this was the last filter so free all the associated memory
1557
                 * and reset the endian token */
1558
                free(col->filters);
1,911✔
1559
                col->filters = NULL;
1,911✔
1560
                col->endian = 0;
1,911✔
1561
        }
1562

1563
        db_col_precompute_reset(col);
10,026✔
1564

1565
        return 0;
1566
}
1567

1568
/**
1569
 * Test if the argument filter can be skipped because it's a tautology
1570
 * @param arg argument filter
1571
 *
1572
 * If this argument filter applied to the lower 32 bit can be skipped this
1573
 * function returns false.
1574
 *
1575
 */
1576
static bool _db_arg_cmp_need_lo(const struct db_api_arg *arg)
61,776✔
1577
{
1578
        if (arg->op == SCMP_CMP_MASKED_EQ && D64_LO(arg->mask) == 0)
12✔
1579
                return false;
68✔
1580

1581
        return true;
1582
}
1583

1584
/**
1585
 * Test if the argument filter can be skipped because it's a tautology
1586
 * @param arg argument filter
1587
 *
1588
 * If this argument filter applied to the upper 32 bit can be skipped this
1589
 * function returns false.
1590
 *
1591
 */
1592
static bool _db_arg_cmp_need_hi(const struct db_api_arg *arg)
183,082✔
1593
{
1594
        if (arg->op == SCMP_CMP_MASKED_EQ && D64_HI(arg->mask) == 0)
11,356✔
1595
                return false;
11,356✔
1596

1597
        return true;
1598
}
1599

1600
/**
1601
 * Fixup the node based on the op/mask
1602
 * @param node the chain node
1603
 *
1604
 * Ensure the datum is masked as well.
1605
 *
1606
 */
1607
static void _db_node_mask_fixup(struct db_arg_chain_tree *node)
233,434✔
1608
{
1609
        node->datum &= node->mask;
233,434✔
1610
}
1611

1612
/**
1613
 * Generate a new filter rule for a 64 bit system
1614
 * @param arch the architecture definition
1615
 * @param rule the new filter rule
1616
 *
1617
 * This function generates a new syscall filter for a 64 bit system. Returns
1618
 * zero on success, negative values on failure.
1619
 *
1620
 */
1621
static struct db_sys_list *_db_rule_gen_64(const struct arch_def *arch,
191,906✔
1622
                                           const struct db_api_rule_list *rule)
1623
{
1624
        unsigned int iter;
191,906✔
1625
        struct db_sys_list *s_new;
191,906✔
1626
        const struct db_api_arg *chain = rule->args;
191,906✔
1627
        struct db_arg_chain_tree *c_iter[3] = { NULL, NULL, NULL };
191,906✔
1628
        struct db_arg_chain_tree *c_prev[3] = { NULL, NULL, NULL };
191,906✔
1629
        enum scmp_compare op_prev = _SCMP_CMP_MIN;
191,906✔
1630
        unsigned int arg;
191,906✔
1631
        scmp_datum_t mask;
191,906✔
1632
        scmp_datum_t datum;
191,906✔
1633

1634
        s_new = zmalloc(sizeof(*s_new));
191,906✔
1635
        if (s_new == NULL)
191,906✔
1636
                return NULL;
1637
        s_new->num = rule->syscall;
191,906✔
1638
        s_new->valid = true;
191,906✔
1639
        /* run through the argument chain */
1640
        for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
1,343,340✔
1641
                if (chain[iter].valid == 0)
1,151,440✔
1642
                        continue;
968,354✔
1643

1644
                /* TODO: handle the case were either hi or lo isn't needed */
1645

1646
                /* skip generating instruction which are no-ops */
1647
                if (!_db_arg_cmp_need_hi(&chain[iter]) &&
183,082✔
1648
                    !_db_arg_cmp_need_lo(&chain[iter]))
11,356✔
1649
                        continue;
68✔
1650

1651
                c_iter[0] = zmalloc(sizeof(*c_iter[0]));
183,014✔
1652
                if (c_iter[0] == NULL)
183,014✔
1653
                        goto gen_64_failure;
×
1654
                c_iter[1] = zmalloc(sizeof(*c_iter[1]));
183,014✔
1655
                if (c_iter[1] == NULL) {
183,014✔
1656
                        free(c_iter[0]);
×
1657
                        goto gen_64_failure;
×
1658
                }
1659
                c_iter[2] = NULL;
183,014✔
1660

1661
                arg = chain[iter].arg;
183,014✔
1662
                mask = chain[iter].mask;
183,014✔
1663
                datum = chain[iter].datum;
183,014✔
1664

1665
                /* NOTE: with the idea that a picture is worth a thousand
1666
                 *       words, i'm presenting the following diagrams which
1667
                 *       show how we should compare 64-bit syscall arguments
1668
                 *       using 32-bit comparisons.
1669
                 *
1670
                 *       in the diagrams below "A(x)" is the syscall argument
1671
                 *       being evaluated and "R(x)" is the syscall argument
1672
                 *       value specified in the libseccomp rule.  the "ACCEPT"
1673
                 *       verdict indicates a rule match and processing should
1674
                 *       continue on to the rest of the rule, or the final rule
1675
                 *       action should be triggered.  the "REJECT" verdict
1676
                 *       indicates that the rule does not match and processing
1677
                 *       should continue to the next rule or the default
1678
                 *       action.
1679
                 *
1680
                 * SCMP_CMP_GT:
1681
                 *                   +------------------+
1682
                 *                +--|  Ah(x) >  Rh(x)  |------+
1683
                 *                |  +------------------+      |
1684
                 *              FALSE                         TRUE     A
1685
                 *                |                            |       C
1686
                 *                +-----------+                +---->  C
1687
                 *                            v                +---->  E
1688
                 *                   +------------------+      |       P
1689
                 *                +--|  Ah(x) == Rh(x)  |--+   |       T
1690
                 *        R       |  +------------------+  |   |
1691
                 *        E     FALSE                     TRUE |
1692
                 *        J  <----+                        |   |
1693
                 *        E  <----+           +------------+   |
1694
                 *        C     FALSE         v                |
1695
                 *        T       |  +------------------+      |
1696
                 *                +--|  Al(x) >  Rl(x)  |------+
1697
                 *                   +------------------+
1698
                 *
1699
                 * SCMP_CMP_GE:
1700
                 *                   +------------------+
1701
                 *                +--|  Ah(x) >  Rh(x)  |------+
1702
                 *                |  +------------------+      |
1703
                 *              FALSE                         TRUE     A
1704
                 *                |                            |       C
1705
                 *                +-----------+                +---->  C
1706
                 *                            v                +---->  E
1707
                 *                   +------------------+      |       P
1708
                 *                +--|  Ah(x) == Rh(x)  |--+   |       T
1709
                 *        R       |  +------------------+  |   |
1710
                 *        E     FALSE                     TRUE |
1711
                 *        J  <----+                        |   |
1712
                 *        E  <----+           +------------+   |
1713
                 *        C     FALSE         v                |
1714
                 *        T       |  +------------------+      |
1715
                 *                +--|  Al(x) >= Rl(x)  |------+
1716
                 *                   +------------------+
1717
                 *
1718
                 * SCMP_CMP_LT:
1719
                 *                   +------------------+
1720
                 *                +--|  Ah(x) >  Rh(x)  |------+
1721
                 *                |  +------------------+      |
1722
                 *              FALSE                         TRUE     R
1723
                 *                |                            |       E
1724
                 *                +-----------+                +---->  J
1725
                 *                            v                +---->  E
1726
                 *                   +------------------+      |       C
1727
                 *                +--|  Ah(x) == Rh(x)  |--+   |       T
1728
                 *        A       |  +------------------+  |   |
1729
                 *        C     FALSE                     TRUE |
1730
                 *        C  <----+                        |   |
1731
                 *        E  <----+           +------------+   |
1732
                 *        P     FALSE         v                |
1733
                 *        T       |  +------------------+      |
1734
                 *                +--|  Al(x) >= Rl(x)  |------+
1735
                 *                   +------------------+
1736
                 *
1737
                 * SCMP_CMP_LE:
1738
                 *                   +------------------+
1739
                 *                +--|  Ah(x) >  Rh(x)  |------+
1740
                 *                |  +------------------+      |
1741
                 *              FALSE                         TRUE     R
1742
                 *                |                            |       E
1743
                 *                +-----------+                +---->  J
1744
                 *                            v                +---->  E
1745
                 *                   +------------------+      |       C
1746
                 *                +--|  Ah(x) == Rh(x)  |--+   |       T
1747
                 *        A       |  +------------------+  |   |
1748
                 *        C     FALSE                     TRUE |
1749
                 *        C  <----+                        |   |
1750
                 *        E  <----+           +------------+   |
1751
                 *        P     FALSE         v                |
1752
                 *        T       |  +------------------+      |
1753
                 *                +--|  Al(x) >  Rl(x)  |------+
1754
                 *                   +------------------+
1755
                 *
1756
                 * SCMP_CMP_EQ:
1757
                 *                   +------------------+
1758
                 *                +--|  Ah(x) == Rh(x)  |--+
1759
                 *        R       |  +------------------+  |           A
1760
                 *        E     FALSE                     TRUE         C
1761
                 *        J  <----+                        |           C
1762
                 *        E  <----+           +------------+   +---->  E
1763
                 *        C     FALSE         v                |       P
1764
                 *        T       |  +------------------+      |       T
1765
                 *                +--|  Al(x) == Rl(x)  |------+
1766
                 *                   +------------------+
1767
                 *
1768
                 * SCMP_CMP_NE:
1769
                 *                   +------------------+
1770
                 *                +--|  Ah(x) == Rh(x)  |--+
1771
                 *        A       |  +------------------+  |           R
1772
                 *        C     FALSE                     TRUE         E
1773
                 *        C  <----+                        |           J
1774
                 *        E  <----+           +------------+   +---->  E
1775
                 *        P     FALSE         v                |       C
1776
                 *        T       |  +------------------+      |       T
1777
                 *                +--|  Al(x) == Rl(x)  |------+
1778
                 *                   +------------------+
1779
                 *
1780
                 */
1781

1782
                /* setup the level */
1783
                switch (chain[iter].op) {
183,014✔
1784
                case SCMP_CMP_GT:
7,112✔
1785
                case SCMP_CMP_GE:
1786
                case SCMP_CMP_LE:
1787
                case SCMP_CMP_LT:
1788
                        c_iter[2] = zmalloc(sizeof(*c_iter[2]));
7,112✔
1789
                        if (c_iter[2] == NULL) {
7,112✔
1790
                                free(c_iter[0]);
×
1791
                                free(c_iter[1]);
×
1792
                                goto gen_64_failure;
×
1793
                        }
1794

1795
                        c_iter[0]->arg = arg;
7,112✔
1796
                        c_iter[1]->arg = arg;
7,112✔
1797
                        c_iter[2]->arg = arg;
7,112✔
1798
                        c_iter[0]->arg_h_flg = true;
7,112✔
1799
                        c_iter[1]->arg_h_flg = true;
7,112✔
1800
                        c_iter[2]->arg_h_flg = false;
7,112✔
1801
                        c_iter[0]->arg_offset = arch_arg_offset_hi(arch, arg);
7,112✔
1802
                        c_iter[1]->arg_offset = arch_arg_offset_hi(arch, arg);
7,112✔
1803
                        c_iter[2]->arg_offset = arch_arg_offset_lo(arch, arg);
7,112✔
1804

1805
                        c_iter[0]->mask = D64_HI(mask);
7,112✔
1806
                        c_iter[1]->mask = D64_HI(mask);
7,112✔
1807
                        c_iter[2]->mask = D64_LO(mask);
7,112✔
1808
                        c_iter[0]->datum = D64_HI(datum);
7,112✔
1809
                        c_iter[1]->datum = D64_HI(datum);
7,112✔
1810
                        c_iter[2]->datum = D64_LO(datum);
7,112✔
1811
                        c_iter[0]->datum_full = datum;
7,112✔
1812
                        c_iter[1]->datum_full = datum;
7,112✔
1813
                        c_iter[2]->datum_full = datum;
7,112✔
1814

1815
                        _db_node_mask_fixup(c_iter[0]);
7,112✔
1816
                        _db_node_mask_fixup(c_iter[1]);
7,112✔
1817
                        _db_node_mask_fixup(c_iter[2]);
7,112✔
1818

1819
                        c_iter[0]->op = SCMP_CMP_GT;
7,112✔
1820
                        c_iter[1]->op = SCMP_CMP_EQ;
7,112✔
1821
                        switch (chain[iter].op) {
7,112✔
1822
                        case SCMP_CMP_GT:
774✔
1823
                        case SCMP_CMP_LE:
1824
                                c_iter[2]->op = SCMP_CMP_GT;
774✔
1825
                                break;
774✔
1826
                        case SCMP_CMP_GE:
6,338✔
1827
                        case SCMP_CMP_LT:
1828
                                c_iter[2]->op = SCMP_CMP_GE;
6,338✔
1829
                                break;
6,338✔
1830
                        default:
×
1831
                                /* we should never get here */
1832
                                goto gen_64_failure;
×
1833
                        }
1834
                        c_iter[0]->op_orig = chain[iter].op;
7,112✔
1835
                        c_iter[1]->op_orig = chain[iter].op;
7,112✔
1836
                        c_iter[2]->op_orig = chain[iter].op;
7,112✔
1837

1838
                        c_iter[0]->nxt_f = _db_node_get(c_iter[1]);
7,112✔
1839
                        c_iter[1]->nxt_t = _db_node_get(c_iter[2]);
7,112✔
1840
                        break;
7,112✔
1841
                case SCMP_CMP_EQ:
175,902✔
1842
                case SCMP_CMP_MASKED_EQ:
1843
                case SCMP_CMP_NE:
1844
                        c_iter[0]->arg = arg;
175,902✔
1845
                        c_iter[1]->arg = arg;
175,902✔
1846
                        c_iter[0]->arg_h_flg = true;
175,902✔
1847
                        c_iter[1]->arg_h_flg = false;
175,902✔
1848
                        c_iter[0]->arg_offset = arch_arg_offset_hi(arch, arg);
175,902✔
1849
                        c_iter[1]->arg_offset = arch_arg_offset_lo(arch, arg);
175,902✔
1850

1851
                        c_iter[0]->mask = D64_HI(mask);
175,902✔
1852
                        c_iter[1]->mask = D64_LO(mask);
175,902✔
1853
                        c_iter[0]->datum = D64_HI(datum);
175,902✔
1854
                        c_iter[1]->datum = D64_LO(datum);
175,902✔
1855
                        c_iter[0]->datum_full = datum;
175,902✔
1856
                        c_iter[1]->datum_full = datum;
175,902✔
1857

1858
                        _db_node_mask_fixup(c_iter[0]);
175,902✔
1859
                        _db_node_mask_fixup(c_iter[1]);
175,902✔
1860

1861
                        switch (chain[iter].op) {
175,902✔
1862
                        case SCMP_CMP_MASKED_EQ:
11,288✔
1863
                                c_iter[0]->op = SCMP_CMP_MASKED_EQ;
11,288✔
1864
                                c_iter[1]->op = SCMP_CMP_MASKED_EQ;
11,288✔
1865
                                break;
11,288✔
1866
                        default:
164,614✔
1867
                                c_iter[0]->op = SCMP_CMP_EQ;
164,614✔
1868
                                c_iter[1]->op = SCMP_CMP_EQ;
164,614✔
1869
                        }
1870
                        c_iter[0]->op_orig = chain[iter].op;
175,902✔
1871
                        c_iter[1]->op_orig = chain[iter].op;
175,902✔
1872

1873
                        c_iter[0]->nxt_t = _db_node_get(c_iter[1]);
175,902✔
1874
                        break;
175,902✔
1875
                default:
×
1876
                        /* we should never get here */
1877
                        goto gen_64_failure;
×
1878
                }
1879

1880
                /* link this level to the previous level */
1881
                if (c_prev[0] != NULL) {
183,014✔
1882
                        switch (op_prev) {
79,454✔
1883
                        case SCMP_CMP_GT:
1884
                        case SCMP_CMP_GE:
1885
                                c_prev[0]->nxt_t = _db_node_get(c_iter[0]);
116✔
1886
                                c_prev[2]->nxt_t = _db_node_get(c_iter[0]);
116✔
1887
                                break;
116✔
1888
                        case SCMP_CMP_EQ:
1889
                        case SCMP_CMP_MASKED_EQ:
1890
                                c_prev[1]->nxt_t = _db_node_get(c_iter[0]);
72,256✔
1891
                                break;
72,256✔
1892
                        case SCMP_CMP_LE:
1893
                        case SCMP_CMP_LT:
1894
                                c_prev[1]->nxt_f = _db_node_get(c_iter[0]);
104✔
1895
                                c_prev[2]->nxt_f = _db_node_get(c_iter[0]);
104✔
1896
                                break;
104✔
1897
                        case SCMP_CMP_NE:
1898
                                c_prev[0]->nxt_f = _db_node_get(c_iter[0]);
6,978✔
1899
                                c_prev[1]->nxt_f = _db_node_get(c_iter[0]);
6,978✔
1900
                                break;
6,978✔
1901
                        default:
×
1902
                                /* we should never get here */
1903
                                goto gen_64_failure;
×
1904
                        }
1905
                } else
1906
                        s_new->chains = _db_node_get(c_iter[0]);
103,560✔
1907

1908
                /* update the node count */
1909
                switch (chain[iter].op) {
183,014✔
1910
                case SCMP_CMP_NE:
175,902✔
1911
                case SCMP_CMP_EQ:
1912
                case SCMP_CMP_MASKED_EQ:
1913
                        s_new->node_cnt += 2;
175,902✔
1914
                        break;
175,902✔
1915
                default:
7,112✔
1916
                        s_new->node_cnt += 3;
7,112✔
1917
                }
1918

1919
                /* keep pointers to this level */
1920
                c_prev[0] = c_iter[0];
1921
                c_prev[1] = c_iter[1];
1922
                c_prev[2] = c_iter[2];
1923
                op_prev = chain[iter].op;
1924
        }
1925
        if (c_iter[0] != NULL) {
191,906✔
1926
                /* set the actions on the last layer */
1927
                switch (op_prev) {
103,560✔
1928
                case SCMP_CMP_GT:
908✔
1929
                case SCMP_CMP_GE:
1930
                        c_iter[0]->act_t_flg = true;
908✔
1931
                        c_iter[0]->act_t = rule->action;
908✔
1932
                        c_iter[2]->act_t_flg = true;
908✔
1933
                        c_iter[2]->act_t = rule->action;
908✔
1934
                        break;
908✔
1935
                case SCMP_CMP_LE:
5,984✔
1936
                case SCMP_CMP_LT:
1937
                        c_iter[1]->act_f_flg = true;
5,984✔
1938
                        c_iter[1]->act_f = rule->action;
5,984✔
1939
                        c_iter[2]->act_f_flg = true;
5,984✔
1940
                        c_iter[2]->act_f = rule->action;
5,984✔
1941
                        break;
5,984✔
1942
                case SCMP_CMP_EQ:
89,416✔
1943
                case SCMP_CMP_MASKED_EQ:
1944
                        c_iter[1]->act_t_flg = true;
89,416✔
1945
                        c_iter[1]->act_t = rule->action;
89,416✔
1946
                        break;
89,416✔
1947
                case SCMP_CMP_NE:
7,252✔
1948
                        c_iter[0]->act_f_flg = true;
7,252✔
1949
                        c_iter[0]->act_f = rule->action;
7,252✔
1950
                        c_iter[1]->act_f_flg = true;
7,252✔
1951
                        c_iter[1]->act_f = rule->action;
7,252✔
1952
                        break;
7,252✔
1953
                default:
×
1954
                        /* we should never get here */
1955
                        goto gen_64_failure;
×
1956
                }
1957
        } else
1958
                s_new->action = rule->action;
88,346✔
1959

1960
        return s_new;
1961

1962
gen_64_failure:
×
1963
        /* free the new chain and its syscall struct */
1964
        _db_tree_put(&s_new->chains);
×
1965
        free(s_new);
×
1966
        return NULL;
×
1967
}
1968

1969
/**
1970
 * Generate a new filter rule for a 32 bit system
1971
 * @param arch the architecture definition
1972
 * @param rule the new filter rule
1973
 *
1974
 * This function generates a new syscall filter for a 32 bit system. Returns
1975
 * zero on success, negative values on failure.
1976
 *
1977
 */
1978
static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch,
95,510✔
1979
                                           const struct db_api_rule_list *rule)
1980
{
1981
        unsigned int iter;
95,510✔
1982
        struct db_sys_list *s_new;
95,510✔
1983
        const struct db_api_arg *chain = rule->args;
95,510✔
1984
        struct db_arg_chain_tree *c_iter = NULL, *c_prev = NULL;
95,510✔
1985
        bool tf_flag;
95,510✔
1986

1987
        s_new = zmalloc(sizeof(*s_new));
95,510✔
1988
        if (s_new == NULL)
95,510✔
1989
                return NULL;
1990
        s_new->num = rule->syscall;
95,510✔
1991
        s_new->valid = true;
95,510✔
1992
        /* run through the argument chain */
1993
        for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
668,570✔
1994
                if (chain[iter].valid == 0)
573,060✔
1995
                        continue;
522,640✔
1996

1997
                /* skip generating instructions which are no-ops */
1998
                if (!_db_arg_cmp_need_lo(&chain[iter]))
50,420✔
1999
                        continue;
×
2000

2001
                c_iter = zmalloc(sizeof(*c_iter));
50,420✔
2002
                if (c_iter == NULL)
50,420✔
2003
                        goto gen_32_failure;
×
2004
                c_iter->arg = chain[iter].arg;
50,420✔
2005
                c_iter->arg_h_flg = false;
50,420✔
2006
                c_iter->arg_offset = arch_arg_offset(arch, c_iter->arg);
50,420✔
2007
                c_iter->op = chain[iter].op;
50,420✔
2008
                c_iter->op_orig = chain[iter].op;
50,420✔
2009
                /* implicitly strips off the upper 32 bit */
2010
                c_iter->mask = chain[iter].mask;
50,420✔
2011
                c_iter->datum = chain[iter].datum;
50,420✔
2012
                c_iter->datum_full = chain[iter].datum;
50,420✔
2013

2014
                /* link in the new node and update the chain */
2015
                if (c_prev != NULL) {
50,420✔
2016
                        if (tf_flag)
60✔
2017
                                c_prev->nxt_t = _db_node_get(c_iter);
36✔
2018
                        else
2019
                                c_prev->nxt_f = _db_node_get(c_iter);
24✔
2020
                } else
2021
                        s_new->chains = _db_node_get(c_iter);
50,360✔
2022
                s_new->node_cnt++;
50,420✔
2023

2024
                /* rewrite the op to reduce the op/datum combos */
2025
                switch (c_iter->op) {
50,420✔
2026
                case SCMP_CMP_NE:
12✔
2027
                        c_iter->op = SCMP_CMP_EQ;
12✔
2028
                        tf_flag = false;
12✔
2029
                        break;
12✔
2030
                case SCMP_CMP_LT:
12✔
2031
                        c_iter->op = SCMP_CMP_GE;
12✔
2032
                        tf_flag = false;
12✔
2033
                        break;
12✔
2034
                case SCMP_CMP_LE:
12✔
2035
                        c_iter->op = SCMP_CMP_GT;
12✔
2036
                        tf_flag = false;
12✔
2037
                        break;
12✔
2038
                default:
2039
                        tf_flag = true;
2040
                }
2041

2042
                /* fixup the mask/datum */
2043
                _db_node_mask_fixup(c_iter);
50,420✔
2044

2045
                c_prev = c_iter;
50,420✔
2046
        }
2047
        if (c_iter != NULL) {
95,510✔
2048
                /* set the leaf node */
2049
                if (tf_flag) {
50,360✔
2050
                        c_iter->act_t_flg = true;
50,348✔
2051
                        c_iter->act_t = rule->action;
50,348✔
2052
                } else {
2053
                        c_iter->act_f_flg = true;
12✔
2054
                        c_iter->act_f = rule->action;
12✔
2055
                }
2056
        } else
2057
                s_new->action = rule->action;
45,150✔
2058

2059
        return s_new;
2060

2061
gen_32_failure:
×
2062
        /* free the new chain and its syscall struct */
2063
        _db_tree_put(&s_new->chains);
×
2064
        free(s_new);
×
2065
        return NULL;
×
2066
}
2067

2068
/**
2069
 * Add a new rule to the seccomp filter DB
2070
 * @param db the seccomp filter db
2071
 * @param rule the filter rule
2072
 *
2073
 * This function adds a new syscall filter to the seccomp filter DB, adding to
2074
 * the existing filters for the syscall, unless no argument specific filters
2075
 * are present (filtering only on the syscall).  When adding new chains, the
2076
 * shortest chain, or most inclusive filter match, will be entered into the
2077
 * filter DB. Returns zero on success, negative values on failure.
2078
 *
2079
 * It is important to note that in the case of failure the db may be corrupted,
2080
 * the caller must use the transaction mechanism if the db integrity is
2081
 * important.
2082
 *
2083
 */
2084
int db_rule_add(struct db_filter *db, const struct db_api_rule_list *rule)
287,416✔
2085
{
2086
        int rc = -ENOMEM;
287,416✔
2087
        struct db_sys_list *s_new, *s_iter, *s_prev = NULL;
287,416✔
2088
        struct db_iter_state state;
287,416✔
2089
        bool rm_flag = false;
287,416✔
2090

2091
        assert(db != NULL);
287,416✔
2092

2093
        /* do all our possible memory allocation up front so we don't have to
2094
         * worry about failure once we get to the point where we start updating
2095
         * the filter db */
2096
        if (db->arch->size == ARCH_SIZE_64)
287,416✔
2097
                s_new = _db_rule_gen_64(db->arch, rule);
191,906✔
2098
        else if (db->arch->size == ARCH_SIZE_32)
95,510✔
2099
                s_new = _db_rule_gen_32(db->arch, rule);
95,510✔
2100
        else
2101
                return -EFAULT;
2102
        if (s_new == NULL)
287,416✔
2103
                return -ENOMEM;
2104

2105
        /* find a matching syscall/chain or insert a new one */
2106
        s_iter = db->syscalls;
287,416✔
2107
        while (s_iter != NULL && s_iter->num < rule->syscall) {
1,471,780✔
2108
                s_prev = s_iter;
1,184,360✔
2109
                s_iter = s_iter->next;
1,184,360✔
2110
        }
2111
        s_new->priority = _DB_PRI_MASK_CHAIN - s_new->node_cnt;
287,416✔
2112
add_reset:
289,704✔
2113
        if (s_iter == NULL || s_iter->num != rule->syscall) {
289,704✔
2114
                /* new syscall, add before s_iter */
2115
                if (s_prev != NULL) {
208,426✔
2116
                        s_new->next = s_prev->next;
166,266✔
2117
                        s_prev->next = s_new;
166,266✔
2118
                } else {
2119
                        s_new->next = db->syscalls;
42,160✔
2120
                        db->syscalls = s_new;
42,160✔
2121
                }
2122
                db->syscall_cnt++;
208,426✔
2123
                return 0;
208,426✔
2124
        } else if (s_iter->chains == NULL) {
81,278✔
2125
                if (rm_flag || !s_iter->valid) {
3,108✔
2126
                        /* we are here because our previous pass cleared the
2127
                         * entire syscall chain when searching for a subtree
2128
                         * match or the existing syscall entry is a phantom,
2129
                         * so either way add the new chain */
2130
                        s_iter->chains = s_new->chains;
2,328✔
2131
                        s_iter->action = s_new->action;
2,328✔
2132
                        s_iter->node_cnt = s_new->node_cnt;
2,328✔
2133
                        if (s_iter->valid)
2,328✔
2134
                                s_iter->priority = s_new->priority;
2,288✔
2135
                        s_iter->valid = true;
2,328✔
2136
                        free(s_new);
2,328✔
2137
                        rc = 0;
2,328✔
2138
                        goto add_priority_update;
2,328✔
2139
                } else {
2140
                        /* syscall exists without any chains - existing filter
2141
                         * is at least as large as the new entry so cleanup and
2142
                         * exit */
2143
                        _db_tree_put(&s_new->chains);
780✔
2144
                        free(s_new);
780✔
2145
                        goto add_free_ok;
780✔
2146
                }
2147
        } else if (s_iter->chains != NULL && s_new->chains == NULL) {
78,170✔
2148
                /* syscall exists with chains but the new filter has no chains
2149
                 * so we need to clear the existing chains and exit */
2150
                _db_tree_put(&s_iter->chains);
132✔
2151
                s_iter->chains = NULL;
132✔
2152
                s_iter->node_cnt = 0;
132✔
2153
                s_iter->action = rule->action;
132✔
2154

2155
                /* cleanup the new tree and return */
2156
                _db_tree_put(&s_new->chains);
132✔
2157
                free(s_new);
132✔
2158
                goto add_free_ok;
132✔
2159
        }
2160

2161
        /* prune any sub-trees that are no longer required */
2162
        memset(&state, 0, sizeof(state));
78,038✔
2163
        state.sx = s_iter;
78,038✔
2164
        state.action = rule->action;
78,038✔
2165
        rc = _db_tree_prune(&s_iter->chains, s_new->chains, &state);
78,038✔
2166
        if (rc > 0) {
78,038✔
2167
                /* we pruned at least some of the existing tree */
2168
                rm_flag = true;
2,288✔
2169
                s_iter->node_cnt -= rc;
2,288✔
2170
                if (s_iter->chains == NULL)
2,288✔
2171
                        /* we pruned the entire tree */
2172
                        goto add_reset;
2,288✔
2173
        } else if ((state.flags & _DB_IST_M_REDUNDANT) == _DB_IST_M_REDUNDANT) {
75,750✔
2174
                /* the existing tree is "shorter", drop the new one */
2175
                _db_tree_put(&s_new->chains);
4,644✔
2176
                free(s_new);
4,644✔
2177
                goto add_free_ok;
4,644✔
2178
        }
2179

2180
        /* add the new rule to the existing filter and cleanup */
2181
        memset(&state, 0, sizeof(state));
71,106✔
2182
        state.sx = s_iter;
71,106✔
2183
        rc = _db_tree_add(&s_iter->chains, s_new->chains, &state);
71,106✔
2184
        if (rc < 0)
71,106✔
2185
                goto add_failure;
34✔
2186
        s_iter->node_cnt += s_new->node_cnt;
71,072✔
2187
        s_iter->node_cnt -= _db_tree_put(&s_new->chains);
71,072✔
2188
        free(s_new);
71,072✔
2189

2190
add_free_ok:
2191
        rc = 0;
2192
add_priority_update:
78,956✔
2193
        /* update the priority */
2194
        if (s_iter != NULL) {
78,956✔
2195
                s_iter->priority &= (~_DB_PRI_MASK_CHAIN);
78,956✔
2196
                s_iter->priority |= (_DB_PRI_MASK_CHAIN - s_iter->node_cnt);
78,956✔
2197
        }
2198
        return rc;
78,956✔
2199

2200
add_failure:
34✔
2201
        /* NOTE: another reminder that we don't do any db error recovery here,
2202
         * use the transaction mechanism as previously mentioned */
2203
        _db_tree_put(&s_new->chains);
34✔
2204
        free(s_new);
34✔
2205
        return rc;
34✔
2206
}
2207

2208
/**
2209
 * Set the priority of a given syscall
2210
 * @param col the filter collection
2211
 * @param syscall the syscall number
2212
 * @param priority priority value, higher value == higher priority
2213
 *
2214
 * This function sets the priority of the given syscall; this value is used
2215
 * when generating the seccomp filter code such that higher priority syscalls
2216
 * will incur less filter code overhead than the lower priority syscalls in the
2217
 * filter.  Returns zero on success, negative values on failure.
2218
 *
2219
 */
2220
int db_col_syscall_priority(struct db_filter_col *col,
68✔
2221
                            int syscall, uint8_t priority)
2222
{
2223
        int rc = 0, rc_tmp;
68✔
2224
        unsigned int iter;
68✔
2225
        int sc_tmp;
68✔
2226
        struct db_filter *filter;
68✔
2227

2228
        for (iter = 0; iter < col->filter_cnt; iter++) {
150✔
2229
                filter = col->filters[iter];
82✔
2230
                sc_tmp = syscall;
82✔
2231

2232
                rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp);
82✔
2233
                if (rc_tmp < 0)
82✔
2234
                        goto priority_failure;
×
2235

2236
                /* if this is a pseudo syscall then we need to rewrite the
2237
                 * syscall for some arch specific reason, don't forget the
2238
                 * special handling for syscall -1 */
2239
                if (sc_tmp < -1) {
82✔
2240
                        /* we set this as a strict op - we don't really care
2241
                         * since priorities are a "best effort" thing - as we
2242
                         * want to catch the -EDOM error and bail on this
2243
                         * architecture */
2244
                        rc_tmp = arch_syscall_rewrite(filter->arch, &sc_tmp);
7✔
2245
                        if (rc_tmp == -EDOM)
7✔
2246
                                continue;
3✔
2247
                        if (rc_tmp < 0)
4✔
2248
                                goto priority_failure;
×
2249
                }
2250

2251
                rc_tmp = _db_syscall_priority(filter, sc_tmp, priority);
79✔
2252

2253
priority_failure:
79✔
2254
                if (rc == 0 && rc_tmp < 0)
79✔
2255
                        rc = rc_tmp;
×
2256
        }
2257

2258
        if (rc == 0)
68✔
2259
                db_col_precompute_reset(col);
136✔
2260

2261
        return rc;
68✔
2262
}
2263

2264
/**
2265
 * Add a new rule to a single filter
2266
 * @param filter the filter
2267
 * @param rule the filter rule
2268
 *
2269
 * This is a helper function for db_col_rule_add() and similar functions, it
2270
 * isn't generally useful.  Returns zero on success, negative values on error.
2271
 *
2272
 */
2273
static int _db_col_rule_add(struct db_filter *filter,
263,368✔
2274
                            struct db_api_rule_list *rule)
2275
{
2276
        int rc;
263,368✔
2277
        struct db_api_rule_list *iter;
263,368✔
2278

2279
        /* add the rule to the filter */
2280
        rc = arch_filter_rule_add(filter, rule);
263,368✔
2281
        if (rc != 0)
263,368✔
2282
                return rc;
2283

2284
        /* insert the chain to the end of the rule list */
2285
        iter = rule;
2286
        while (iter->next)
262,955✔
2287
                iter = iter->next;
2288
        if (filter->rules != NULL) {
262,955✔
2289
                rule->prev = filter->rules->prev;
228,276✔
2290
                iter->next = filter->rules;
228,276✔
2291
                filter->rules->prev->next = rule;
228,276✔
2292
                filter->rules->prev = iter;
228,276✔
2293
        } else {
2294
                rule->prev = iter;
34,679✔
2295
                iter->next = rule;
34,679✔
2296
                filter->rules = rule;
34,679✔
2297
        }
2298

2299
        return 0;
2300
}
2301

2302
/**
2303
 * Add a new rule to the current filter
2304
 * @param col the filter collection
2305
 * @param strict the strict flag
2306
 * @param action the filter action
2307
 * @param syscall the syscall number
2308
 * @param arg_cnt the number of argument filters in the argument filter chain
2309
 * @param arg_array the argument filter chain, (uint, enum scmp_compare, ulong)
2310
 *
2311
 * This function adds a new argument/comparison/value to the seccomp filter for
2312
 * a syscall; multiple arguments can be specified and they will be chained
2313
 * together (essentially AND'd together) in the filter.  When the strict flag
2314
 * is true the function will fail if the exact rule can not be added to the
2315
 * filter, if the strict flag is false the function will not fail if the
2316
 * function needs to adjust the rule due to architecture specifics.  Returns
2317
 * zero on success, negative values on failure.
2318
 *
2319
 */
2320
int db_col_rule_add(struct db_filter_col *col,
53,116✔
2321
                    bool strict, uint32_t action, int syscall,
2322
                    unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array)
2323
{
2324
        int rc = 0, rc_tmp;
53,116✔
2325
        unsigned int iter;
53,116✔
2326
        unsigned int arg_num;
53,116✔
2327
        size_t chain_size;
53,116✔
2328
        struct db_api_arg *chain = NULL;
53,116✔
2329
        struct scmp_arg_cmp arg_data;
53,116✔
2330
        struct db_api_rule_list *rule;
53,116✔
2331
        struct db_filter *db;
53,116✔
2332

2333
        /* collect the arguments for the filter rule */
2334
        chain_size = sizeof(*chain) * ARG_COUNT_MAX;
53,116✔
2335
        chain = zmalloc(chain_size);
53,116✔
2336
        if (chain == NULL)
53,116✔
2337
                return -ENOMEM;
2338
        for (iter = 0; iter < arg_cnt; iter++) {
125,178✔
2339
                arg_data = arg_array[iter];
72,064✔
2340
                arg_num = arg_data.arg;
72,064✔
2341
                if (arg_num < ARG_COUNT_MAX && chain[arg_num].valid == 0) {
72,064✔
2342
                        chain[arg_num].valid = 1;
72,064✔
2343
                        chain[arg_num].arg = arg_num;
72,064✔
2344
                        chain[arg_num].op = arg_data.op;
72,064✔
2345
                        /* TODO: we should check datum/mask size against the
2346
                         *         arch definition, e.g. 64 bit datum on x86 */
2347
                        switch (chain[arg_num].op) {
72,064✔
2348
                        case SCMP_CMP_NE:
66,389✔
2349
                        case SCMP_CMP_LT:
2350
                        case SCMP_CMP_LE:
2351
                        case SCMP_CMP_EQ:
2352
                        case SCMP_CMP_GE:
2353
                        case SCMP_CMP_GT:
2354
                                chain[arg_num].mask = DATUM_MAX;
66,389✔
2355
                                chain[arg_num].datum = arg_data.datum_a;
66,389✔
2356
                                break;
66,389✔
2357
                        case SCMP_CMP_MASKED_EQ:
5,673✔
2358
                                chain[arg_num].mask = arg_data.datum_a;
5,673✔
2359
                                chain[arg_num].datum = arg_data.datum_b;
5,673✔
2360
                                break;
5,673✔
2361
                        default:
2✔
2362
                                rc = -EINVAL;
2✔
2363
                                goto add_return;
2✔
2364
                        }
2365
                } else {
2366
                        rc = -EINVAL;
×
2367
                        goto add_return;
×
2368
                }
2369
        }
2370

2371
        /* create a checkpoint */
2372
        rc = db_col_transaction_start(col);
53,114✔
2373
        if (rc != 0)
53,114✔
2374
                goto add_return;
×
2375

2376
        /* add the rule to the different filters in the collection */
2377
        for (iter = 0; iter < col->filter_cnt; iter++) {
184,947✔
2378
                db = col->filters[iter];
131,833✔
2379

2380
                /* create the rule */
2381
                rule = _db_rule_new(strict, action, syscall, chain);
131,833✔
2382
                if (rule == NULL) {
131,833✔
2383
                        rc_tmp = -ENOMEM;
×
2384
                        goto add_arch_fail;
×
2385
                }
2386

2387
                /* add the rule */
2388
                rc_tmp = _db_col_rule_add(db, rule);
131,833✔
2389
                if (rc_tmp != 0)
131,833✔
2390
                        free(rule);
413✔
2391

2392
add_arch_fail:
131,420✔
2393
                if (rc_tmp != 0 && rc == 0)
131,833✔
2394
                        rc = rc_tmp;
413✔
2395
        }
2396

2397
        /* commit the transaction or abort */
2398
        if (rc == 0)
53,114✔
2399
                db_col_transaction_commit(col);
52,701✔
2400
        else
2401
                db_col_transaction_abort(col);
413✔
2402

2403
add_return:
53,114✔
2404
        /* update the misc state */
2405
        if (rc == 0) {
53,116✔
2406
                if (action == SCMP_ACT_NOTIFY)
52,701✔
2407
                        col->notify_used = true;
×
2408
                db_col_precompute_reset(col);
105,817✔
2409
        }
2410
        if (chain != NULL)
53,116✔
2411
                free(chain);
53,116✔
2412
        return rc;
53,116✔
2413
}
2414

2415
/**
2416
 * Start a new seccomp filter transaction
2417
 * @param col the filter collection
2418
 *
2419
 * This function starts a new seccomp filter transaction for the given filter
2420
 * collection.  Returns zero on success, negative values on failure.
2421
 *
2422
 */
2423
int db_col_transaction_start(struct db_filter_col *col)
53,114✔
2424
{
2425
        int rc;
53,114✔
2426
        unsigned int iter;
53,114✔
2427
        struct db_filter_snap *snap;
53,114✔
2428
        struct db_filter *filter_o, *filter_s;
53,114✔
2429
        struct db_api_rule_list *rule_o, *rule_s = NULL;
53,114✔
2430

2431
        /* check to see if a shadow snapshot exists */
2432
        if (col->snapshots && col->snapshots->shadow) {
53,114✔
2433
                /* we have a shadow!  this will be easy */
2434

2435
                /* NOTE: we don't bother to do any verification of the shadow
2436
                 *       because we start a new transaction every time we add
2437
                 *       a new rule to the filter(s); if this ever changes we
2438
                 *       will need to add a mechanism to verify that the shadow
2439
                 *       transaction is current/correct */
2440

2441
                col->snapshots->shadow = false;
45,944✔
2442
                return 0;
45,944✔
2443
        }
2444

2445
        /* allocate the snapshot */
2446
        snap = zmalloc(sizeof(*snap));
7,170✔
2447
        if (snap == NULL)
7,170✔
2448
                return -ENOMEM;
2449
        snap->filters = zmalloc(sizeof(struct db_filter *) * col->filter_cnt);
7,170✔
2450
        if (snap->filters == NULL) {
7,170✔
2451
                free(snap);
×
2452
                return -ENOMEM;
×
2453
        }
2454
        snap->filter_cnt = col->filter_cnt;
7,170✔
2455
        for (iter = 0; iter < snap->filter_cnt; iter++)
24,535✔
2456
                snap->filters[iter] = NULL;
17,365✔
2457
        snap->next = NULL;
7,170✔
2458

2459
        /* create a snapshot of the current filter state */
2460
        for (iter = 0; iter < col->filter_cnt; iter++) {
24,535✔
2461
                /* allocate a new filter */
2462
                filter_o = col->filters[iter];
17,365✔
2463
                filter_s = _db_init(filter_o->arch);
17,365✔
2464
                if (filter_s == NULL)
17,365✔
2465
                        goto trans_start_failure;
×
2466
                snap->filters[iter] = filter_s;
17,365✔
2467

2468
                /* create a filter snapshot from existing rules */
2469
                rule_o = filter_o->rules;
17,365✔
2470
                if (rule_o == NULL)
17,365✔
2471
                        continue;
17,318✔
2472
                do {
115✔
2473
                        /* duplicate the rule */
2474
                        rule_s = db_rule_dup(rule_o);
115✔
2475
                        if (rule_s == NULL)
115✔
2476
                                goto trans_start_failure;
×
2477

2478
                        /* add the rule */
2479
                        rc = _db_col_rule_add(filter_s, rule_s);
115✔
2480
                        if (rc != 0)
115✔
2481
                                goto trans_start_failure;
×
2482
                        rule_s = NULL;
115✔
2483

2484
                        /* next rule */
2485
                        rule_o = rule_o->next;
115✔
2486
                } while (rule_o != filter_o->rules);
115✔
2487
        }
2488

2489
        /* add the snapshot to the list */
2490
        snap->next = col->snapshots;
7,170✔
2491
        col->snapshots = snap;
7,170✔
2492

2493
        return 0;
7,170✔
2494

2495
trans_start_failure:
×
2496
        if (rule_s != NULL)
×
2497
                free(rule_s);
×
2498
        _db_snap_release(snap);
×
2499
        return -ENOMEM;
×
2500
}
2501

2502
/**
2503
 * Abort the top most seccomp filter transaction
2504
 * @param col the filter collection
2505
 *
2506
 * This function aborts the most recent seccomp filter transaction.
2507
 *
2508
 */
2509
void db_col_transaction_abort(struct db_filter_col *col)
413✔
2510
{
2511
        int iter;
413✔
2512
        unsigned int filter_cnt;
413✔
2513
        struct db_filter **filters;
413✔
2514
        struct db_filter_snap *snap;
413✔
2515

2516
        if (col->snapshots == NULL)
413✔
2517
                return;
2518

2519
        /* replace the current filter with the last snapshot */
2520
        snap = col->snapshots;
413✔
2521
        col->snapshots = snap->next;
413✔
2522
        filter_cnt = col->filter_cnt;
413✔
2523
        filters = col->filters;
413✔
2524
        col->filter_cnt = snap->filter_cnt;
413✔
2525
        col->filters = snap->filters;
413✔
2526
        free(snap);
413✔
2527

2528
        /* free the filter we swapped out */
2529
        for (iter = 0; iter < filter_cnt; iter++)
826✔
2530
                _db_release(filters[iter]);
826✔
2531
        free(filters);
413✔
2532

2533
        /* free any precompute */
2534
        db_col_precompute_reset(col);
826✔
2535
}
2536

2537
/**
2538
 * Commit the top most seccomp filter transaction
2539
 * @param col the filter collection
2540
 *
2541
 * This function commits the most recent seccomp filter transaction and
2542
 * attempts to create a shadow transaction that is a duplicate of the current
2543
 * filter to speed up future transactions.
2544
 *
2545
 */
2546
void db_col_transaction_commit(struct db_filter_col *col)
52,701✔
2547
{
2548
        int rc;
52,701✔
2549
        unsigned int iter;
52,701✔
2550
        struct db_filter_snap *snap;
52,701✔
2551
        struct db_filter *filter_o, *filter_s;
52,701✔
2552
        struct db_api_rule_list *rule_o, *rule_s;
52,701✔
2553

2554
        snap = col->snapshots;
52,701✔
2555
        if (snap == NULL)
52,701✔
2556
                return;
2557

2558
        /* check for a shadow set by a higher transaction commit */
2559
        if (snap->shadow) {
52,701✔
2560
                /* leave the shadow intact, but drop the next snapshot */
2561
                if (snap->next) {
×
2562
                        snap->next = snap->next->next;
×
2563
                        _db_snap_release(snap->next);
×
2564
                }
2565
                return;
×
2566
        }
2567

2568
        /* adjust the number of filters if needed */
2569
        if (col->filter_cnt > snap->filter_cnt) {
52,701✔
2570
                unsigned int tmp_i;
×
2571
                struct db_filter **tmp_f;
×
2572

2573
                /* add filters */
2574
                tmp_f = realloc(snap->filters,
×
2575
                                sizeof(struct db_filter *) * col->filter_cnt);
×
2576
                if (tmp_f == NULL)
×
2577
                        goto shadow_err;
×
2578
                snap->filters = tmp_f;
×
2579
                do {
×
2580
                        tmp_i = snap->filter_cnt;
×
2581
                        snap->filters[tmp_i] =
×
2582
                                _db_init(col->filters[tmp_i]->arch);
×
2583
                        if (snap->filters[tmp_i] == NULL)
×
2584
                                goto shadow_err;
×
2585
                        snap->filter_cnt++;
×
2586
                } while (snap->filter_cnt < col->filter_cnt);
×
2587
        } else if (col->filter_cnt < snap->filter_cnt) {
52,701✔
2588
                /* remove filters */
2589

2590
                /* NOTE: while we release the filters we no longer need, we
2591
                 *       don't bother to resize the filter array, we just
2592
                 *       adjust the filter counter, this *should* be harmless
2593
                 *       at the cost of a not reaping all the memory possible */
2594

2595
                do {
×
2596
                        _db_release(snap->filters[snap->filter_cnt--]);
×
2597
                } while (snap->filter_cnt > col->filter_cnt);
×
2598
        }
2599

2600
        /* loop through each filter and update the rules on the snapshot */
2601
        for (iter = 0; iter < col->filter_cnt; iter++) {
184,121✔
2602
                filter_o = col->filters[iter];
131,420✔
2603
                filter_s = snap->filters[iter];
131,420✔
2604

2605
                /* skip ahead to the new rule(s) */
2606
                rule_o = filter_o->rules;
131,420✔
2607
                rule_s = filter_s->rules;
131,420✔
2608
                if (rule_o == NULL)
131,420✔
2609
                        /* nothing to shadow */
2610
                        continue;
×
2611
                if (rule_s != NULL) {
131,420✔
2612
                        do {
1,116,570✔
2613
                                rule_o = rule_o->next;
1,116,570✔
2614
                                rule_s = rule_s->next;
1,116,570✔
2615
                        } while (rule_s != filter_s->rules);
1,116,570✔
2616

2617
                        /* did we actually add any rules? */
2618
                        if (rule_o == filter_o->rules)
114,104✔
2619
                                /* no, we are done in this case */
2620
                                continue;
×
2621
                }
2622

2623
                /* update the old snapshot to make it a shadow */
2624
                do {
131,420✔
2625
                        /* duplicate the rule */
2626
                        rule_s = db_rule_dup(rule_o);
131,420✔
2627
                        if (rule_s == NULL)
131,420✔
2628
                                goto shadow_err;
×
2629

2630
                        /* add the rule */
2631
                        rc = _db_col_rule_add(filter_s, rule_s);
131,420✔
2632
                        if (rc != 0) {
131,420✔
2633
                                free(rule_s);
×
2634
                                goto shadow_err;
×
2635
                        }
2636

2637
                        /* next rule */
2638
                        rule_o = rule_o->next;
131,420✔
2639
                } while (rule_o != filter_o->rules);
131,420✔
2640
        }
2641

2642
        /* success, mark the snapshot as a shadow and return */
2643
        snap->shadow = true;
52,701✔
2644
        return;
52,701✔
2645

2646
shadow_err:
×
2647
        /* we failed making a shadow, cleanup and return */
2648
        col->snapshots = snap->next;
×
2649
        _db_snap_release(snap);
×
2650
        return;
×
2651
}
2652

2653
/**
2654
 * Precompute the seccomp filters
2655
 * @param col the filter collection
2656
 *
2657
 * This function precomputes the seccomp filters before they are needed,
2658
 * returns zero on success, negative values on error.
2659
 *
2660
 */
2661
int db_col_precompute(struct db_filter_col *col)
7,824✔
2662
{
2663
        if (!col->prgm_bpf)
7,824✔
2664
                return gen_bpf_generate(col, &col->prgm_bpf);
7,810✔
2665
        return 0;
2666
}
2667

2668
/**
2669
 * Free any precomputed filter programs
2670
 * @param col the filter collection
2671
 *
2672
 * This function releases any precomputed filter programs.
2673
 */
2674
void db_col_precompute_reset(struct db_filter_col *col)
86,853✔
2675
{
2676
        if (!col->prgm_bpf)
86,853✔
2677
                return;
2678

2679
        gen_bpf_release(col->prgm_bpf);
309✔
2680
        col->prgm_bpf = NULL;
7,810✔
2681
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc