]> git.proxmox.com Git - mirror_libseccomp.git/blame - src/python/seccomp.pyx
python: Expose API level functionality
[mirror_libseccomp.git] / src / python / seccomp.pyx
CommitLineData
62c6598e
PM
1#
2# Seccomp Library Python Bindings
3#
ce5aea6a 4# Copyright (c) 2012,2013,2017 Red Hat <pmoore@redhat.com>
d5fd8b95 5# Author: Paul Moore <paul@paul-moore.com>
62c6598e
PM
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
24The libseccomp library provides and easy to use, platform independent,
25interface to the Linux Kernel's syscall filtering mechanism: seccomp. The
26libseccomp API is designed to abstract away the underlying BPF based
27syscall filter language and present a more conventional function-call
28based filtering interface that should be familiar to, and easily adopted
29by application developers.
30
31Filter 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
70c89434
PM
40Argument comparison values (see the Arg class):
41
42 NE - arg != datum_a
43 LT - arg < datum_a
44 LE - arg <= datum_a
45 EQ - arg == datum_a
46 GT - arg > datum_a
47 GE - arg >= datum_a
8af9ba44 48 MASKED_EQ - (arg & datum_b) == datum_a
62c6598e
PM
49
50
51Example:
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>'
ce5aea6a 71__date__ = "3 February 2017"
62c6598e 72
ce5aea6a 73from cpython.version cimport PY_MAJOR_VERSION
62c6598e
PM
74from libc.stdint cimport uint32_t
75import errno
76
77cimport libseccomp
78
ce5aea6a
PM
79def c_str(string):
80 """ Convert a Python string to a C string.
81
82 Arguments:
83 string - the Python string
84
85 Description:
86 Convert the Python string into a form usable by C taking into consideration
87 the Python major version, e.g. Python 2.x or Python 3.x.
88 See http://docs.cython.org/en/latest/src/tutorial/strings.html for more
89 information.
90 """
91 if PY_MAJOR_VERSION < 3:
92 return string
93 else:
94 return bytes(string, "ascii")
95
62c6598e
PM
96KILL = libseccomp.SCMP_ACT_KILL
97TRAP = libseccomp.SCMP_ACT_TRAP
98ALLOW = libseccomp.SCMP_ACT_ALLOW
99def ERRNO(int errno):
28a57d88
AL
100 """The action ERRNO(x) means that the syscall will return (x).
101 To conform to Linux syscall calling conventions, the syscall return
102 value should almost always be a negative number.
103 """
62c6598e
PM
104 return libseccomp.SCMP_ACT_ERRNO(errno)
105def TRACE(int value):
28a57d88
AL
106 """The action TRACE(x) means that, if the process is being traced, (x)
107 will be returned to the tracing process via PTRACE_EVENT_SECCOMP
108 and the PTRACE_GETEVENTMSG option.
109 """
62c6598e
PM
110 return libseccomp.SCMP_ACT_TRACE(value)
111
112NE = libseccomp.SCMP_CMP_NE
113LT = libseccomp.SCMP_CMP_LT
114LE = libseccomp.SCMP_CMP_LE
115EQ = libseccomp.SCMP_CMP_EQ
116GE = libseccomp.SCMP_CMP_GE
117GT = libseccomp.SCMP_CMP_GT
118MASKED_EQ = libseccomp.SCMP_CMP_MASKED_EQ
119
aeac2736
PM
120def system_arch():
121 """ Return the system architecture value.
122
123 Description:
124 Returns the native system architecture value.
125 """
126 return libseccomp.seccomp_arch_native()
127
6220c8c0
PM
128def resolve_syscall(arch, syscall):
129 """ Resolve the syscall.
130
131 Arguments:
132 arch - the architecture value, e.g. Arch.*
133 syscall - the syscall name or number
134
135 Description:
136 Resolve an architecture's syscall name to the correct number or the
137 syscall number to the correct name.
138 """
f7c11d67
AL
139 cdef char *ret_str
140
f05fc7cb 141 if isinstance(syscall, basestring):
ce5aea6a
PM
142 return libseccomp.seccomp_syscall_resolve_name_rewrite(arch,
143 c_str(syscall))
f05fc7cb 144 elif isinstance(syscall, int):
f7c11d67
AL
145 ret_str = libseccomp.seccomp_syscall_resolve_num_arch(arch, syscall)
146 if ret_str is NULL:
147 raise ValueError('Unknown syscall %d on arch %d' % (syscall, arch))
148 else:
149 return ret_str
6220c8c0
PM
150 else:
151 raise TypeError("Syscall must either be an int or str type")
152
4f16fe20
TH
153def get_api():
154 """ Query the level of API support
155
156 Description:
157 Returns the API level value indicating the current supported
158 functionality.
159 """
160 level = libseccomp.seccomp_api_get()
161 if level < 0:
162 raise RuntimeError(str.format("Library error (errno = {0})", level))
163
164 return level
165
166def set_api(unsigned int level):
167 """ Set the level of API support
168
169 Arguments:
170 level - the API level
171
172 Description:
173 This function forcibly sets the API level at runtime. General use
174 of this function is strongly discouraged.
175 """
176 rc = libseccomp.seccomp_api_set(level)
177 if rc == -errno.EINVAL:
178 raise ValueError("Invalid level")
179 elif rc != 0:
180 raise RuntimeError(str.format("Library error (errno = {0})", rc))
181
62c6598e
PM
182cdef class Arch:
183 """ Python object representing the SyscallFilter architecture values.
184
185 Data values:
186 NATIVE - the native architecture
187 X86 - 32-bit x86
188 X86_64 - 64-bit x86
e9b5a6eb 189 X32 - 64-bit x86 using the x32 ABI
db440d1e 190 ARM - ARM
ab63dc7f 191 AARCH64 - 64-bit ARM
5a703f60
PM
192 MIPS - MIPS O32 ABI
193 MIPS64 - MIPS 64-bit ABI
194 MIPS64N32 - MIPS N32 ABI
195 MIPSEL - MIPS little endian O32 ABI
196 MIPSEL64 - MIPS little endian 64-bit ABI
197 MIPSEL64N32 - MIPS little endian N32 ABI
c86e1f56
HD
198 PARISC - 32-bit PA-RISC
199 PARISC64 - 64-bit PA-RISC
daed219e 200 PPC64 - 64-bit PowerPC
a2ad734f 201 PPC - 32-bit PowerPC
62c6598e 202 """
aeac2736 203
f05fc7cb
PM
204 cdef int _token
205
62c6598e
PM
206 NATIVE = libseccomp.SCMP_ARCH_NATIVE
207 X86 = libseccomp.SCMP_ARCH_X86
208 X86_64 = libseccomp.SCMP_ARCH_X86_64
e9b5a6eb 209 X32 = libseccomp.SCMP_ARCH_X32
db440d1e 210 ARM = libseccomp.SCMP_ARCH_ARM
ab63dc7f 211 AARCH64 = libseccomp.SCMP_ARCH_AARCH64
2b9c637c 212 MIPS = libseccomp.SCMP_ARCH_MIPS
5a703f60
PM
213 MIPS64 = libseccomp.SCMP_ARCH_MIPS64
214 MIPS64N32 = libseccomp.SCMP_ARCH_MIPS64N32
2b9c637c 215 MIPSEL = libseccomp.SCMP_ARCH_MIPSEL
5a703f60
PM
216 MIPSEL64 = libseccomp.SCMP_ARCH_MIPSEL64
217 MIPSEL64N32 = libseccomp.SCMP_ARCH_MIPSEL64N32
c86e1f56
HD
218 PARISC = libseccomp.SCMP_ARCH_PARISC
219 PARISC64 = libseccomp.SCMP_ARCH_PARISC64
fc886cbe 220 PPC = libseccomp.SCMP_ARCH_PPC
daed219e 221 PPC64 = libseccomp.SCMP_ARCH_PPC64
a2ad734f 222 PPC64LE = libseccomp.SCMP_ARCH_PPC64LE
c5d3e1d6
PM
223 S390 = libseccomp.SCMP_ARCH_S390
224 S390X = libseccomp.SCMP_ARCH_S390X
62c6598e 225
f05fc7cb
PM
226 def __cinit__(self, arch=libseccomp.SCMP_ARCH_NATIVE):
227 """ Initialize the architecture object.
228
229 Arguments:
230 arch - the architecture name or token value
231
232 Description:
233 Create an architecture object using the given name or token value.
234 """
235 if isinstance(arch, int):
236 if arch == libseccomp.SCMP_ARCH_NATIVE:
237 self._token = libseccomp.seccomp_arch_native()
238 elif arch == libseccomp.SCMP_ARCH_X86:
239 self._token = libseccomp.SCMP_ARCH_X86
240 elif arch == libseccomp.SCMP_ARCH_X86_64:
241 self._token = libseccomp.SCMP_ARCH_X86_64
242 elif arch == libseccomp.SCMP_ARCH_X32:
243 self._token = libseccomp.SCMP_ARCH_X32
244 elif arch == libseccomp.SCMP_ARCH_ARM:
245 self._token = libseccomp.SCMP_ARCH_ARM
ab63dc7f
MJ
246 elif arch == libseccomp.SCMP_ARCH_AARCH64:
247 self._token = libseccomp.SCMP_ARCH_AARCH64
f05fc7cb
PM
248 elif arch == libseccomp.SCMP_ARCH_MIPS:
249 self._token = libseccomp.SCMP_ARCH_MIPS
5a703f60
PM
250 elif arch == libseccomp.SCMP_ARCH_MIPS64:
251 self._token = libseccomp.SCMP_ARCH_MIPS64
252 elif arch == libseccomp.SCMP_ARCH_MIPS64N32:
253 self._token = libseccomp.SCMP_ARCH_MIPS64N32
f05fc7cb
PM
254 elif arch == libseccomp.SCMP_ARCH_MIPSEL:
255 self._token = libseccomp.SCMP_ARCH_MIPSEL
5a703f60
PM
256 elif arch == libseccomp.SCMP_ARCH_MIPSEL64:
257 self._token = libseccomp.SCMP_ARCH_MIPSEL64
258 elif arch == libseccomp.SCMP_ARCH_MIPSEL64N32:
259 self._token = libseccomp.SCMP_ARCH_MIPSEL64N32
c86e1f56
HD
260 elif arch == libseccomp.SCMP_ARCH_PARISC:
261 self._token = libseccomp.SCMP_ARCH_PARISC
262 elif arch == libseccomp.SCMP_ARCH_PARISC64:
263 self._token = libseccomp.SCMP_ARCH_PARISC64
fc886cbe
PM
264 elif arch == libseccomp.SCMP_ARCH_PPC:
265 self._token = libseccomp.SCMP_ARCH_PPC
daed219e
PM
266 elif arch == libseccomp.SCMP_ARCH_PPC64:
267 self._token = libseccomp.SCMP_ARCH_PPC64
268 elif arch == libseccomp.SCMP_ARCH_PPC64LE:
269 self._token = libseccomp.SCMP_ARCH_PPC64LE
c5d3e1d6
PM
270 elif arch == libseccomp.SCMP_ARCH_S390:
271 self._token = libseccomp.SCMP_ARCH_S390
272 elif arch == libseccomp.SCMP_ARCH_S390X:
273 self._token = libseccomp.SCMP_ARCH_S390X
f05fc7cb
PM
274 else:
275 self._token = 0;
276 elif isinstance(arch, basestring):
ce5aea6a 277 self._token = libseccomp.seccomp_arch_resolve_name(c_str(arch))
f05fc7cb
PM
278 else:
279 raise TypeError("Architecture must be an int or str type")
280 if self._token == 0:
281 raise ValueError("Invalid architecture")
282
283 def __int__(self):
284 """ Convert the architecture object to a token value.
285
286 Description:
287 Convert the architecture object to an integer representing the
288 architecture's token value.
289 """
290 return self._token
291
62c6598e
PM
292cdef class Attr:
293 """ Python object representing the SyscallFilter attributes.
294
295 Data values:
296 ACT_DEFAULT - the filter's default action
297 ACT_BADARCH - the filter's bad architecture action
298 CTL_NNP - the filter's "no new privileges" flag
4d29f586 299 CTL_NNP - the filter's thread sync flag
62c6598e
PM
300 """
301 ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT
302 ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH
303 CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP
4d29f586 304 CTL_TSYNC = libseccomp.SCMP_FLTATR_CTL_TSYNC
dc879990 305 API_TSKIP = libseccomp.SCMP_FLTATR_API_TSKIP
62c6598e
PM
306
307cdef class Arg:
308 """ Python object representing a SyscallFilter syscall argument.
309 """
310 cdef libseccomp.scmp_arg_cmp _arg
311
312 def __cinit__(self, arg, op, datum_a, datum_b = 0):
313 """ Initialize the argument comparison.
314
315 Arguments:
46a0ab2f 316 arg - the argument number, starting at 0
62c6598e
PM
317 op - the argument comparison operator, e.g. {NE,LT,LE,...}
318 datum_a - argument value
319 datum_b - argument value, only valid when op == MASKED_EQ
320
321 Description:
322 Create an argument comparison object for use with SyscallFilter.
323 """
324 self._arg.arg = arg
325 self._arg.op = op
8e1b4634
AL
326 self._arg.datum_a = datum_a
327 self._arg.datum_b = datum_b
62c6598e 328
dd673b51 329 cdef libseccomp.scmp_arg_cmp to_c(self):
62c6598e
PM
330 """ Convert the object into a C structure.
331
332 Description:
333 Helper function which should only be used internally by
334 SyscallFilter objects and exists for the sole purpose of making it
335 easier to deal with the varadic functions of the libseccomp API,
336 e.g. seccomp_rule_add().
337 """
338 return self._arg
339
340cdef class SyscallFilter:
341 """ Python object representing a seccomp syscall filter. """
342 cdef int _defaction
343 cdef libseccomp.scmp_filter_ctx _ctx
344
345 def __cinit__(self, int defaction):
4021195b
AL
346 self._ctx = libseccomp.seccomp_init(defaction)
347 if self._ctx == NULL:
348 raise RuntimeError("Library error")
349 _defaction = defaction
350
351 def __init__(self, defaction):
62c6598e
PM
352 """ Initialize the filter state
353
354 Arguments:
355 defaction - the default filter action
356
357 Description:
358 Initializes the seccomp filter state to the defaults.
359 """
62c6598e
PM
360
361 def __dealloc__(self):
362 """ Destroys the filter state and releases any resources.
363
364 Description:
365 Destroys the seccomp filter state and releases any resources
366 associated with the filter state. This function does not affect
367 any seccomp filters already loaded into the kernel.
368 """
369 if self._ctx != NULL:
370 libseccomp.seccomp_release(self._ctx)
371
372 def reset(self, int defaction = -1):
373 """ Reset the filter state.
374
375 Arguments:
376 defaction - the default filter action
377
378 Description:
379 Resets the seccomp filter state to an initial default state, if a
380 default filter action is not specified in the reset call the
381 original action will be reused. This function does not affect any
382 seccomp filters alread loaded into the kernel.
383 """
384 if defaction == -1:
385 defaction = self._defaction
386 rc = libseccomp.seccomp_reset(self._ctx, defaction)
387 if rc == -errno.EINVAL:
388 raise ValueError("Invalid action")
389 if rc != 0:
390 raise RuntimeError(str.format("Library error (errno = {0})", rc))
391 _defaction = defaction
392
393 def merge(self, SyscallFilter filter):
394 """ Merge two existing SyscallFilter objects.
395
396 Arguments:
397 filter - a valid SyscallFilter object
398
399 Description:
400 Merges a valid SyscallFilter object with the current SyscallFilter
401 object; the passed filter object will be reset on success. In
402 order to successfully merge two seccomp filters they must have the
403 same attribute values and not share any of the same architectures.
404 """
405 rc = libseccomp.seccomp_merge(self._ctx, filter._ctx)
406 if rc != 0:
407 raise RuntimeError(str.format("Library error (errno = {0})", rc))
408 filter._ctx = NULL
409 filter = SyscallFilter(filter._defaction)
410
411 def exist_arch(self, arch):
412 """ Check if the seccomp filter contains a given architecture.
413
414 Arguments:
415 arch - the architecture value, e.g. Arch.*
416
417 Description:
418 Test to see if a given architecture is included in the filter.
419 Return True is the architecture exists, False if it does not
420 exist.
421 """
422 rc = libseccomp.seccomp_arch_exist(self._ctx, arch)
423 if rc == 0:
424 return True
425 elif rc == -errno.EEXIST:
426 return False
427 elif rc == -errno.EINVAL:
428 raise ValueError("Invalid architecture")
429 else:
430 raise RuntimeError(str.format("Library error (errno = {0})", rc))
431
432 def add_arch(self, arch):
433 """ Add an architecture to the filter.
434
435 Arguments:
436 arch - the architecture value, e.g. Arch.*
437
438 Description:
439 Add the given architecture to the filter. Any new rules added
440 after this method returns successfully will be added to this new
441 architecture, but any existing rules will not be added to the new
442 architecture.
443 """
444 rc = libseccomp.seccomp_arch_add(self._ctx, arch)
445 if rc == -errno.EINVAL:
446 raise ValueError("Invalid architecture")
447 elif rc != 0:
448 raise RuntimeError(str.format("Library error (errno = {0})", rc))
449
450 def remove_arch(self, arch):
451 """ Remove an architecture from the filter.
452
453 Arguments:
454 arch - the architecture value, e.g. Arch.*
455
456 Description:
457 Remove the given architecture from the filter. The filter must
458 always contain at least one architecture, so if only one
459 architecture exists in the filter this method will fail.
460 """
461 rc = libseccomp.seccomp_arch_remove(self._ctx, arch)
462 if rc == -errno.EINVAL:
463 raise ValueError("Invalid architecture")
464 elif rc != 0:
465 raise RuntimeError(str.format("Library error (errno = {0})", rc))
466
467 def load(self):
468 """ Load the filter into the Linux Kernel.
469
470 Description:
471 Load the current filter into the Linux Kernel. As soon as the
472 method returns the filter will be active and enforcing.
473 """
474 rc = libseccomp.seccomp_load(self._ctx)
475 if rc != 0:
476 raise RuntimeError(str.format("Library error (errno = {0})", rc))
477
478 def get_attr(self, attr):
479 """ Get an attribute value from the filter.
480
481 Arguments:
482 attr - the attribute, e.g. Attr.*
483
484 Description:
485 Lookup the given attribute in the filter and return the
486 attribute's value to the caller.
487 """
4367b1b4 488 cdef uint32_t value = 0
62c6598e
PM
489 rc = libseccomp.seccomp_attr_get(self._ctx,
490 attr, <uint32_t *>&value)
491 if rc == -errno.EINVAL:
492 raise ValueError("Invalid attribute")
493 elif rc != 0:
494 raise RuntimeError(str.format("Library error (errno = {0})", rc))
495 return value
496
497 def set_attr(self, attr, int value):
498 """ Set a filter attribute.
499
500 Arguments:
501 attr - the attribute, e.g. Attr.*
502 value - the attribute value
503
504 Description:
505 Lookup the given attribute in the filter and assign it the given
506 value.
507 """
508 rc = libseccomp.seccomp_attr_set(self._ctx, attr, value)
509 if rc == -errno.EINVAL:
510 raise ValueError("Invalid attribute")
511 elif rc != 0:
512 raise RuntimeError(str.format("Library error (errno = {0})", rc))
513
514 def syscall_priority(self, syscall, int priority):
515 """ Set the filter priority of a syscall.
516
517 Arguments:
518 syscall - the syscall name or number
519 priority - the priority of the syscall
520
521 Description:
522 Set the filter priority of the given syscall. A syscall with a
523 higher priority will have less overhead in the generated filter
524 code which is loaded into the system. Priority values can range
525 from 0 to 255 inclusive.
526 """
527 if priority < 0 or priority > 255:
6220c8c0 528 raise ValueError("Syscall priority must be between 0 and 255")
62c6598e
PM
529 if isinstance(syscall, str):
530 syscall_str = syscall.encode()
531 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
532 elif isinstance(syscall, int):
533 syscall_num = syscall
534 else:
6220c8c0 535 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
536 rc = libseccomp.seccomp_syscall_priority(self._ctx,
537 syscall_num, priority)
538 if rc != 0:
539 raise RuntimeError(str.format("Library error (errno = {0})", rc))
540
541 def add_rule(self, int action, syscall, *args):
542 """ Add a new rule to filter.
543
544 Arguments:
545 action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
546 syscall - the syscall name or number
547 args - variable number of Arg objects
548
549 Description:
550 Add a new rule to the filter, matching on the given syscall and an
551 optional list of argument comparisons. If the rule is triggered
552 the given action will be taken by the kernel. In order for the
553 rule to trigger, the syscall as well as each argument comparison
554 must be true.
555
556 In the case where the specific rule is not valid on a specific
557 architecture, e.g. socket() on 32-bit x86, this method rewrites
558 the rule to the best possible match. If you don't want this fule
559 rewriting to take place use add_rule_exactly().
560 """
561 cdef libseccomp.scmp_arg_cmp c_arg[6]
562 if isinstance(syscall, str):
563 syscall_str = syscall.encode()
564 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
565 elif isinstance(syscall, int):
566 syscall_num = syscall
567 else:
6220c8c0 568 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
569 """ NOTE: the code below exists solely to deal with the varadic
570 nature of seccomp_rule_add() function and the inability of Cython
571 to handle this automatically """
2f65c7f4
PM
572 if len(args) > 6:
573 raise RuntimeError("Maximum number of arguments exceeded")
dd673b51 574 cdef Arg arg
62c6598e
PM
575 for i, arg in enumerate(args):
576 c_arg[i] = arg.to_c()
577 if len(args) == 0:
578 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, 0)
579 elif len(args) == 1:
580 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
581 len(args),
582 c_arg[0])
583 elif len(args) == 2:
584 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
585 len(args),
586 c_arg[0],
587 c_arg[1])
588 elif len(args) == 3:
589 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
590 len(args),
591 c_arg[0],
592 c_arg[1],
593 c_arg[2])
594 elif len(args) == 4:
595 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
596 len(args),
597 c_arg[0],
598 c_arg[1],
599 c_arg[2],
600 c_arg[3])
601 elif len(args) == 5:
602 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
603 len(args),
604 c_arg[0],
605 c_arg[1],
606 c_arg[2],
607 c_arg[3],
608 c_arg[4])
609 elif len(args) == 6:
610 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
611 len(args),
612 c_arg[0],
613 c_arg[1],
614 c_arg[2],
615 c_arg[3],
616 c_arg[4],
617 c_arg[5])
618 else:
619 raise RuntimeError("Maximum number of arguments exceeded")
620 if rc != 0:
621 raise RuntimeError(str.format("Library error (errno = {0})", rc))
622
623 def add_rule_exactly(self, int action, syscall, *args):
624 """ Add a new rule to filter.
625
626 Arguments:
627 action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
628 syscall - the syscall name or number
629 args - variable number of Arg objects
630
631 Description:
632 Add a new rule to the filter, matching on the given syscall and an
633 optional list of argument comparisons. If the rule is triggered
634 the given action will be taken by the kernel. In order for the
635 rule to trigger, the syscall as well as each argument comparison
636 must be true.
637
638 This method attempts to add the filter rule exactly as specified
639 which can cause problems on certain architectures, e.g. socket()
640 on 32-bit x86. For a architecture independent version of this
641 method use add_rule().
642 """
643 cdef libseccomp.scmp_arg_cmp c_arg[6]
644 if isinstance(syscall, str):
645 syscall_str = syscall.encode()
646 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
647 elif isinstance(syscall, int):
648 syscall_num = syscall
649 else:
6220c8c0 650 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
651 """ NOTE: the code below exists solely to deal with the varadic
652 nature of seccomp_rule_add_exact() function and the inability of
653 Cython to handle this automatically """
2f65c7f4
PM
654 if len(args) > 6:
655 raise RuntimeError("Maximum number of arguments exceeded")
dd673b51 656 cdef Arg arg
62c6598e
PM
657 for i, arg in enumerate(args):
658 c_arg[i] = arg.to_c()
659 if len(args) == 0:
660 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
661 syscall_num, 0)
662 elif len(args) == 1:
663 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
664 syscall_num, len(args),
665 c_arg[0])
666 elif len(args) == 2:
667 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
668 syscall_num, len(args),
669 c_arg[0],
670 c_arg[1])
671 elif len(args) == 3:
672 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
673 syscall_num, len(args),
674 c_arg[0],
675 c_arg[1],
676 c_arg[2])
677 elif len(args) == 4:
678 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
679 syscall_num, len(args),
680 c_arg[0],
681 c_arg[1],
682 c_arg[2],
683 c_arg[3])
684 elif len(args) == 5:
685 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
686 syscall_num, len(args),
687 c_arg[0],
688 c_arg[1],
689 c_arg[2],
690 c_arg[3],
691 c_arg[4])
692 elif len(args) == 6:
693 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
694 syscall_num, len(args),
695 c_arg[0],
696 c_arg[1],
697 c_arg[2],
698 c_arg[3],
699 c_arg[4],
700 c_arg[5])
701 else:
702 raise RuntimeError("Maximum number of arguments exceeded")
703 if rc != 0:
704 raise RuntimeError(str.format("Library error (errno = {0})", rc))
705
706 def export_pfc(self, file):
707 """ Export the filter in PFC format.
708
709 Arguments:
710 file - the output file
711
712 Description:
713 Output the filter in Pseudo Filter Code (PFC) to the given file.
714 The output is functionally equivalent to the BPF based filter
715 which is loaded into the Linux Kernel.
716 """
717 rc = libseccomp.seccomp_export_pfc(self._ctx, file.fileno())
718 if rc != 0:
719 raise RuntimeError(str.format("Library error (errno = {0})", rc))
720
721 def export_bpf(self, file):
722 """ Export the filter in BPF format.
723
724 Arguments:
725 file - the output file
726
727 Output the filter in Berkley Packet Filter (BPF) to the given
728 file. The output is identical to what is loaded into the
729 Linux Kernel.
730 """
731 rc = libseccomp.seccomp_export_bpf(self._ctx, file.fileno())
732 if rc != 0:
733 raise RuntimeError(str.format("Library error (errno = {0})", rc))
734
735# kate: syntax python;
736# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off;