2 # Seccomp Library Python Bindings
4 # Copyright (c) 2012,2013 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>.
22 """ Python bindings for the libseccomp library
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.
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
40 Argument comparison values (see the Arg class):
48 MASKED_EQ - (arg & datum_b) == datum_a
56 # create a filter object with a default KILL action
57 f = SyscallFilter(defaction=KILL)
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")
67 # load the filter into the kernel
70 __author__ = 'Paul Moore <paul@paul-moore.com>'
71 __date__ = "7 January 2013"
73 from libc.stdint cimport uint32_t
78 KILL = libseccomp.SCMP_ACT_KILL
79 TRAP = libseccomp.SCMP_ACT_TRAP
80 ALLOW = libseccomp.SCMP_ACT_ALLOW
82 """The action ERRNO(x) means that the syscall will return (x).
83 To conform to Linux syscall calling conventions, the syscall return
84 value should almost always be a negative number.
86 return libseccomp.SCMP_ACT_ERRNO(errno)
88 """The action TRACE(x) means that, if the process is being traced, (x)
89 will be returned to the tracing process via PTRACE_EVENT_SECCOMP
90 and the PTRACE_GETEVENTMSG option.
92 return libseccomp.SCMP_ACT_TRACE(value)
94 NE = libseccomp.SCMP_CMP_NE
95 LT = libseccomp.SCMP_CMP_LT
96 LE = libseccomp.SCMP_CMP_LE
97 EQ = libseccomp.SCMP_CMP_EQ
98 GE = libseccomp.SCMP_CMP_GE
99 GT = libseccomp.SCMP_CMP_GT
100 MASKED_EQ = libseccomp.SCMP_CMP_MASKED_EQ
103 """ Return the system architecture value.
106 Returns the native system architecture value.
108 return libseccomp.seccomp_arch_native()
110 def resolve_syscall(arch, syscall):
111 """ Resolve the syscall.
114 arch - the architecture value, e.g. Arch.*
115 syscall - the syscall name or number
118 Resolve an architecture's syscall name to the correct number or the
119 syscall number to the correct name.
123 if isinstance(syscall, basestring):
124 return libseccomp.seccomp_syscall_resolve_name_rewrite(arch, syscall)
125 elif isinstance(syscall, int):
126 ret_str = libseccomp.seccomp_syscall_resolve_num_arch(arch, syscall)
128 raise ValueError('Unknown syscall %d on arch %d' % (syscall, arch))
132 raise TypeError("Syscall must either be an int or str type")
135 """ Python object representing the SyscallFilter architecture values.
138 NATIVE - the native architecture
141 X32 - 64-bit x86 using the x32 ABI
145 MIPS64 - MIPS 64-bit ABI
146 MIPS64N32 - MIPS N32 ABI
147 MIPSEL - MIPS little endian O32 ABI
148 MIPSEL64 - MIPS little endian 64-bit ABI
149 MIPSEL64N32 - MIPS little endian N32 ABI
150 PPC64 - 64-bit PowerPC
156 NATIVE = libseccomp.SCMP_ARCH_NATIVE
157 X86 = libseccomp.SCMP_ARCH_X86
158 X86_64 = libseccomp.SCMP_ARCH_X86_64
159 X32 = libseccomp.SCMP_ARCH_X32
160 ARM = libseccomp.SCMP_ARCH_ARM
161 AARCH64 = libseccomp.SCMP_ARCH_AARCH64
162 MIPS = libseccomp.SCMP_ARCH_MIPS
163 MIPS64 = libseccomp.SCMP_ARCH_MIPS64
164 MIPS64N32 = libseccomp.SCMP_ARCH_MIPS64N32
165 MIPSEL = libseccomp.SCMP_ARCH_MIPSEL
166 MIPSEL64 = libseccomp.SCMP_ARCH_MIPSEL64
167 MIPSEL64N32 = libseccomp.SCMP_ARCH_MIPSEL64N32
168 PPC = libseccomp.SCMP_ARCH_PPC
169 PPC64 = libseccomp.SCMP_ARCH_PPC64
170 PPC64LE = libseccomp.SCMP_ARCH_PPC64LE
171 S390 = libseccomp.SCMP_ARCH_S390
172 S390X = libseccomp.SCMP_ARCH_S390X
174 def __cinit__(self, arch=libseccomp.SCMP_ARCH_NATIVE):
175 """ Initialize the architecture object.
178 arch - the architecture name or token value
181 Create an architecture object using the given name or token value.
183 if isinstance(arch, int):
184 if arch == libseccomp.SCMP_ARCH_NATIVE:
185 self._token = libseccomp.seccomp_arch_native()
186 elif arch == libseccomp.SCMP_ARCH_X86:
187 self._token = libseccomp.SCMP_ARCH_X86
188 elif arch == libseccomp.SCMP_ARCH_X86_64:
189 self._token = libseccomp.SCMP_ARCH_X86_64
190 elif arch == libseccomp.SCMP_ARCH_X32:
191 self._token = libseccomp.SCMP_ARCH_X32
192 elif arch == libseccomp.SCMP_ARCH_ARM:
193 self._token = libseccomp.SCMP_ARCH_ARM
194 elif arch == libseccomp.SCMP_ARCH_AARCH64:
195 self._token = libseccomp.SCMP_ARCH_AARCH64
196 elif arch == libseccomp.SCMP_ARCH_MIPS:
197 self._token = libseccomp.SCMP_ARCH_MIPS
198 elif arch == libseccomp.SCMP_ARCH_MIPS64:
199 self._token = libseccomp.SCMP_ARCH_MIPS64
200 elif arch == libseccomp.SCMP_ARCH_MIPS64N32:
201 self._token = libseccomp.SCMP_ARCH_MIPS64N32
202 elif arch == libseccomp.SCMP_ARCH_MIPSEL:
203 self._token = libseccomp.SCMP_ARCH_MIPSEL
204 elif arch == libseccomp.SCMP_ARCH_MIPSEL64:
205 self._token = libseccomp.SCMP_ARCH_MIPSEL64
206 elif arch == libseccomp.SCMP_ARCH_MIPSEL64N32:
207 self._token = libseccomp.SCMP_ARCH_MIPSEL64N32
208 elif arch == libseccomp.SCMP_ARCH_PPC:
209 self._token = libseccomp.SCMP_ARCH_PPC
210 elif arch == libseccomp.SCMP_ARCH_PPC64:
211 self._token = libseccomp.SCMP_ARCH_PPC64
212 elif arch == libseccomp.SCMP_ARCH_PPC64LE:
213 self._token = libseccomp.SCMP_ARCH_PPC64LE
214 elif arch == libseccomp.SCMP_ARCH_S390:
215 self._token = libseccomp.SCMP_ARCH_S390
216 elif arch == libseccomp.SCMP_ARCH_S390X:
217 self._token = libseccomp.SCMP_ARCH_S390X
220 elif isinstance(arch, basestring):
221 self._token = libseccomp.seccomp_arch_resolve_name(arch)
223 raise TypeError("Architecture must be an int or str type")
225 raise ValueError("Invalid architecture")
228 """ Convert the architecture object to a token value.
231 Convert the architecture object to an integer representing the
232 architecture's token value.
237 """ Python object representing the SyscallFilter attributes.
240 ACT_DEFAULT - the filter's default action
241 ACT_BADARCH - the filter's bad architecture action
242 CTL_NNP - the filter's "no new privileges" flag
243 CTL_NNP - the filter's thread sync flag
245 ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT
246 ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH
247 CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP
248 CTL_TSYNC = libseccomp.SCMP_FLTATR_CTL_TSYNC
251 """ Python object representing a SyscallFilter syscall argument.
253 cdef libseccomp.scmp_arg_cmp _arg
255 def __cinit__(self, arg, op, datum_a, datum_b = 0):
256 """ Initialize the argument comparison.
259 arg - the argument number, starting at 0
260 op - the argument comparison operator, e.g. {NE,LT,LE,...}
261 datum_a - argument value
262 datum_b - argument value, only valid when op == MASKED_EQ
265 Create an argument comparison object for use with SyscallFilter.
269 self._arg.datum_a = datum_a
270 self._arg.datum_b = datum_b
272 cdef libseccomp.scmp_arg_cmp to_c(self):
273 """ Convert the object into a C structure.
276 Helper function which should only be used internally by
277 SyscallFilter objects and exists for the sole purpose of making it
278 easier to deal with the varadic functions of the libseccomp API,
279 e.g. seccomp_rule_add().
283 cdef class SyscallFilter:
284 """ Python object representing a seccomp syscall filter. """
286 cdef libseccomp.scmp_filter_ctx _ctx
288 def __cinit__(self, int defaction):
289 self._ctx = libseccomp.seccomp_init(defaction)
290 if self._ctx == NULL:
291 raise RuntimeError("Library error")
292 _defaction = defaction
294 def __init__(self, defaction):
295 """ Initialize the filter state
298 defaction - the default filter action
301 Initializes the seccomp filter state to the defaults.
304 def __dealloc__(self):
305 """ Destroys the filter state and releases any resources.
308 Destroys the seccomp filter state and releases any resources
309 associated with the filter state. This function does not affect
310 any seccomp filters already loaded into the kernel.
312 if self._ctx != NULL:
313 libseccomp.seccomp_release(self._ctx)
315 def reset(self, int defaction = -1):
316 """ Reset the filter state.
319 defaction - the default filter action
322 Resets the seccomp filter state to an initial default state, if a
323 default filter action is not specified in the reset call the
324 original action will be reused. This function does not affect any
325 seccomp filters alread loaded into the kernel.
328 defaction = self._defaction
329 rc = libseccomp.seccomp_reset(self._ctx, defaction)
330 if rc == -errno.EINVAL:
331 raise ValueError("Invalid action")
333 raise RuntimeError(str.format("Library error (errno = {0})", rc))
334 _defaction = defaction
336 def merge(self, SyscallFilter filter):
337 """ Merge two existing SyscallFilter objects.
340 filter - a valid SyscallFilter object
343 Merges a valid SyscallFilter object with the current SyscallFilter
344 object; the passed filter object will be reset on success. In
345 order to successfully merge two seccomp filters they must have the
346 same attribute values and not share any of the same architectures.
348 rc = libseccomp.seccomp_merge(self._ctx, filter._ctx)
350 raise RuntimeError(str.format("Library error (errno = {0})", rc))
352 filter = SyscallFilter(filter._defaction)
354 def exist_arch(self, arch):
355 """ Check if the seccomp filter contains a given architecture.
358 arch - the architecture value, e.g. Arch.*
361 Test to see if a given architecture is included in the filter.
362 Return True is the architecture exists, False if it does not
365 rc = libseccomp.seccomp_arch_exist(self._ctx, arch)
368 elif rc == -errno.EEXIST:
370 elif rc == -errno.EINVAL:
371 raise ValueError("Invalid architecture")
373 raise RuntimeError(str.format("Library error (errno = {0})", rc))
375 def add_arch(self, arch):
376 """ Add an architecture to the filter.
379 arch - the architecture value, e.g. Arch.*
382 Add the given architecture to the filter. Any new rules added
383 after this method returns successfully will be added to this new
384 architecture, but any existing rules will not be added to the new
387 rc = libseccomp.seccomp_arch_add(self._ctx, arch)
388 if rc == -errno.EINVAL:
389 raise ValueError("Invalid architecture")
391 raise RuntimeError(str.format("Library error (errno = {0})", rc))
393 def remove_arch(self, arch):
394 """ Remove an architecture from the filter.
397 arch - the architecture value, e.g. Arch.*
400 Remove the given architecture from the filter. The filter must
401 always contain at least one architecture, so if only one
402 architecture exists in the filter this method will fail.
404 rc = libseccomp.seccomp_arch_remove(self._ctx, arch)
405 if rc == -errno.EINVAL:
406 raise ValueError("Invalid architecture")
408 raise RuntimeError(str.format("Library error (errno = {0})", rc))
411 """ Load the filter into the Linux Kernel.
414 Load the current filter into the Linux Kernel. As soon as the
415 method returns the filter will be active and enforcing.
417 rc = libseccomp.seccomp_load(self._ctx)
419 raise RuntimeError(str.format("Library error (errno = {0})", rc))
421 def get_attr(self, attr):
422 """ Get an attribute value from the filter.
425 attr - the attribute, e.g. Attr.*
428 Lookup the given attribute in the filter and return the
429 attribute's value to the caller.
431 cdef uint32_t value = 0
432 rc = libseccomp.seccomp_attr_get(self._ctx,
433 attr, <uint32_t *>&value)
434 if rc == -errno.EINVAL:
435 raise ValueError("Invalid attribute")
437 raise RuntimeError(str.format("Library error (errno = {0})", rc))
440 def set_attr(self, attr, int value):
441 """ Set a filter attribute.
444 attr - the attribute, e.g. Attr.*
445 value - the attribute value
448 Lookup the given attribute in the filter and assign it the given
451 rc = libseccomp.seccomp_attr_set(self._ctx, attr, value)
452 if rc == -errno.EINVAL:
453 raise ValueError("Invalid attribute")
455 raise RuntimeError(str.format("Library error (errno = {0})", rc))
457 def syscall_priority(self, syscall, int priority):
458 """ Set the filter priority of a syscall.
461 syscall - the syscall name or number
462 priority - the priority of the syscall
465 Set the filter priority of the given syscall. A syscall with a
466 higher priority will have less overhead in the generated filter
467 code which is loaded into the system. Priority values can range
468 from 0 to 255 inclusive.
470 if priority < 0 or priority > 255:
471 raise ValueError("Syscall priority must be between 0 and 255")
472 if isinstance(syscall, str):
473 syscall_str = syscall.encode()
474 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
475 elif isinstance(syscall, int):
476 syscall_num = syscall
478 raise TypeError("Syscall must either be an int or str type")
479 rc = libseccomp.seccomp_syscall_priority(self._ctx,
480 syscall_num, priority)
482 raise RuntimeError(str.format("Library error (errno = {0})", rc))
484 def add_rule(self, int action, syscall, *args):
485 """ Add a new rule to filter.
488 action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
489 syscall - the syscall name or number
490 args - variable number of Arg objects
493 Add a new rule to the filter, matching on the given syscall and an
494 optional list of argument comparisons. If the rule is triggered
495 the given action will be taken by the kernel. In order for the
496 rule to trigger, the syscall as well as each argument comparison
499 In the case where the specific rule is not valid on a specific
500 architecture, e.g. socket() on 32-bit x86, this method rewrites
501 the rule to the best possible match. If you don't want this fule
502 rewriting to take place use add_rule_exactly().
504 cdef libseccomp.scmp_arg_cmp c_arg[6]
505 if isinstance(syscall, str):
506 syscall_str = syscall.encode()
507 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
508 elif isinstance(syscall, int):
509 syscall_num = syscall
511 raise TypeError("Syscall must either be an int or str type")
512 """ NOTE: the code below exists solely to deal with the varadic
513 nature of seccomp_rule_add() function and the inability of Cython
514 to handle this automatically """
516 raise RuntimeError("Maximum number of arguments exceeded")
518 for i, arg in enumerate(args):
519 c_arg[i] = arg.to_c()
521 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, 0)
523 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
527 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
532 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
538 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
545 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
553 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
562 raise RuntimeError("Maximum number of arguments exceeded")
564 raise RuntimeError(str.format("Library error (errno = {0})", rc))
566 def add_rule_exactly(self, int action, syscall, *args):
567 """ Add a new rule to filter.
570 action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
571 syscall - the syscall name or number
572 args - variable number of Arg objects
575 Add a new rule to the filter, matching on the given syscall and an
576 optional list of argument comparisons. If the rule is triggered
577 the given action will be taken by the kernel. In order for the
578 rule to trigger, the syscall as well as each argument comparison
581 This method attempts to add the filter rule exactly as specified
582 which can cause problems on certain architectures, e.g. socket()
583 on 32-bit x86. For a architecture independent version of this
584 method use add_rule().
586 cdef libseccomp.scmp_arg_cmp c_arg[6]
587 if isinstance(syscall, str):
588 syscall_str = syscall.encode()
589 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
590 elif isinstance(syscall, int):
591 syscall_num = syscall
593 raise TypeError("Syscall must either be an int or str type")
594 """ NOTE: the code below exists solely to deal with the varadic
595 nature of seccomp_rule_add_exact() function and the inability of
596 Cython to handle this automatically """
598 raise RuntimeError("Maximum number of arguments exceeded")
600 for i, arg in enumerate(args):
601 c_arg[i] = arg.to_c()
603 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
606 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
607 syscall_num, len(args),
610 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
611 syscall_num, len(args),
615 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
616 syscall_num, len(args),
621 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
622 syscall_num, len(args),
628 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
629 syscall_num, len(args),
636 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
637 syscall_num, len(args),
645 raise RuntimeError("Maximum number of arguments exceeded")
647 raise RuntimeError(str.format("Library error (errno = {0})", rc))
649 def export_pfc(self, file):
650 """ Export the filter in PFC format.
653 file - the output file
656 Output the filter in Pseudo Filter Code (PFC) to the given file.
657 The output is functionally equivalent to the BPF based filter
658 which is loaded into the Linux Kernel.
660 rc = libseccomp.seccomp_export_pfc(self._ctx, file.fileno())
662 raise RuntimeError(str.format("Library error (errno = {0})", rc))
664 def export_bpf(self, file):
665 """ Export the filter in BPF format.
668 file - the output file
670 Output the filter in Berkley Packet Filter (BPF) to the given
671 file. The output is identical to what is loaded into the
674 rc = libseccomp.seccomp_export_bpf(self._ctx, file.fileno())
676 raise RuntimeError(str.format("Library error (errno = {0})", rc))
678 # kate: syntax python;
679 # kate: indent-mode python; space-indent on; indent-width 4; mixedindent off;