]>
Commit | Line | Data |
---|---|---|
62c6598e PM |
1 | # |
2 | # Seccomp Library Python Bindings | |
3 | # | |
6220c8c0 | 4 | # Copyright (c) 2012,2013 Red Hat <pmoore@redhat.com> |
62c6598e PM |
5 | # Author: Paul Moore <pmoore@redhat.com> |
6 | # | |
7 | ||
8 | # | |
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. | |
12 | # | |
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 | |
16 | # for more details. | |
17 | # | |
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>. | |
20 | # | |
21 | ||
22 | """ Python bindings for the libseccomp library | |
23 | ||
24 | The libseccomp library provides and easy to use, platform independent, | |
25 | interface to the Linux Kernel's syscall filtering mechanism: seccomp. The | |
26 | libseccomp API is designed to abstract away the underlying BPF based | |
27 | syscall filter language and present a more conventional function-call | |
28 | based filtering interface that should be familiar to, and easily adopted | |
29 | by application developers. | |
30 | ||
31 | Filter action values: | |
32 | KILL - kill the process | |
33 | ALLOW - allow the syscall to execute | |
34 | TRAP - a SIGSYS signal will be thrown | |
35 | ERRNO(x) - syscall will return (x) | |
36 | TRACE(x) - if the process is being traced, (x) will be returned to the | |
37 | tracing process via PTRACE_EVENT_SECCOMP and the | |
38 | PTRACE_GETEVENTMSG option | |
39 | ||
40 | Argument comparison values: | |
41 | ||
42 | NE - argument not equal the value | |
43 | LT - argument less than the value | |
44 | LE - argument less than, or equal to, the value | |
45 | EQ - argument equal the value | |
46 | GT - argument greater than the value | |
47 | GE - argument greater than, or equal to, the value | |
48 | MASKED_EQ - masked argument is equal to the value | |
49 | ||
50 | ||
51 | Example: | |
52 | ||
53 | import sys | |
54 | from seccomp import * | |
55 | ||
56 | # create a filter object with a default KILL action | |
57 | f = SyscallFilter(defaction=KILL) | |
58 | ||
59 | # add syscall filter rules to allow certain syscalls | |
60 | f.add_rule(ALLOW, "open") | |
61 | f.add_rule(ALLOW, "close") | |
62 | f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin)) | |
63 | f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout)) | |
64 | f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stderr)) | |
65 | f.add_rule(ALLOW, "rt_sigreturn") | |
66 | ||
67 | # load the filter into the kernel | |
68 | f.load() | |
69 | """ | |
70 | __author__ = 'Paul Moore <paul@paul-moore.com>' | |
6220c8c0 | 71 | __date__ = "7 January 2013" |
62c6598e PM |
72 | |
73 | from libc.stdint cimport uint32_t | |
74 | import errno | |
75 | ||
76 | cimport libseccomp | |
77 | ||
78 | KILL = libseccomp.SCMP_ACT_KILL | |
79 | TRAP = libseccomp.SCMP_ACT_TRAP | |
80 | ALLOW = libseccomp.SCMP_ACT_ALLOW | |
81 | def ERRNO(int errno): | |
82 | return libseccomp.SCMP_ACT_ERRNO(errno) | |
83 | def TRACE(int value): | |
84 | return libseccomp.SCMP_ACT_TRACE(value) | |
85 | ||
86 | NE = libseccomp.SCMP_CMP_NE | |
87 | LT = libseccomp.SCMP_CMP_LT | |
88 | LE = libseccomp.SCMP_CMP_LE | |
89 | EQ = libseccomp.SCMP_CMP_EQ | |
90 | GE = libseccomp.SCMP_CMP_GE | |
91 | GT = libseccomp.SCMP_CMP_GT | |
92 | MASKED_EQ = libseccomp.SCMP_CMP_MASKED_EQ | |
93 | ||
aeac2736 PM |
94 | def system_arch(): |
95 | """ Return the system architecture value. | |
96 | ||
97 | Description: | |
98 | Returns the native system architecture value. | |
99 | """ | |
100 | return libseccomp.seccomp_arch_native() | |
101 | ||
6220c8c0 PM |
102 | def resolve_syscall(arch, syscall): |
103 | """ Resolve the syscall. | |
104 | ||
105 | Arguments: | |
106 | arch - the architecture value, e.g. Arch.* | |
107 | syscall - the syscall name or number | |
108 | ||
109 | Description: | |
110 | Resolve an architecture's syscall name to the correct number or the | |
111 | syscall number to the correct name. | |
112 | """ | |
113 | if (isinstance(syscall, basestring)): | |
114 | return libseccomp.seccomp_syscall_resolve_name_arch(arch, syscall) | |
115 | elif (isinstance(syscall, int)): | |
116 | return libseccomp.seccomp_syscall_resolve_num_arch(arch, syscall) | |
117 | else: | |
118 | raise TypeError("Syscall must either be an int or str type") | |
119 | ||
62c6598e PM |
120 | cdef class Arch: |
121 | """ Python object representing the SyscallFilter architecture values. | |
122 | ||
123 | Data values: | |
124 | NATIVE - the native architecture | |
125 | X86 - 32-bit x86 | |
126 | X86_64 - 64-bit x86 | |
e9b5a6eb | 127 | X32 - 64-bit x86 using the x32 ABI |
62c6598e | 128 | """ |
aeac2736 | 129 | |
62c6598e PM |
130 | NATIVE = libseccomp.SCMP_ARCH_NATIVE |
131 | X86 = libseccomp.SCMP_ARCH_X86 | |
132 | X86_64 = libseccomp.SCMP_ARCH_X86_64 | |
e9b5a6eb | 133 | X32 = libseccomp.SCMP_ARCH_X32 |
62c6598e PM |
134 | |
135 | cdef class Attr: | |
136 | """ Python object representing the SyscallFilter attributes. | |
137 | ||
138 | Data values: | |
139 | ACT_DEFAULT - the filter's default action | |
140 | ACT_BADARCH - the filter's bad architecture action | |
141 | CTL_NNP - the filter's "no new privileges" flag | |
142 | """ | |
143 | ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT | |
144 | ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH | |
145 | CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP | |
146 | ||
147 | cdef class Arg: | |
148 | """ Python object representing a SyscallFilter syscall argument. | |
149 | """ | |
150 | cdef libseccomp.scmp_arg_cmp _arg | |
151 | ||
152 | def __cinit__(self, arg, op, datum_a, datum_b = 0): | |
153 | """ Initialize the argument comparison. | |
154 | ||
155 | Arguments: | |
156 | arg - the arguement number, starting at 0 | |
157 | op - the argument comparison operator, e.g. {NE,LT,LE,...} | |
158 | datum_a - argument value | |
159 | datum_b - argument value, only valid when op == MASKED_EQ | |
160 | ||
161 | Description: | |
162 | Create an argument comparison object for use with SyscallFilter. | |
163 | """ | |
164 | self._arg.arg = arg | |
165 | self._arg.op = op | |
166 | if isinstance(datum_a, file): | |
167 | self._arg.datum_a = datum_a.fileno() | |
168 | else: | |
169 | self._arg.datum_a = datum_a | |
170 | if isinstance(datum_b, file): | |
171 | self._arg.datum_b = datum_b.fileno() | |
172 | else: | |
173 | self._arg.datum_b = datum_b | |
174 | ||
175 | def to_c(self): | |
176 | """ Convert the object into a C structure. | |
177 | ||
178 | Description: | |
179 | Helper function which should only be used internally by | |
180 | SyscallFilter objects and exists for the sole purpose of making it | |
181 | easier to deal with the varadic functions of the libseccomp API, | |
182 | e.g. seccomp_rule_add(). | |
183 | """ | |
184 | return self._arg | |
185 | ||
186 | cdef class SyscallFilter: | |
187 | """ Python object representing a seccomp syscall filter. """ | |
188 | cdef int _defaction | |
189 | cdef libseccomp.scmp_filter_ctx _ctx | |
190 | ||
191 | def __cinit__(self, int defaction): | |
192 | """ Initialize the filter state | |
193 | ||
194 | Arguments: | |
195 | defaction - the default filter action | |
196 | ||
197 | Description: | |
198 | Initializes the seccomp filter state to the defaults. | |
199 | """ | |
200 | self._ctx = libseccomp.seccomp_init(defaction) | |
201 | if self._ctx == NULL: | |
202 | raise RuntimeError("Library error") | |
203 | _defaction = defaction | |
204 | ||
205 | def __dealloc__(self): | |
206 | """ Destroys the filter state and releases any resources. | |
207 | ||
208 | Description: | |
209 | Destroys the seccomp filter state and releases any resources | |
210 | associated with the filter state. This function does not affect | |
211 | any seccomp filters already loaded into the kernel. | |
212 | """ | |
213 | if self._ctx != NULL: | |
214 | libseccomp.seccomp_release(self._ctx) | |
215 | ||
216 | def reset(self, int defaction = -1): | |
217 | """ Reset the filter state. | |
218 | ||
219 | Arguments: | |
220 | defaction - the default filter action | |
221 | ||
222 | Description: | |
223 | Resets the seccomp filter state to an initial default state, if a | |
224 | default filter action is not specified in the reset call the | |
225 | original action will be reused. This function does not affect any | |
226 | seccomp filters alread loaded into the kernel. | |
227 | """ | |
228 | if defaction == -1: | |
229 | defaction = self._defaction | |
230 | rc = libseccomp.seccomp_reset(self._ctx, defaction) | |
231 | if rc == -errno.EINVAL: | |
232 | raise ValueError("Invalid action") | |
233 | if rc != 0: | |
234 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
235 | _defaction = defaction | |
236 | ||
237 | def merge(self, SyscallFilter filter): | |
238 | """ Merge two existing SyscallFilter objects. | |
239 | ||
240 | Arguments: | |
241 | filter - a valid SyscallFilter object | |
242 | ||
243 | Description: | |
244 | Merges a valid SyscallFilter object with the current SyscallFilter | |
245 | object; the passed filter object will be reset on success. In | |
246 | order to successfully merge two seccomp filters they must have the | |
247 | same attribute values and not share any of the same architectures. | |
248 | """ | |
249 | rc = libseccomp.seccomp_merge(self._ctx, filter._ctx) | |
250 | if rc != 0: | |
251 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
252 | filter._ctx = NULL | |
253 | filter = SyscallFilter(filter._defaction) | |
254 | ||
255 | def exist_arch(self, arch): | |
256 | """ Check if the seccomp filter contains a given architecture. | |
257 | ||
258 | Arguments: | |
259 | arch - the architecture value, e.g. Arch.* | |
260 | ||
261 | Description: | |
262 | Test to see if a given architecture is included in the filter. | |
263 | Return True is the architecture exists, False if it does not | |
264 | exist. | |
265 | """ | |
266 | rc = libseccomp.seccomp_arch_exist(self._ctx, arch) | |
267 | if rc == 0: | |
268 | return True | |
269 | elif rc == -errno.EEXIST: | |
270 | return False | |
271 | elif rc == -errno.EINVAL: | |
272 | raise ValueError("Invalid architecture") | |
273 | else: | |
274 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
275 | ||
276 | def add_arch(self, arch): | |
277 | """ Add an architecture to the filter. | |
278 | ||
279 | Arguments: | |
280 | arch - the architecture value, e.g. Arch.* | |
281 | ||
282 | Description: | |
283 | Add the given architecture to the filter. Any new rules added | |
284 | after this method returns successfully will be added to this new | |
285 | architecture, but any existing rules will not be added to the new | |
286 | architecture. | |
287 | """ | |
288 | rc = libseccomp.seccomp_arch_add(self._ctx, arch) | |
289 | if rc == -errno.EINVAL: | |
290 | raise ValueError("Invalid architecture") | |
291 | elif rc != 0: | |
292 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
293 | ||
294 | def remove_arch(self, arch): | |
295 | """ Remove an architecture from the filter. | |
296 | ||
297 | Arguments: | |
298 | arch - the architecture value, e.g. Arch.* | |
299 | ||
300 | Description: | |
301 | Remove the given architecture from the filter. The filter must | |
302 | always contain at least one architecture, so if only one | |
303 | architecture exists in the filter this method will fail. | |
304 | """ | |
305 | rc = libseccomp.seccomp_arch_remove(self._ctx, arch) | |
306 | if rc == -errno.EINVAL: | |
307 | raise ValueError("Invalid architecture") | |
308 | elif rc != 0: | |
309 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
310 | ||
311 | def load(self): | |
312 | """ Load the filter into the Linux Kernel. | |
313 | ||
314 | Description: | |
315 | Load the current filter into the Linux Kernel. As soon as the | |
316 | method returns the filter will be active and enforcing. | |
317 | """ | |
318 | rc = libseccomp.seccomp_load(self._ctx) | |
319 | if rc != 0: | |
320 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
321 | ||
322 | def get_attr(self, attr): | |
323 | """ Get an attribute value from the filter. | |
324 | ||
325 | Arguments: | |
326 | attr - the attribute, e.g. Attr.* | |
327 | ||
328 | Description: | |
329 | Lookup the given attribute in the filter and return the | |
330 | attribute's value to the caller. | |
331 | """ | |
332 | value = 0 | |
333 | rc = libseccomp.seccomp_attr_get(self._ctx, | |
334 | attr, <uint32_t *>&value) | |
335 | if rc == -errno.EINVAL: | |
336 | raise ValueError("Invalid attribute") | |
337 | elif rc != 0: | |
338 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
339 | return value | |
340 | ||
341 | def set_attr(self, attr, int value): | |
342 | """ Set a filter attribute. | |
343 | ||
344 | Arguments: | |
345 | attr - the attribute, e.g. Attr.* | |
346 | value - the attribute value | |
347 | ||
348 | Description: | |
349 | Lookup the given attribute in the filter and assign it the given | |
350 | value. | |
351 | """ | |
352 | rc = libseccomp.seccomp_attr_set(self._ctx, attr, value) | |
353 | if rc == -errno.EINVAL: | |
354 | raise ValueError("Invalid attribute") | |
355 | elif rc != 0: | |
356 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
357 | ||
358 | def syscall_priority(self, syscall, int priority): | |
359 | """ Set the filter priority of a syscall. | |
360 | ||
361 | Arguments: | |
362 | syscall - the syscall name or number | |
363 | priority - the priority of the syscall | |
364 | ||
365 | Description: | |
366 | Set the filter priority of the given syscall. A syscall with a | |
367 | higher priority will have less overhead in the generated filter | |
368 | code which is loaded into the system. Priority values can range | |
369 | from 0 to 255 inclusive. | |
370 | """ | |
371 | if priority < 0 or priority > 255: | |
6220c8c0 | 372 | raise ValueError("Syscall priority must be between 0 and 255") |
62c6598e PM |
373 | if isinstance(syscall, str): |
374 | syscall_str = syscall.encode() | |
375 | syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str) | |
376 | elif isinstance(syscall, int): | |
377 | syscall_num = syscall | |
378 | else: | |
6220c8c0 | 379 | raise TypeError("Syscall must either be an int or str type") |
62c6598e PM |
380 | rc = libseccomp.seccomp_syscall_priority(self._ctx, |
381 | syscall_num, priority) | |
382 | if rc != 0: | |
383 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
384 | ||
385 | def add_rule(self, int action, syscall, *args): | |
386 | """ Add a new rule to filter. | |
387 | ||
388 | Arguments: | |
389 | action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW | |
390 | syscall - the syscall name or number | |
391 | args - variable number of Arg objects | |
392 | ||
393 | Description: | |
394 | Add a new rule to the filter, matching on the given syscall and an | |
395 | optional list of argument comparisons. If the rule is triggered | |
396 | the given action will be taken by the kernel. In order for the | |
397 | rule to trigger, the syscall as well as each argument comparison | |
398 | must be true. | |
399 | ||
400 | In the case where the specific rule is not valid on a specific | |
401 | architecture, e.g. socket() on 32-bit x86, this method rewrites | |
402 | the rule to the best possible match. If you don't want this fule | |
403 | rewriting to take place use add_rule_exactly(). | |
404 | """ | |
405 | cdef libseccomp.scmp_arg_cmp c_arg[6] | |
406 | if isinstance(syscall, str): | |
407 | syscall_str = syscall.encode() | |
408 | syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str) | |
409 | elif isinstance(syscall, int): | |
410 | syscall_num = syscall | |
411 | else: | |
6220c8c0 | 412 | raise TypeError("Syscall must either be an int or str type") |
62c6598e PM |
413 | """ NOTE: the code below exists solely to deal with the varadic |
414 | nature of seccomp_rule_add() function and the inability of Cython | |
415 | to handle this automatically """ | |
416 | for i, arg in enumerate(args): | |
417 | c_arg[i] = arg.to_c() | |
418 | if len(args) == 0: | |
419 | rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, 0) | |
420 | elif len(args) == 1: | |
421 | rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, | |
422 | len(args), | |
423 | c_arg[0]) | |
424 | elif len(args) == 2: | |
425 | rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, | |
426 | len(args), | |
427 | c_arg[0], | |
428 | c_arg[1]) | |
429 | elif len(args) == 3: | |
430 | rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, | |
431 | len(args), | |
432 | c_arg[0], | |
433 | c_arg[1], | |
434 | c_arg[2]) | |
435 | elif len(args) == 4: | |
436 | rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, | |
437 | len(args), | |
438 | c_arg[0], | |
439 | c_arg[1], | |
440 | c_arg[2], | |
441 | c_arg[3]) | |
442 | elif len(args) == 5: | |
443 | rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, | |
444 | len(args), | |
445 | c_arg[0], | |
446 | c_arg[1], | |
447 | c_arg[2], | |
448 | c_arg[3], | |
449 | c_arg[4]) | |
450 | elif len(args) == 6: | |
451 | rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, | |
452 | len(args), | |
453 | c_arg[0], | |
454 | c_arg[1], | |
455 | c_arg[2], | |
456 | c_arg[3], | |
457 | c_arg[4], | |
458 | c_arg[5]) | |
459 | else: | |
460 | raise RuntimeError("Maximum number of arguments exceeded") | |
461 | if rc != 0: | |
462 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
463 | ||
464 | def add_rule_exactly(self, int action, syscall, *args): | |
465 | """ Add a new rule to filter. | |
466 | ||
467 | Arguments: | |
468 | action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW | |
469 | syscall - the syscall name or number | |
470 | args - variable number of Arg objects | |
471 | ||
472 | Description: | |
473 | Add a new rule to the filter, matching on the given syscall and an | |
474 | optional list of argument comparisons. If the rule is triggered | |
475 | the given action will be taken by the kernel. In order for the | |
476 | rule to trigger, the syscall as well as each argument comparison | |
477 | must be true. | |
478 | ||
479 | This method attempts to add the filter rule exactly as specified | |
480 | which can cause problems on certain architectures, e.g. socket() | |
481 | on 32-bit x86. For a architecture independent version of this | |
482 | method use add_rule(). | |
483 | """ | |
484 | cdef libseccomp.scmp_arg_cmp c_arg[6] | |
485 | if isinstance(syscall, str): | |
486 | syscall_str = syscall.encode() | |
487 | syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str) | |
488 | elif isinstance(syscall, int): | |
489 | syscall_num = syscall | |
490 | else: | |
6220c8c0 | 491 | raise TypeError("Syscall must either be an int or str type") |
62c6598e PM |
492 | """ NOTE: the code below exists solely to deal with the varadic |
493 | nature of seccomp_rule_add_exact() function and the inability of | |
494 | Cython to handle this automatically """ | |
495 | for i, arg in enumerate(args): | |
496 | c_arg[i] = arg.to_c() | |
497 | if len(args) == 0: | |
498 | rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, | |
499 | syscall_num, 0) | |
500 | elif len(args) == 1: | |
501 | rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, | |
502 | syscall_num, len(args), | |
503 | c_arg[0]) | |
504 | elif len(args) == 2: | |
505 | rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, | |
506 | syscall_num, len(args), | |
507 | c_arg[0], | |
508 | c_arg[1]) | |
509 | elif len(args) == 3: | |
510 | rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, | |
511 | syscall_num, len(args), | |
512 | c_arg[0], | |
513 | c_arg[1], | |
514 | c_arg[2]) | |
515 | elif len(args) == 4: | |
516 | rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, | |
517 | syscall_num, len(args), | |
518 | c_arg[0], | |
519 | c_arg[1], | |
520 | c_arg[2], | |
521 | c_arg[3]) | |
522 | elif len(args) == 5: | |
523 | rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, | |
524 | syscall_num, len(args), | |
525 | c_arg[0], | |
526 | c_arg[1], | |
527 | c_arg[2], | |
528 | c_arg[3], | |
529 | c_arg[4]) | |
530 | elif len(args) == 6: | |
531 | rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, | |
532 | syscall_num, len(args), | |
533 | c_arg[0], | |
534 | c_arg[1], | |
535 | c_arg[2], | |
536 | c_arg[3], | |
537 | c_arg[4], | |
538 | c_arg[5]) | |
539 | else: | |
540 | raise RuntimeError("Maximum number of arguments exceeded") | |
541 | if rc != 0: | |
542 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
543 | ||
544 | def export_pfc(self, file): | |
545 | """ Export the filter in PFC format. | |
546 | ||
547 | Arguments: | |
548 | file - the output file | |
549 | ||
550 | Description: | |
551 | Output the filter in Pseudo Filter Code (PFC) to the given file. | |
552 | The output is functionally equivalent to the BPF based filter | |
553 | which is loaded into the Linux Kernel. | |
554 | """ | |
555 | rc = libseccomp.seccomp_export_pfc(self._ctx, file.fileno()) | |
556 | if rc != 0: | |
557 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
558 | ||
559 | def export_bpf(self, file): | |
560 | """ Export the filter in BPF format. | |
561 | ||
562 | Arguments: | |
563 | file - the output file | |
564 | ||
565 | Output the filter in Berkley Packet Filter (BPF) to the given | |
566 | file. The output is identical to what is loaded into the | |
567 | Linux Kernel. | |
568 | """ | |
569 | rc = libseccomp.seccomp_export_bpf(self._ctx, file.fileno()) | |
570 | if rc != 0: | |
571 | raise RuntimeError(str.format("Library error (errno = {0})", rc)) | |
572 | ||
573 | # kate: syntax python; | |
574 | # kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; |