2 * Seccomp Pseudo Filter Code (PFC) Generator
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>.
29 /* NOTE: needed for the arch->token decoding in _pfc_arch() */
30 #include <linux/audit.h>
39 struct db_sys_list
*sys
;
40 struct pfc_sys_list
*next
;
43 /* XXX - we should check the fprintf() return values */
46 * Display a string representation of the architecture
47 * @param arch the architecture definition
49 static const char *_pfc_arch(const struct arch_def
*arch
)
51 switch (arch
->token
) {
54 case SCMP_ARCH_X86_64
:
60 case SCMP_ARCH_AARCH64
:
64 case SCMP_ARCH_MIPSEL
:
66 case SCMP_ARCH_MIPS64
:
68 case SCMP_ARCH_MIPSEL64
:
70 case SCMP_ARCH_MIPS64N32
:
72 case SCMP_ARCH_MIPSEL64N32
:
76 case SCMP_ARCH_PPC64LE
:
90 * Display a string representation of the node argument
91 * @param fds the file stream to send the output
92 * @param arch the architecture definition
93 * @param node the node
95 static void _pfc_arg(FILE *fds
,
96 const struct arch_def
*arch
,
97 const struct db_arg_chain_tree
*node
)
99 if (arch
->size
== ARCH_SIZE_64
) {
100 if (arch_arg_offset_hi(arch
, node
->arg
) == node
->arg_offset
)
101 fprintf(fds
, "$a%d.hi32", node
->arg
);
103 fprintf(fds
, "$a%d.lo32", node
->arg
);
105 fprintf(fds
, "$a%d", node
->arg
);
109 * Display a string representation of the filter action
110 * @param fds the file stream to send the output
111 * @param action the action
113 static void _pfc_action(FILE *fds
, uint32_t action
)
115 switch (action
& 0xffff0000) {
117 fprintf(fds
, "action KILL;\n");
120 fprintf(fds
, "action TRAP;\n");
122 case SCMP_ACT_ERRNO(0):
123 fprintf(fds
, "action ERRNO(%u);\n", (action
& 0x0000ffff));
125 case SCMP_ACT_TRACE(0):
126 fprintf(fds
, "action TRACE(%u);\n", (action
& 0x0000ffff));
129 fprintf(fds
, "action ALLOW;\n");
132 fprintf(fds
, "action 0x%x;\n", action
);
137 * Indent the output stream
138 * @param fds the file stream to send the output
139 * @param lvl the indentation level
141 * This function indents the output stream with whitespace based on the
142 * requested indentation level.
144 static void _indent(FILE *fds
, unsigned int lvl
)
151 * Generate the pseudo filter code for an argument chain
152 * @param arch the architecture definition
153 * @param node the head of the argument chain
154 * @param lvl the indentation level
155 * @param fds the file stream to send the output
157 * This function generates the pseudo filter code representation of the given
158 * argument chain and writes it to the given output stream.
161 static void _gen_pfc_chain(const struct arch_def
*arch
,
162 const struct db_arg_chain_tree
*node
,
163 unsigned int lvl
, FILE *fds
)
165 const struct db_arg_chain_tree
*c_iter
;
167 /* get to the start */
169 while (c_iter
->lvl_prv
!= NULL
)
170 c_iter
= c_iter
->lvl_prv
;
172 while (c_iter
!= NULL
) {
173 /* comparison operation */
175 fprintf(fds
, "if (");
176 _pfc_arg(fds
, arch
, c_iter
);
177 switch (c_iter
->op
) {
179 fprintf(fds
, " == ");
182 fprintf(fds
, " >= ");
187 case SCMP_CMP_MASKED_EQ
:
188 fprintf(fds
, " & 0x%.8x == ", c_iter
->mask
);
194 fprintf(fds
, " ??? ");
196 fprintf(fds
, "%u)\n", c_iter
->datum
);
199 if (c_iter
->act_t_flg
) {
200 _indent(fds
, lvl
+ 1);
201 _pfc_action(fds
, c_iter
->act_t
);
202 } else if (c_iter
->nxt_t
!= NULL
)
203 _gen_pfc_chain(arch
, c_iter
->nxt_t
, lvl
+ 1, fds
);
206 if (c_iter
->act_f_flg
) {
208 fprintf(fds
, "else\n");
209 _indent(fds
, lvl
+ 1);
210 _pfc_action(fds
, c_iter
->act_f
);
211 } else if (c_iter
->nxt_f
!= NULL
) {
213 fprintf(fds
, "else\n");
214 _gen_pfc_chain(arch
, c_iter
->nxt_f
, lvl
+ 1, fds
);
217 c_iter
= c_iter
->lvl_nxt
;
222 * Generate pseudo filter code for a syscall
223 * @param arch the architecture definition
224 * @param sys the syscall filter
225 * @param fds the file stream to send the output
227 * This function generates a pseduo filter code representation of the given
228 * syscall filter and writes it to the given output stream.
231 static void _gen_pfc_syscall(const struct arch_def
*arch
,
232 const struct db_sys_list
*sys
, FILE *fds
)
234 unsigned int sys_num
= sys
->num
;
235 const char *sys_name
= arch_syscall_resolve_num(arch
, sys_num
);
238 fprintf(fds
, "# filter for syscall \"%s\" (%d) [priority: %d]\n",
239 (sys_name
? sys_name
: "UNKNOWN"), sys_num
, sys
->priority
);
241 fprintf(fds
, "if ($syscall == %d)\n", sys_num
);
242 if (sys
->chains
== NULL
) {
244 _pfc_action(fds
, sys
->action
);
246 _gen_pfc_chain(arch
, sys
->chains
, 2, fds
);
250 * Generate pseudo filter code for an architecture
251 * @param col the seccomp filter collection
252 * @param db the single seccomp filter
253 * @param fds the file stream to send the output
255 * This function generates a pseudo filter code representation of the given
256 * filter DB and writes it to the given output stream. Returns zero on
257 * success, negative values on failure.
260 static int _gen_pfc_arch(const struct db_filter_col
*col
,
261 const struct db_filter
*db
, FILE *fds
)
264 struct db_sys_list
*s_iter
;
265 struct pfc_sys_list
*p_iter
= NULL
, *p_new
, *p_head
= NULL
, *p_prev
;
267 /* sort the syscall list */
268 db_list_foreach(s_iter
, db
->syscalls
) {
269 p_new
= malloc(sizeof(*p_new
));
274 memset(p_new
, 0, sizeof(*p_new
));
279 while (p_iter
!= NULL
&&
280 s_iter
->priority
< p_iter
->sys
->priority
) {
282 p_iter
= p_iter
->next
;
286 else if (p_prev
== NULL
) {
287 p_new
->next
= p_head
;
290 p_new
->next
= p_iter
;
291 p_prev
->next
= p_new
;
295 fprintf(fds
, "# filter for arch %s (%u)\n",
296 _pfc_arch(db
->arch
), db
->arch
->token_bpf
);
297 fprintf(fds
, "if ($arch == %u)\n", db
->arch
->token_bpf
);
299 while (p_iter
!= NULL
) {
300 if (!p_iter
->sys
->valid
)
302 _gen_pfc_syscall(db
->arch
, p_iter
->sys
, fds
);
303 p_iter
= p_iter
->next
;
306 fprintf(fds
, "# default action\n");
308 _pfc_action(fds
, col
->attr
.act_default
);
311 while (p_head
!= NULL
) {
313 p_head
= p_head
->next
;
320 * Generate a pseudo filter code string representation
321 * @param col the seccomp filter collection
322 * @param fd the fd to send the output
324 * This function generates a pseudo filter code representation of the given
325 * filter collection and writes it to the given fd. Returns zero on success,
326 * negative values on failure.
329 int gen_pfc_generate(const struct db_filter_col
*col
, int fd
)
339 fds
= fdopen(newfd
, "a");
345 /* generate the pfc */
347 fprintf(fds
, "# pseudo filter code start\n");
350 for (iter
= 0; iter
< col
->filter_cnt
; iter
++)
351 _gen_pfc_arch(col
, col
->filters
[iter
], fds
);
353 fprintf(fds
, "# invalid architecture action\n");
354 _pfc_action(fds
, col
->attr
.act_badarch
);
356 fprintf(fds
, "# pseudo filter code end\n");
This page took 0.032806 seconds and 4 git commands to generate.