]>
iEval git - linux-seccomp.git/blob - libseccomp/src/gen_bpf.c
2418a1aeba741f179ce4584b497a47fe62653828
2 * Seccomp BPF Translator
4 * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
5 * Author: Paul Moore <paul@paul-moore.com>
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of version 2.1 of the GNU Lesser General Public License as
11 * published by the Free Software Foundation.
13 * This library is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses>.
43 /* allocation increments */
51 #define _ACC_STATE(x,y) \
52 (struct acc_state){ .offset = (x), .mask = (y) }
53 #define _ACC_STATE_OFFSET(x) \
54 _ACC_STATE(x,ARG_MASK_MAX)
55 #define _ACC_STATE_UNDEF \
57 #define _ACC_CMP_EQ(x,y) \
58 ((x).offset == (y).offset && (x).mask == (y).mask)
62 TGT_K
, /* immediate "k" value */
63 TGT_NXT
, /* fall through to the next block */
64 TGT_IMM
, /* resolved immediate value */
65 TGT_PTR_DB
, /* pointer to part of the filter db */
66 TGT_PTR_BLK
, /* pointer to an instruction block */
67 TGT_PTR_HSH
, /* pointer to a block hash table */
75 struct db_arg_chain_tree
*db
;
79 enum bpf_jump_type type
;
81 #define _BPF_OP(a,x) \
84 ((struct bpf_jump) { .type = TGT_NONE })
85 #define _BPF_JMP_NXT(x) \
86 ((struct bpf_jump) { .type = TGT_NXT, .tgt = { .nxt = (x) } })
87 #define _BPF_JMP_IMM(x) \
88 ((struct bpf_jump) { .type = TGT_IMM, .tgt = { .imm_j = (x) } })
89 #define _BPF_JMP_DB(x) \
90 ((struct bpf_jump) { .type = TGT_PTR_DB, .tgt = { .db = (x) } })
91 #define _BPF_JMP_BLK(x) \
92 ((struct bpf_jump) { .type = TGT_PTR_BLK, .tgt = { .blk = (x) } })
93 #define _BPF_JMP_HSH(x) \
94 ((struct bpf_jump) { .type = TGT_PTR_HSH, .tgt = { .hash = (x) } })
96 ((struct bpf_jump) { .type = TGT_K, .tgt = { .imm_k = _htot32(a,x) } })
97 #define _BPF_JMP_MAX 255
98 #define _BPF_JMP_MAX_RET 255
106 #define _BPF_OFFSET_SYSCALL (offsetof(struct seccomp_data, nr))
107 #define _BPF_SYSCALL(a) _BPF_K(a,_BPF_OFFSET_SYSCALL)
108 #define _BPF_OFFSET_ARCH (offsetof(struct seccomp_data, arch))
109 #define _BPF_ARCH(a) _BPF_K(a,_BPF_OFFSET_ARCH)
112 /* bpf instructions */
113 struct bpf_instr
*blks
;
114 unsigned int blk_cnt
;
115 unsigned int blk_alloc
;
117 /* accumulator state */
118 struct acc_state acc_start
;
119 struct acc_state acc_end
;
121 /* priority - higher is better */
122 unsigned int priority
;
125 bool flag_hash
; /* added to the hash table */
126 bool flag_dup
; /* duplicate block and in use */
127 bool flag_unique
; /* ->blks is unique to this block */
129 /* original db_arg_chain_tree node */
130 const struct db_arg_chain_tree
*node
;
132 /* used during block assembly */
134 struct bpf_blk
*hash_nxt
;
135 struct bpf_blk
*prev
, *next
;
136 struct bpf_blk
*lvl_prv
, *lvl_nxt
;
138 #define _BLK_MSZE(x) \
139 ((x)->blk_cnt * sizeof(*((x)->blks)))
141 struct bpf_hash_bkt
{
143 struct bpf_hash_bkt
*next
;
147 #define _BPF_HASH_BITS 8
148 #define _BPF_HASH_SIZE (1 << _BPF_HASH_BITS)
149 #define _BPF_HASH_MASK (_BPF_HASH_BITS - 1)
151 /* block hash table */
152 struct bpf_hash_bkt
*htbl
[_BPF_HASH_SIZE
];
154 /* filter attributes */
155 const struct db_filter_attr
*attr
;
156 /* bad arch action */
157 uint64_t bad_arch_hsh
;
161 /* target arch - NOTE: be careful, temporary use only! */
162 const struct arch_def
*arch
;
165 struct bpf_program
*bpf
;
169 * Populate a BPF instruction
170 * @param _ins the BPF instruction
171 * @param _op the BPF operand
172 * @param _jt the BPF jt value
173 * @param _jf the BPF jf value
174 * @param _k the BPF k value
176 * Set the given values on the provided bpf_instr struct.
179 #define _BPF_INSTR(_ins,_op,_jt,_jf,_k) \
181 memset(&(_ins), 0, sizeof(_ins)); \
188 static struct bpf_blk
*_gen_bpf_chain(struct bpf_state
*state
,
189 const struct db_sys_list
*sys
,
190 const struct db_arg_chain_tree
*chain
,
191 const struct bpf_jump
*nxt_jump
,
192 struct acc_state
*a_state
);
194 static struct bpf_blk
*_hsh_remove(struct bpf_state
*state
, uint64_t h_val
);
195 static struct bpf_blk
*_hsh_find(const struct bpf_state
*state
, uint64_t h_val
);
198 * Convert a 16-bit host integer into the target's endianess
199 * @param arch the architecture definition
200 * @param val the 16-bit integer
202 * Convert the endianess of the supplied value and return it to the caller.
205 uint16_t _htot16(const struct arch_def
*arch
, uint16_t val
)
207 if (arch
->endian
== ARCH_ENDIAN_LITTLE
)
214 * Convert a 32-bit host integer into the target's endianess
215 * @param arch the architecture definition
216 * @param val the 32-bit integer
218 * Convert the endianess of the supplied value and return it to the caller.
221 uint32_t _htot32(const struct arch_def
*arch
, uint32_t val
)
223 if (arch
->endian
== ARCH_ENDIAN_LITTLE
)
230 * Free the BPF instruction block
231 * @param state the BPF state
232 * @param blk the BPF instruction block
234 * Free the BPF instruction block, any linked blocks are preserved and the hash
235 * table is not modified. In general, you probably want to use _blk_free()
239 static void __blk_free(struct bpf_state
*state
, struct bpf_blk
*blk
)
241 struct bpf_blk
*b_tmp
;
243 while (blk
->hash_nxt
!= NULL
) {
244 b_tmp
= blk
->hash_nxt
;
245 blk
->hash_nxt
= b_tmp
->hash_nxt
;
246 if (!b_tmp
->flag_dup
)
249 if (blk
->blks
!= NULL
&& blk
->flag_unique
)
255 * Free the BPF instruction block
256 * @param state the BPF state
257 * @param blk the BPF instruction block
259 * Free the BPF instruction block including any linked blocks. The hash table
260 * is updated to reflect the newly removed block(s).
263 static void _blk_free(struct bpf_state
*state
, struct bpf_blk
*blk
)
266 struct bpf_blk
*b_iter
;
267 struct bpf_instr
*i_iter
;
272 /* remove this block from the hash table */
273 _hsh_remove(state
, blk
->hash
);
275 /* run through the block freeing TGT_PTR_{BLK,HSH} jump targets */
276 for (iter
= 0; iter
< blk
->blk_cnt
; iter
++) {
277 i_iter
= &blk
->blks
[iter
];
278 switch (i_iter
->jt
.type
) {
280 _blk_free(state
, i_iter
->jt
.tgt
.blk
);
283 b_iter
= _hsh_find(state
, i_iter
->jt
.tgt
.hash
);
284 _blk_free(state
, b_iter
);
290 switch (i_iter
->jf
.type
) {
292 _blk_free(state
, i_iter
->jf
.tgt
.blk
);
295 b_iter
= _hsh_find(state
, i_iter
->jf
.tgt
.hash
);
296 _blk_free(state
, b_iter
);
303 __blk_free(state
, blk
);
307 * Allocate and initialize a new instruction block
309 * Allocate a new BPF instruction block and perform some very basic
310 * initialization. Returns a pointer to the block on success, NULL on failure.
313 static struct bpf_blk
*_blk_alloc(void)
317 blk
= malloc(sizeof(*blk
));
321 memset(blk
, 0, sizeof(*blk
));
322 blk
->flag_unique
= true;
323 blk
->acc_start
= _ACC_STATE_UNDEF
;
324 blk
->acc_end
= _ACC_STATE_UNDEF
;
330 * Resize an instruction block
331 * @param state the BPF state
332 * @param blk the existing instruction block, or NULL
333 * @param size_add the minimum amount of instructions to add
335 * Resize the given instruction block such that it is at least as large as the
336 * current size plus @size_add. Returns a pointer to the block on success,
340 static struct bpf_blk
*_blk_resize(struct bpf_state
*state
,
342 unsigned int size_add
)
344 unsigned int size_adj
= (AINC_BLK
> size_add
? AINC_BLK
: size_add
);
345 struct bpf_instr
*new;
350 if ((blk
->blk_cnt
+ size_adj
) <= blk
->blk_alloc
)
353 blk
->blk_alloc
+= size_adj
;
354 new = realloc(blk
->blks
, blk
->blk_alloc
* sizeof(*(blk
->blks
)));
356 _blk_free(state
, blk
);
365 * Append a new BPF instruction to an instruction block
366 * @param state the BPF state
367 * @param blk the existing instruction block, or NULL
368 * @param instr the new instruction
370 * Add the new BPF instruction to the end of the given instruction block. If
371 * the given instruction block is NULL, a new block will be allocated. Returns
372 * a pointer to the block on success, NULL on failure, and in the case of
373 * failure the instruction block is free'd.
376 static struct bpf_blk
*_blk_append(struct bpf_state
*state
,
378 const struct bpf_instr
*instr
)
386 if (_blk_resize(state
, blk
, 1) == NULL
)
388 memcpy(&blk
->blks
[blk
->blk_cnt
++], instr
, sizeof(*instr
));
394 * Prepend a new BPF instruction to an instruction block
395 * @param state the BPF state
396 * @param blk the existing instruction block, or NULL
397 * @param instr the new instruction
399 * Add the new BPF instruction to the start of the given instruction block.
400 * If the given instruction block is NULL, a new block will be allocated.
401 * Returns a pointer to the block on success, NULL on failure, and in the case
402 * of failure the instruction block is free'd.
405 static struct bpf_blk
*_blk_prepend(struct bpf_state
*state
,
407 const struct bpf_instr
*instr
)
409 /* empty - we can treat this like a normal append operation */
410 if (blk
== NULL
|| blk
->blk_cnt
== 0)
411 return _blk_append(state
, blk
, instr
);
413 if (_blk_resize(state
, blk
, 1) == NULL
)
415 memmove(&blk
->blks
[1], &blk
->blks
[0], blk
->blk_cnt
++ * sizeof(*instr
));
416 memcpy(&blk
->blks
[0], instr
, sizeof(*instr
));
422 * Append a block of BPF instructions to the final BPF program
423 * @param prg the BPF program
424 * @param blk the BPF instruction block
426 * Add the BPF instruction block to the end of the BPF program and perform the
427 * necssary translation. Returns zero on success, negative values on failure
428 * and in the case of failure the BPF program is free'd.
431 static int _bpf_append_blk(struct bpf_program
*prg
, const struct bpf_blk
*blk
)
434 bpf_instr_raw
*i_new
;
435 bpf_instr_raw
*i_iter
;
436 unsigned int old_cnt
= prg
->blk_cnt
;
439 /* (re)allocate the program memory */
440 prg
->blk_cnt
+= blk
->blk_cnt
;
441 i_new
= realloc(prg
->blks
, BPF_PGM_SIZE(prg
));
444 goto bpf_append_blk_failure
;
448 /* transfer and translate the blocks to raw instructions */
449 for (iter
= 0; iter
< blk
->blk_cnt
; iter
++) {
450 i_iter
= &(prg
->blks
[old_cnt
+ iter
]);
452 i_iter
->code
= blk
->blks
[iter
].op
;
453 switch (blk
->blks
[iter
].jt
.type
) {
458 /* jump to the value specified */
459 i_iter
->jt
= blk
->blks
[iter
].jt
.tgt
.imm_j
;
462 /* fatal error - we should never get here */
464 goto bpf_append_blk_failure
;
466 switch (blk
->blks
[iter
].jf
.type
) {
471 /* jump to the value specified */
472 i_iter
->jf
= blk
->blks
[iter
].jf
.tgt
.imm_j
;
475 /* fatal error - we should never get here */
477 goto bpf_append_blk_failure
;
479 switch (blk
->blks
[iter
].k
.type
) {
484 i_iter
->k
= blk
->blks
[iter
].k
.tgt
.imm_k
;
487 /* fatal error - we should never get here */
489 goto bpf_append_blk_failure
;
495 bpf_append_blk_failure
:
502 * Free the BPF program
503 * @param prg the BPF program
505 * Free the BPF program. None of the associated BPF state used to generate the
506 * BPF program is released in this function.
509 static void _program_free(struct bpf_program
*prg
)
514 if (prg
->blks
!= NULL
)
521 * @param state the BPF state
523 * Free all of the BPF state, including the BPF program if present.
526 static void _state_release(struct bpf_state
*state
)
529 struct bpf_hash_bkt
*iter
;
534 /* release all of the hash table entries */
535 for (bkt
= 0; bkt
< _BPF_HASH_SIZE
; bkt
++) {
536 while (state
->htbl
[bkt
]) {
537 iter
= state
->htbl
[bkt
];
538 state
->htbl
[bkt
] = iter
->next
;
539 __blk_free(state
, iter
->blk
);
543 _program_free(state
->bpf
);
545 memset(state
, 0, sizeof(*state
));
549 * Add an instruction block to the BPF state hash table
550 * @param state the BPF state
551 * @param blk_p pointer to the BPF instruction block
552 * @param found initial found value (see _hsh_find_once() for description)
554 * This function adds an instruction block to the hash table, and frees the
555 * block if an identical instruction block already exists, returning a pointer
556 * to the original block in place of the given block. Returns zero on success
557 * and negative values on failure.
560 static int _hsh_add(struct bpf_state
*state
, struct bpf_blk
**blk_p
,
564 struct bpf_hash_bkt
*h_new
, *h_iter
, *h_prev
= NULL
;
565 struct bpf_blk
*blk
= *blk_p
;
566 struct bpf_blk
*b_iter
;
571 h_new
= malloc(sizeof(*h_new
));
574 memset(h_new
, 0, sizeof(*h_new
));
576 /* generate the hash */
577 h_val
= jhash(blk
->blks
, _BLK_MSZE(blk
), 0);
579 blk
->flag_hash
= true;
582 h_new
->found
= (found
? 1 : 0);
584 /* insert the block into the hash table */
586 h_iter
= state
->htbl
[h_val
& _BPF_HASH_MASK
];
587 if (h_iter
!= NULL
) {
589 if ((h_iter
->blk
->hash
== h_val
) &&
590 (_BLK_MSZE(h_iter
->blk
) == _BLK_MSZE(blk
)) &&
591 (memcmp(h_iter
->blk
->blks
, blk
->blks
,
592 _BLK_MSZE(blk
)) == 0)) {
593 /* duplicate block */
596 /* store the duplicate block */
597 b_iter
= h_iter
->blk
;
598 while (b_iter
->hash_nxt
!= NULL
)
599 b_iter
= b_iter
->hash_nxt
;
600 b_iter
->hash_nxt
= blk
;
602 /* in some cases we want to return the
605 blk
->flag_dup
= true;
609 /* update the priority if needed */
610 if (h_iter
->blk
->priority
< blk
->priority
)
611 h_iter
->blk
->priority
= blk
->priority
;
613 /* try to save some memory */
615 blk
->blks
= h_iter
->blk
->blks
;
616 blk
->flag_unique
= false;
618 *blk_p
= h_iter
->blk
;
620 } else if (h_iter
->blk
->hash
== h_val
) {
622 if ((h_val
>> 32) == 0xffffffff) {
624 blk
->flag_hash
= false;
629 h_val
+= ((uint64_t)1 << 32);
630 h_new
->blk
->hash
= h_val
;
632 /* restart at the beginning of the bucket */
633 goto hsh_add_restart
;
635 /* no match, move along */
637 h_iter
= h_iter
->next
;
639 } while (h_iter
!= NULL
);
640 h_prev
->next
= h_new
;
642 state
->htbl
[h_val
& _BPF_HASH_MASK
] = h_new
;
648 * Remove an entry from the hash table
649 * @param state the BPF state
650 * @param h_val the hash value
652 * Remove an entry from the hash table and return it to the caller, NULL is
653 * returned if the entry can not be found.
656 static struct bpf_blk
*_hsh_remove(struct bpf_state
*state
, uint64_t h_val
)
658 unsigned int bkt
= h_val
& _BPF_HASH_MASK
;
660 struct bpf_hash_bkt
*h_iter
, *h_prev
= NULL
;
662 h_iter
= state
->htbl
[bkt
];
663 while (h_iter
!= NULL
) {
664 if (h_iter
->blk
->hash
== h_val
) {
666 h_prev
->next
= h_iter
->next
;
668 state
->htbl
[bkt
] = h_iter
->next
;
674 h_iter
= h_iter
->next
;
681 * Find and return a hash bucket
682 * @param state the BPF state
683 * @param h_val the hash value
685 * Find the entry associated with the given hash value and return it to the
686 * caller, NULL is returned if the entry can not be found. This function
687 * should not be called directly; use _hsh_find() and _hsh_find_once() instead.
690 static struct bpf_hash_bkt
*_hsh_find_bkt(const struct bpf_state
*state
,
693 struct bpf_hash_bkt
*h_iter
;
695 h_iter
= state
->htbl
[h_val
& _BPF_HASH_MASK
];
696 while (h_iter
!= NULL
) {
697 if (h_iter
->blk
->hash
== h_val
)
699 h_iter
= h_iter
->next
;
706 * Find and only return an entry in the hash table once
707 * @param state the BPF state
708 * @param h_val the hash value
710 * Find the entry associated with the given hash value and return it to the
711 * caller if it has not be returned previously by this function; returns NULL
712 * if the entry can not be found or has already been returned in a previous
716 static struct bpf_blk
*_hsh_find_once(const struct bpf_state
*state
,
719 struct bpf_hash_bkt
*h_iter
;
721 h_iter
= _hsh_find_bkt(state
, h_val
);
722 if (h_iter
== NULL
|| h_iter
->found
!= 0)
729 * Finds an entry in the hash table
730 * @param state the BPF state
731 * @param h_val the hash value
733 * Find the entry associated with the given hash value and return it to the
734 * caller, NULL is returned if the entry can not be found.
737 static struct bpf_blk
*_hsh_find(const struct bpf_state
*state
, uint64_t h_val
)
739 struct bpf_hash_bkt
*h_iter
;
741 h_iter
= _hsh_find_bkt(state
, h_val
);
748 * Generate a BPF action instruction
749 * @param state the BPF state
750 * @param blk the BPF instruction block, or NULL
751 * @param action the desired action
753 * Generate a BPF action instruction and append it to the given instruction
754 * block. Returns a pointer to the instruction block on success, NULL on
758 static struct bpf_blk
*_gen_bpf_action(struct bpf_state
*state
,
759 struct bpf_blk
*blk
, uint32_t action
)
761 struct bpf_instr instr
;
763 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_RET
),
764 _BPF_JMP_NO
, _BPF_JMP_NO
, _BPF_K(state
->arch
, action
));
765 return _blk_append(state
, blk
, &instr
);
769 * Generate a BPF action instruction and insert it into the hash table
770 * @param state the BPF state
771 * @param action the desired action
773 * Generate a BPF action instruction and insert it into the hash table.
774 * Returns a pointer to the instruction block on success, NULL on failure.
777 static struct bpf_blk
*_gen_bpf_action_hsh(struct bpf_state
*state
,
782 blk
= _gen_bpf_action(state
, NULL
, action
);
785 if (_hsh_add(state
, &blk
, 0) < 0) {
786 _blk_free(state
, blk
);
794 * Generate a BPF instruction block for a given chain node
795 * @param state the BPF state
796 * @param node the filter chain node
797 * @param a_state the accumulator state
799 * Generate BPF instructions to execute the filter for the given chain node.
800 * Returns a pointer to the instruction block on success, NULL on failure.
803 static struct bpf_blk
*_gen_bpf_node(struct bpf_state
*state
,
804 const struct db_arg_chain_tree
*node
,
805 struct acc_state
*a_state
)
809 uint64_t act_t_hash
= 0, act_f_hash
= 0;
810 struct bpf_blk
*blk
, *b_act
;
811 struct bpf_instr instr
;
816 blk
->acc_start
= *a_state
;
818 /* generate the action blocks */
819 if (node
->act_t_flg
) {
820 b_act
= _gen_bpf_action_hsh(state
, node
->act_t
);
823 act_t_hash
= b_act
->hash
;
825 if (node
->act_f_flg
) {
826 b_act
= _gen_bpf_action_hsh(state
, node
->act_f
);
829 act_f_hash
= b_act
->hash
;
832 /* check the accumulator state */
833 acc_offset
= node
->arg_offset
;
834 acc_mask
= node
->mask
;
837 if ((acc_offset
!= a_state
->offset
) ||
838 ((acc_mask
& a_state
->mask
) != acc_mask
)) {
839 /* reload the accumulator */
840 a_state
->offset
= acc_offset
;
841 a_state
->mask
= ARG_MASK_MAX
;
842 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_LD
+ BPF_ABS
),
843 _BPF_JMP_NO
, _BPF_JMP_NO
,
844 _BPF_K(state
->arch
, acc_offset
));
845 blk
= _blk_append(state
, blk
, &instr
);
848 /* we're not dependent on the accumulator anymore */
849 blk
->acc_start
= _ACC_STATE_UNDEF
;
851 if (acc_mask
!= a_state
->mask
) {
852 /* apply the bitmask */
853 a_state
->mask
= acc_mask
;
854 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_ALU
+ BPF_AND
),
855 _BPF_JMP_NO
, _BPF_JMP_NO
,
856 _BPF_K(state
->arch
, acc_mask
));
857 blk
= _blk_append(state
, blk
, &instr
);
862 /* check the accumulator against the datum */
864 case SCMP_CMP_MASKED_EQ
:
866 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JEQ
),
867 _BPF_JMP_NO
, _BPF_JMP_NO
,
868 _BPF_K(state
->arch
, node
->datum
));
871 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JGT
),
872 _BPF_JMP_NO
, _BPF_JMP_NO
,
873 _BPF_K(state
->arch
, node
->datum
));
876 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JGE
),
877 _BPF_JMP_NO
, _BPF_JMP_NO
,
878 _BPF_K(state
->arch
, node
->datum
));
884 /* fatal error, we should never get here */
888 /* fixup the jump targets */
889 if (node
->nxt_t
!= NULL
)
890 instr
.jt
= _BPF_JMP_DB(node
->nxt_t
);
891 else if (node
->act_t_flg
)
892 instr
.jt
= _BPF_JMP_HSH(act_t_hash
);
894 instr
.jt
= _BPF_JMP_NXT(0);
895 if (node
->nxt_f
!= NULL
)
896 instr
.jf
= _BPF_JMP_DB(node
->nxt_f
);
897 else if (node
->act_f_flg
)
898 instr
.jf
= _BPF_JMP_HSH(act_f_hash
);
900 instr
.jf
= _BPF_JMP_NXT(0);
901 blk
= _blk_append(state
, blk
, &instr
);
906 blk
->acc_end
= *a_state
;
910 _blk_free(state
, blk
);
915 * Resolve the jump targets in a BPF instruction block
916 * @param state the BPF state
917 * @param sys the syscall filter
918 * @param blk the BPF instruction block
919 * @param nxt_jump the jump to fallthrough to at the end of the level
921 * Resolve the jump targets in a BPF instruction block generated by the
922 * _gen_bpf_chain_lvl() function and adds the resulting block to the hash
923 * table. Returns a pointer to the new instruction block on success, NULL on
927 static struct bpf_blk
*_gen_bpf_chain_lvl_res(struct bpf_state
*state
,
928 const struct db_sys_list
*sys
,
930 const struct bpf_jump
*nxt_jump
)
934 struct bpf_blk
*b_new
;
935 struct bpf_instr
*i_iter
;
936 struct db_arg_chain_tree
*node
;
941 /* convert TGT_PTR_DB to TGT_PTR_HSH references */
942 for (iter
= 0; iter
< blk
->blk_cnt
; iter
++) {
943 i_iter
= &blk
->blks
[iter
];
944 switch (i_iter
->jt
.type
) {
948 /* ignore these jump types */
951 b_new
= _gen_bpf_chain_lvl_res(state
, sys
,
956 i_iter
->jt
= _BPF_JMP_HSH(b_new
->hash
);
959 node
= (struct db_arg_chain_tree
*)i_iter
->jt
.tgt
.db
;
960 b_new
= _gen_bpf_chain(state
, sys
, node
,
961 nxt_jump
, &blk
->acc_start
);
964 i_iter
->jt
= _BPF_JMP_HSH(b_new
->hash
);
967 /* we should not be here */
970 switch (i_iter
->jf
.type
) {
974 /* ignore these jump types */
977 b_new
= _gen_bpf_chain_lvl_res(state
, sys
,
982 i_iter
->jf
= _BPF_JMP_HSH(b_new
->hash
);
985 node
= (struct db_arg_chain_tree
*)i_iter
->jf
.tgt
.db
;
986 b_new
= _gen_bpf_chain(state
, sys
, node
,
987 nxt_jump
, &blk
->acc_start
);
990 i_iter
->jf
= _BPF_JMP_HSH(b_new
->hash
);
993 /* we should not be here */
996 switch (i_iter
->k
.type
) {
1000 /* ignore these jump types */
1003 /* we should not be here */
1008 /* insert the block into the hash table */
1009 rc
= _hsh_add(state
, &blk
, 0);
1017 * Generates the BPF instruction blocks for a given filter chain
1018 * @param state the BPF state
1019 * @param sys the syscall filter
1020 * @param chain the filter chain
1021 * @param nxt_jump the jump to fallthrough to at the end of the level
1022 * @param a_state the accumulator state
1024 * Generate the BPF instruction blocks for the given filter chain and return
1025 * a pointer to the first block on success; returns NULL on failure.
1028 static struct bpf_blk
*_gen_bpf_chain(struct bpf_state
*state
,
1029 const struct db_sys_list
*sys
,
1030 const struct db_arg_chain_tree
*chain
,
1031 const struct bpf_jump
*nxt_jump
,
1032 struct acc_state
*a_state
)
1034 struct bpf_blk
*b_head
= NULL
, *b_tail
= NULL
;
1035 struct bpf_blk
*b_prev
, *b_next
, *b_iter
;
1036 struct bpf_instr
*i_iter
;
1037 const struct db_arg_chain_tree
*c_iter
;
1039 struct bpf_jump nxt_jump_tmp
;
1040 struct acc_state acc
= *a_state
;
1042 if (chain
== NULL
) {
1043 b_head
= _gen_bpf_action(state
, NULL
, sys
->action
);
1048 /* find the starting node of the level */
1050 while (c_iter
->lvl_prv
!= NULL
)
1051 c_iter
= c_iter
->lvl_prv
;
1053 /* build all of the blocks for this level */
1055 b_iter
= _gen_bpf_node(state
, c_iter
, &acc
);
1058 if (b_head
!= NULL
) {
1059 b_iter
->lvl_prv
= b_tail
;
1060 b_tail
->lvl_nxt
= b_iter
;
1066 c_iter
= c_iter
->lvl_nxt
;
1067 } while (c_iter
!= NULL
);
1069 /* resolve the TGT_NXT jumps */
1072 b_next
= b_iter
->lvl_nxt
;
1073 for (iter
= 0; iter
< b_iter
->blk_cnt
; iter
++) {
1074 i_iter
= &b_iter
->blks
[iter
];
1075 if (i_iter
->jt
.type
== TGT_NXT
) {
1076 if (i_iter
->jt
.tgt
.nxt
!= 0)
1079 i_iter
->jt
= *nxt_jump
;
1082 _BPF_JMP_BLK(b_next
);
1084 if (i_iter
->jf
.type
== TGT_NXT
) {
1085 if (i_iter
->jf
.tgt
.nxt
!= 0)
1088 i_iter
->jf
= *nxt_jump
;
1091 _BPF_JMP_BLK(b_next
);
1095 } while (b_iter
!= NULL
);
1098 /* resolve all of the blocks */
1099 memset(&nxt_jump_tmp
, 0, sizeof(nxt_jump_tmp
));
1102 /* b_iter may change after resolving, so save the linkage */
1103 b_prev
= b_iter
->lvl_prv
;
1104 b_next
= b_iter
->lvl_nxt
;
1106 nxt_jump_tmp
= _BPF_JMP_BLK(b_next
);
1107 b_iter
= _gen_bpf_chain_lvl_res(state
, sys
, b_iter
,
1114 /* restore the block linkage on this level */
1116 b_prev
->lvl_nxt
= b_iter
;
1117 b_iter
->lvl_prv
= b_prev
;
1118 b_iter
->lvl_nxt
= b_next
;
1120 b_next
->lvl_prv
= b_iter
;
1121 if (b_iter
->lvl_prv
== NULL
)
1125 } while (b_iter
!= NULL
);
1130 while (b_head
!= NULL
) {
1132 b_head
= b_iter
->lvl_nxt
;
1133 _blk_free(state
, b_iter
);
1139 * Generate the BPF instruction blocks for a given syscall
1140 * @param state the BPF state
1141 * @param sys the syscall filter DB entry
1142 * @param nxt_hash the hash value of the next syscall filter DB entry
1143 * @param acc_reset accumulator reset flag
1145 * Generate the BPF instruction blocks for the given syscall filter and return
1146 * a pointer to the first block on success; returns NULL on failure. It is
1147 * important to note that the block returned has not been added to the hash
1148 * table, however, any linked/referenced blocks have been added to the hash
1152 static struct bpf_blk
*_gen_bpf_syscall(struct bpf_state
*state
,
1153 const struct db_sys_list
*sys
,
1158 struct bpf_instr instr
;
1159 struct bpf_blk
*blk_c
, *blk_s
;
1160 struct bpf_jump def_jump
;
1161 struct acc_state a_state
;
1163 /* we do the memset before the assignment to keep valgrind happy */
1164 memset(&def_jump
, 0, sizeof(def_jump
));
1165 def_jump
= _BPF_JMP_HSH(state
->def_hsh
);
1167 blk_s
= _blk_alloc();
1171 /* setup the accumulator state */
1173 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_LD
+ BPF_ABS
),
1174 _BPF_JMP_NO
, _BPF_JMP_NO
,
1175 _BPF_SYSCALL(state
->arch
));
1176 blk_s
= _blk_append(state
, blk_s
, &instr
);
1179 /* we've loaded the syscall ourselves */
1180 a_state
= _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL
);
1181 blk_s
->acc_start
= _ACC_STATE_UNDEF
;
1182 blk_s
->acc_end
= _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL
);
1184 /* we rely on someone else to load the syscall */
1185 a_state
= _ACC_STATE_UNDEF
;
1186 blk_s
->acc_start
= _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL
);
1187 blk_s
->acc_end
= _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL
);
1190 /* generate the argument chains */
1191 blk_c
= _gen_bpf_chain(state
, sys
, sys
->chains
, &def_jump
, &a_state
);
1192 if (blk_c
== NULL
) {
1193 _blk_free(state
, blk_s
);
1198 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JEQ
),
1199 _BPF_JMP_HSH(blk_c
->hash
), _BPF_JMP_HSH(nxt_hash
),
1200 _BPF_K(state
->arch
, sys
->num
));
1201 blk_s
= _blk_append(state
, blk_s
, &instr
);
1204 blk_s
->priority
= sys
->priority
;
1206 /* add to the hash table */
1207 rc
= _hsh_add(state
, &blk_s
, 1);
1209 _blk_free(state
, blk_s
);
1217 * Generate the BPF instruction blocks for a given filter/architecture
1218 * @param state the BPF state
1219 * @param db the filter DB
1220 * @param db_secondary the secondary DB
1222 * Generate the BPF instruction block for the given filter DB(s)/architecture(s)
1223 * and return a pointer to the block on succes, NULL on failure. The resulting
1224 * block assumes that the architecture token has already been loaded into the
1228 static struct bpf_blk
*_gen_bpf_arch(struct bpf_state
*state
,
1229 const struct db_filter
*db
,
1230 const struct db_filter
*db_secondary
)
1233 unsigned int blk_cnt
= 0;
1235 struct bpf_instr instr
;
1236 struct db_sys_list
*s_head
= NULL
, *s_tail
= NULL
, *s_iter
, *s_iter_b
;
1237 struct bpf_blk
*b_head
= NULL
, *b_tail
= NULL
, *b_iter
, *b_new
;
1239 state
->arch
= db
->arch
;
1241 /* sort the syscall list */
1242 db_list_foreach(s_iter
, db
->syscalls
) {
1243 if (s_head
!= NULL
) {
1245 while ((s_iter_b
->pri_nxt
!= NULL
) &&
1246 (s_iter
->priority
<= s_iter_b
->priority
))
1247 s_iter_b
= s_iter_b
->pri_nxt
;
1249 if (s_iter
->priority
> s_iter_b
->priority
) {
1250 s_iter
->pri_prv
= s_iter_b
->pri_prv
;
1251 s_iter
->pri_nxt
= s_iter_b
;
1252 if (s_iter_b
== s_head
) {
1253 s_head
->pri_prv
= s_iter
;
1256 s_iter
->pri_prv
->pri_nxt
= s_iter
;
1257 s_iter
->pri_nxt
->pri_prv
= s_iter
;
1260 s_iter
->pri_prv
= s_tail
;
1261 s_iter
->pri_nxt
= NULL
;
1262 s_iter
->pri_prv
->pri_nxt
= s_iter
;
1268 s_head
->pri_prv
= NULL
;
1269 s_head
->pri_nxt
= NULL
;
1272 if (db_secondary
!= NULL
) {
1273 db_list_foreach(s_iter
, db_secondary
->syscalls
) {
1274 if (s_head
!= NULL
) {
1276 while ((s_iter_b
->pri_nxt
!= NULL
) &&
1277 (s_iter
->priority
<= s_iter_b
->priority
))
1278 s_iter_b
= s_iter_b
->pri_nxt
;
1280 if (s_iter
->priority
> s_iter_b
->priority
) {
1281 s_iter
->pri_prv
= s_iter_b
->pri_prv
;
1282 s_iter
->pri_nxt
= s_iter_b
;
1283 if (s_iter_b
== s_head
) {
1284 s_head
->pri_prv
= s_iter
;
1287 s_iter
->pri_prv
->pri_nxt
=
1289 s_iter
->pri_nxt
->pri_prv
=
1293 s_iter
->pri_prv
= s_tail
;
1294 s_iter
->pri_nxt
= NULL
;
1295 s_iter
->pri_prv
->pri_nxt
= s_iter
;
1301 s_head
->pri_prv
= NULL
;
1302 s_head
->pri_nxt
= NULL
;
1307 if ((state
->arch
->token
== SCMP_ARCH_X86_64
||
1308 state
->arch
->token
== SCMP_ARCH_X32
) && (db_secondary
== NULL
))
1313 /* create the syscall filters and add them to block list group */
1314 for (s_iter
= s_tail
; s_iter
!= NULL
; s_iter
= s_iter
->pri_prv
) {
1318 /* build the syscall filter */
1319 b_new
= _gen_bpf_syscall(state
, s_iter
,
1321 state
->def_hsh
: b_head
->hash
),
1323 acc_reset
: false));
1327 /* add the filter to the list head */
1329 b_new
->next
= b_head
;
1330 if (b_tail
!= NULL
) {
1331 b_head
->prev
= b_new
;
1338 if (b_tail
->next
!= NULL
)
1339 b_tail
= b_tail
->next
;
1343 /* additional ABI filtering */
1344 if ((state
->arch
->token
== SCMP_ARCH_X86_64
||
1345 state
->arch
->token
== SCMP_ARCH_X32
) && (db_secondary
== NULL
)) {
1346 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_LD
+ BPF_ABS
),
1347 _BPF_JMP_NO
, _BPF_JMP_NO
, _BPF_SYSCALL(state
->arch
));
1348 b_new
= _blk_append(state
, NULL
, &instr
);
1351 b_new
->acc_end
= _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL
);
1352 if (state
->arch
->token
== SCMP_ARCH_X86_64
) {
1353 /* filter out x32 */
1355 _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JGE
),
1356 _BPF_JMP_HSH(state
->bad_arch_hsh
),
1358 _BPF_K(state
->arch
, X32_SYSCALL_BIT
));
1360 instr
.jf
= _BPF_JMP_HSH(b_head
->hash
);
1362 instr
.jf
= _BPF_JMP_HSH(state
->def_hsh
);
1364 } else if (state
->arch
->token
== SCMP_ARCH_X32
) {
1365 /* filter out x86_64 */
1367 _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JGE
),
1369 _BPF_JMP_HSH(state
->bad_arch_hsh
),
1370 _BPF_K(state
->arch
, X32_SYSCALL_BIT
));
1372 instr
.jt
= _BPF_JMP_HSH(b_head
->hash
);
1374 instr
.jt
= _BPF_JMP_HSH(state
->def_hsh
);
1377 /* we should never get here */
1379 b_new
= _blk_append(state
, b_new
, &instr
);
1382 b_new
->next
= b_head
;
1384 b_head
->prev
= b_new
;
1386 rc
= _hsh_add(state
, &b_head
, 1);
1391 /* do the ABI/architecture check */
1392 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JEQ
),
1393 _BPF_JMP_NO
, _BPF_JMP_NXT(blk_cnt
++),
1394 _BPF_K(state
->arch
, state
->arch
->token_bpf
));
1396 instr
.jt
= _BPF_JMP_HSH(b_head
->hash
);
1398 instr
.jt
= _BPF_JMP_HSH(state
->def_hsh
);
1399 b_new
= _blk_append(state
, NULL
, &instr
);
1402 b_new
->next
= b_head
;
1404 b_head
->prev
= b_new
;
1406 rc
= _hsh_add(state
, &b_head
, 1);
1414 /* NOTE: we do the cleanup here and not just return an error as all of
1415 * the instruction blocks may not be added to the hash table when we
1419 while (b_iter
!= NULL
) {
1420 b_new
= b_iter
->next
;
1421 _blk_free(state
, b_iter
);
1428 * Find the target block for the "next" jump
1429 * @param blk the instruction block
1430 * @param nxt the next offset
1432 * Find the target block for the TGT_NXT jump using the given offset. Returns
1433 * a pointer to the target block on success or NULL on failure.
1436 static struct bpf_blk
*_gen_bpf_find_nxt(const struct bpf_blk
*blk
,
1439 struct bpf_blk
*iter
= blk
->next
;
1441 for (; (iter
!= NULL
) && (nxt
> 0); nxt
--)
1448 * Manage jumps to return instructions
1449 * @param state the BPF state
1450 * @param blk the instruction block to check
1451 * @param offset the instruction offset into the instruction block
1452 * @param blk_ret the return instruction block
1454 * Using the given block and instruction offset, calculate the jump distance
1455 * between the jumping instruction and return instruction block. If the jump
1456 * distance is too great, duplicate the return instruction to reduce the
1457 * distance to the maximum value. Returns 1 if a long jump was added, zero if
1458 * the existing jump is valid, and negative values on failure.
1461 static int _gen_bpf_build_jmp_ret(struct bpf_state
*state
,
1462 struct bpf_blk
*blk
, unsigned int offset
,
1463 struct bpf_blk
*blk_ret
)
1466 uint64_t tgt_hash
= blk_ret
->hash
;
1467 struct bpf_blk
*b_jmp
, *b_new
;
1469 /* calculate the jump distance */
1470 j_len
= blk
->blk_cnt
- (offset
+ 1);
1472 while (b_jmp
!= NULL
&& b_jmp
!= blk_ret
&& j_len
< _BPF_JMP_MAX_RET
) {
1473 j_len
+= b_jmp
->blk_cnt
;
1474 b_jmp
= b_jmp
->next
;
1478 if (j_len
<= _BPF_JMP_MAX_RET
&& b_jmp
== blk_ret
)
1481 /* we need a closer return instruction, see if one already exists */
1482 j_len
= blk
->blk_cnt
- (offset
+ 1);
1484 while (b_jmp
!= NULL
&& b_jmp
->hash
!= tgt_hash
&&
1485 j_len
< _BPF_JMP_MAX_RET
) {
1486 j_len
+= b_jmp
->blk_cnt
;
1487 b_jmp
= b_jmp
->next
;
1491 if (j_len
<= _BPF_JMP_MAX_RET
&& b_jmp
->hash
== tgt_hash
)
1494 /* we need to insert a new return instruction - create one */
1495 b_new
= _gen_bpf_action(state
, NULL
, blk_ret
->blks
[0].k
.tgt
.imm_k
);
1499 /* NOTE - we need to be careful here, we're giving the block a hash
1500 * value (this is a sneaky way to ensure we leverage the
1501 * inserted long jumps as much as possible) but we never add the
1502 * block to the hash table so it won't get cleaned up
1504 b_new
->hash
= tgt_hash
;
1506 /* insert the jump after the current jumping block */
1508 b_new
->next
= blk
->next
;
1509 blk
->next
->prev
= b_new
;
1516 * Manage jump lengths by duplicating and adding jumps if needed
1517 * @param state the BPF state
1518 * @param tail the tail of the instruction block list
1519 * @param blk the instruction block to check
1520 * @param offset the instruction offset into the instruction block
1521 * @param tgt_hash the hash of the jump destination block
1523 * Using the given block and instruction offset, calculate the jump distance
1524 * between the jumping instruction and the destination. If the jump distance
1525 * is too great, add a long jump instruction to reduce the distance to a legal
1526 * value. Returns 1 if a new instruction was added, zero if the existing jump
1527 * is valid, and negative values on failure.
1530 static int _gen_bpf_build_jmp(struct bpf_state
*state
,
1531 struct bpf_blk
*tail
,
1532 struct bpf_blk
*blk
, unsigned int offset
,
1536 unsigned int jmp_len
;
1537 struct bpf_instr instr
;
1538 struct bpf_blk
*b_new
, *b_jmp
, *b_tgt
;
1540 /* find the jump target */
1542 while (b_tgt
!= blk
&& b_tgt
->hash
!= tgt_hash
)
1543 b_tgt
= b_tgt
->prev
;
1547 if (b_tgt
->blk_cnt
== 1 &&
1548 b_tgt
->blks
[0].op
== _BPF_OP(state
->arch
, BPF_RET
)) {
1549 rc
= _gen_bpf_build_jmp_ret(state
, blk
, offset
, b_tgt
);
1556 /* calculate the jump distance */
1557 jmp_len
= blk
->blk_cnt
- (offset
+ 1);
1559 while (b_jmp
!= NULL
&& b_jmp
!= b_tgt
&& jmp_len
< _BPF_JMP_MAX
) {
1560 jmp_len
+= b_jmp
->blk_cnt
;
1561 b_jmp
= b_jmp
->next
;
1565 if (jmp_len
<= _BPF_JMP_MAX
&& b_jmp
== b_tgt
)
1568 /* we need a long jump, see if one already exists */
1569 jmp_len
= blk
->blk_cnt
- (offset
+ 1);
1571 while (b_jmp
!= NULL
&& b_jmp
->hash
!= tgt_hash
&&
1572 jmp_len
< _BPF_JMP_MAX
) {
1573 jmp_len
+= b_jmp
->blk_cnt
;
1574 b_jmp
= b_jmp
->next
;
1578 if (jmp_len
<= _BPF_JMP_MAX
&& b_jmp
->hash
== tgt_hash
)
1581 /* we need to insert a long jump - create one */
1582 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_JMP
+ BPF_JA
),
1583 _BPF_JMP_NO
, _BPF_JMP_NO
, _BPF_JMP_HSH(tgt_hash
));
1584 b_new
= _blk_append(state
, NULL
, &instr
);
1588 /* NOTE - we need to be careful here, we're giving the block a hash
1589 * value (this is a sneaky way to ensure we leverage the
1590 * inserted long jumps as much as possible) but we never add the
1591 * block to the hash table so it won't get cleaned up
1593 b_new
->hash
= tgt_hash
;
1595 /* insert the jump after the current jumping block */
1597 b_new
->next
= blk
->next
;
1598 blk
->next
->prev
= b_new
;
1605 * Generate the BPF program for the given filter collection
1606 * @param state the BPF state
1607 * @param col the filter collection
1609 * Generate the BPF program for the given filter collection. Returns zero on
1610 * success, negative values on failure.
1613 static int _gen_bpf_build_bpf(struct bpf_state
*state
,
1614 const struct db_filter_col
*col
)
1619 unsigned int res_cnt
;
1620 unsigned int jmp_len
;
1621 int arch_x86_64
= -1, arch_x32
= -1;
1622 struct bpf_instr instr
;
1623 struct bpf_instr
*i_iter
;
1624 struct bpf_blk
*b_badarch
, *b_default
;
1625 struct bpf_blk
*b_head
= NULL
, *b_tail
= NULL
, *b_iter
, *b_new
, *b_jmp
;
1626 struct db_filter
*db_secondary
= NULL
;
1627 struct arch_def pseudo_arch
;
1629 if (col
->filter_cnt
== 0)
1632 /* create a fake architecture definition for use in the early stages */
1633 memset(&pseudo_arch
, 0, sizeof(pseudo_arch
));
1634 pseudo_arch
.endian
= col
->endian
;
1635 state
->arch
= &pseudo_arch
;
1637 /* generate the badarch action */
1638 b_badarch
= _gen_bpf_action(state
, NULL
, state
->attr
->act_badarch
);
1639 if (b_badarch
== NULL
)
1641 rc
= _hsh_add(state
, &b_badarch
, 1);
1644 state
->bad_arch_hsh
= b_badarch
->hash
;
1646 /* generate the default action */
1647 b_default
= _gen_bpf_action(state
, NULL
, state
->attr
->act_default
);
1648 if (b_default
== NULL
)
1650 rc
= _hsh_add(state
, &b_default
, 0);
1653 state
->def_hsh
= b_default
->hash
;
1655 /* load the architecture token/number */
1656 _BPF_INSTR(instr
, _BPF_OP(state
->arch
, BPF_LD
+ BPF_ABS
),
1657 _BPF_JMP_NO
, _BPF_JMP_NO
, _BPF_ARCH(state
->arch
));
1658 b_head
= _blk_append(state
, NULL
, &instr
);
1661 b_head
->acc_end
= _ACC_STATE_OFFSET(_BPF_OFFSET_ARCH
);
1662 rc
= _hsh_add(state
, &b_head
, 1);
1667 /* generate the per-architecture filters */
1668 for (iter
= 0; iter
< col
->filter_cnt
; iter
++) {
1669 if (col
->filters
[iter
]->arch
->token
== SCMP_ARCH_X86_64
)
1671 if (col
->filters
[iter
]->arch
->token
== SCMP_ARCH_X32
)
1674 for (iter
= 0; iter
< col
->filter_cnt
; iter
++) {
1675 /* figure out the secondary arch filter mess */
1676 if (iter
== arch_x86_64
) {
1677 if (arch_x32
> iter
)
1678 db_secondary
= col
->filters
[arch_x32
];
1679 else if (arch_x32
>= 0)
1681 } else if (iter
== arch_x32
) {
1682 if (arch_x86_64
> iter
)
1683 db_secondary
= col
->filters
[arch_x86_64
];
1684 else if (arch_x86_64
>= 0)
1687 db_secondary
= NULL
;
1689 /* create the filter for the architecture(s) */
1690 b_new
= _gen_bpf_arch(state
, col
->filters
[iter
], db_secondary
);
1693 b_new
->prev
= b_tail
;
1694 b_tail
->next
= b_new
;
1696 while (b_tail
->next
!= NULL
)
1697 b_tail
= b_tail
->next
;
1700 /* add a badarch action to the end */
1701 b_badarch
->prev
= b_tail
;
1702 b_badarch
->next
= NULL
;
1703 b_tail
->next
= b_badarch
;
1706 /* reset the state to the pseudo_arch for the final resolution */
1707 state
->arch
= &pseudo_arch
;
1709 /* resolve any TGT_NXT jumps at the top level */
1712 for (iter
= 0; iter
< b_iter
->blk_cnt
; iter
++) {
1713 i_iter
= &b_iter
->blks
[iter
];
1714 if (i_iter
->jt
.type
== TGT_NXT
) {
1715 b_jmp
= _gen_bpf_find_nxt(b_iter
,
1716 i_iter
->jt
.tgt
.nxt
);
1719 i_iter
->jt
= _BPF_JMP_HSH(b_jmp
->hash
);
1721 if (i_iter
->jf
.type
== TGT_NXT
) {
1722 b_jmp
= _gen_bpf_find_nxt(b_iter
,
1723 i_iter
->jf
.tgt
.nxt
);
1726 i_iter
->jf
= _BPF_JMP_HSH(b_jmp
->hash
);
1728 /* we shouldn't need to worry about a TGT_NXT in k */
1730 b_iter
= b_iter
->next
;
1731 } while (b_iter
!= NULL
&& b_iter
->next
!= NULL
);
1733 /* pull in all of the TGT_PTR_HSH jumps, one layer at a time */
1737 /* look for jumps - backwards (shorter jumps) */
1738 for (iter
= b_iter
->blk_cnt
- 1;
1739 (iter
>= 0) && (b_jmp
== NULL
);
1741 i_iter
= &b_iter
->blks
[iter
];
1742 if (i_iter
->jt
.type
== TGT_PTR_HSH
)
1743 b_jmp
= _hsh_find_once(state
,
1744 i_iter
->jt
.tgt
.hash
);
1745 if (b_jmp
== NULL
&& i_iter
->jf
.type
== TGT_PTR_HSH
)
1746 b_jmp
= _hsh_find_once(state
,
1747 i_iter
->jf
.tgt
.hash
);
1748 if (b_jmp
== NULL
&& i_iter
->k
.type
== TGT_PTR_HSH
)
1749 b_jmp
= _hsh_find_once(state
,
1750 i_iter
->k
.tgt
.hash
);
1751 if (b_jmp
!= NULL
) {
1752 /* do we need to reload the accumulator? */
1753 if ((b_jmp
->acc_start
.offset
!= -1) &&
1754 !_ACC_CMP_EQ(b_iter
->acc_end
,
1755 b_jmp
->acc_start
)) {
1756 if (b_jmp
->acc_start
.mask
!= ARG_MASK_MAX
) {
1758 _BPF_OP(state
->arch
,
1763 b_jmp
->acc_start
.mask
));
1764 b_jmp
= _blk_prepend(state
,
1771 _BPF_OP(state
->arch
,
1773 _BPF_JMP_NO
, _BPF_JMP_NO
,
1775 b_jmp
->acc_start
.offset
));
1776 b_jmp
= _blk_prepend(state
,
1780 /* not reliant on the accumulator */
1781 b_jmp
->acc_start
= _ACC_STATE_UNDEF
;
1783 /* insert the new block after this block */
1784 b_jmp
->prev
= b_iter
;
1785 b_jmp
->next
= b_iter
->next
;
1786 b_iter
->next
= b_jmp
;
1788 b_jmp
->next
->prev
= b_jmp
;
1791 if (b_jmp
!= NULL
) {
1792 while (b_tail
->next
!= NULL
)
1793 b_tail
= b_tail
->next
;
1796 b_iter
= b_iter
->prev
;
1797 } while (b_iter
!= NULL
);
1800 /* NOTE - from here to the end of the function we need to fail via the
1801 * the build_bpf_free_blks label, not just return an error; see
1802 * the _gen_bpf_build_jmp() function for details */
1804 /* check for long jumps and insert if necessary, we also verify that
1805 * all our jump targets are valid at this point in the process */
1809 for (iter
= b_iter
->blk_cnt
- 1; iter
>= 0; iter
--) {
1810 i_iter
= &b_iter
->blks
[iter
];
1811 switch (i_iter
->jt
.type
) {
1816 h_val
= i_iter
->jt
.tgt
.hash
;
1817 rc
= _gen_bpf_build_jmp(state
, b_tail
,
1821 goto build_bpf_free_blks
;
1826 goto build_bpf_free_blks
;
1828 switch (i_iter
->jf
.type
) {
1833 h_val
= i_iter
->jf
.tgt
.hash
;
1834 rc
= _gen_bpf_build_jmp(state
, b_tail
,
1838 goto build_bpf_free_blks
;
1843 goto build_bpf_free_blks
;
1847 b_iter
= b_iter
->prev
;
1848 } while (b_iter
!= NULL
);
1850 /* build the bpf program */
1853 /* resolve the TGT_PTR_HSH jumps */
1854 for (iter
= 0; iter
< b_iter
->blk_cnt
; iter
++) {
1855 i_iter
= &b_iter
->blks
[iter
];
1856 if (i_iter
->jt
.type
== TGT_PTR_HSH
) {
1857 h_val
= i_iter
->jt
.tgt
.hash
;
1858 jmp_len
= b_iter
->blk_cnt
- (iter
+ 1);
1859 b_jmp
= b_iter
->next
;
1860 while (b_jmp
!= NULL
&& b_jmp
->hash
!= h_val
) {
1861 jmp_len
+= b_jmp
->blk_cnt
;
1862 b_jmp
= b_jmp
->next
;
1864 if (b_jmp
== NULL
|| jmp_len
> _BPF_JMP_MAX
)
1865 goto build_bpf_free_blks
;
1866 i_iter
->jt
= _BPF_JMP_IMM(jmp_len
);
1868 if (i_iter
->jf
.type
== TGT_PTR_HSH
) {
1869 h_val
= i_iter
->jf
.tgt
.hash
;
1870 jmp_len
= b_iter
->blk_cnt
- (iter
+ 1);
1871 b_jmp
= b_iter
->next
;
1872 while (b_jmp
!= NULL
&& b_jmp
->hash
!= h_val
) {
1873 jmp_len
+= b_jmp
->blk_cnt
;
1874 b_jmp
= b_jmp
->next
;
1876 if (b_jmp
== NULL
|| jmp_len
> _BPF_JMP_MAX
)
1877 goto build_bpf_free_blks
;
1878 i_iter
->jf
= _BPF_JMP_IMM(jmp_len
);
1880 if (i_iter
->k
.type
== TGT_PTR_HSH
) {
1881 h_val
= i_iter
->k
.tgt
.hash
;
1882 jmp_len
= b_iter
->blk_cnt
- (iter
+ 1);
1884 while (b_jmp
->hash
!= h_val
)
1885 b_jmp
= b_jmp
->prev
;
1886 b_jmp
= b_jmp
->prev
;
1887 while (b_jmp
!= b_iter
) {
1888 jmp_len
+= b_jmp
->blk_cnt
;
1889 b_jmp
= b_jmp
->prev
;
1892 goto build_bpf_free_blks
;
1893 i_iter
->k
= _BPF_K(state
->arch
, jmp_len
);
1897 /* build the bpf program */
1898 if (_bpf_append_blk(state
->bpf
, b_iter
) < 0)
1899 goto build_bpf_free_blks
;
1901 /* we're done with the block, free it */
1902 b_head
= b_iter
->next
;
1903 _blk_free(state
, b_iter
);
1904 } while (b_head
!= NULL
);
1908 build_bpf_free_blks
:
1910 while (b_iter
!= NULL
) {
1911 b_jmp
= b_iter
->next
;
1912 _hsh_remove(state
, b_iter
->hash
);
1913 __blk_free(state
, b_iter
);
1920 * Generate a BPF representation of the filter DB
1921 * @param col the seccomp filter collection
1923 * This function generates a BPF representation of the given filter collection.
1924 * Returns a pointer to a valid bpf_program on success, NULL on failure.
1927 struct bpf_program
*gen_bpf_generate(const struct db_filter_col
*col
)
1930 struct bpf_state state
;
1932 memset(&state
, 0, sizeof(state
));
1933 state
.attr
= &col
->attr
;
1935 state
.bpf
= malloc(sizeof(*(state
.bpf
)));
1936 if (state
.bpf
== NULL
)
1938 memset(state
.bpf
, 0, sizeof(*(state
.bpf
)));
1940 rc
= _gen_bpf_build_bpf(&state
, col
);
1942 goto bpf_generate_end
;
1946 _state_release(&state
);
1951 * Free memory associated with a BPF representation
1952 * @param program the BPF representation
1954 * Free the memory associated with a BPF representation generated by the
1955 * gen_bpf_generate() function.
1958 void gen_bpf_release(struct bpf_program
*program
)
1960 _program_free(program
);
This page took 0.150541 seconds and 4 git commands to generate.