]> git.proxmox.com Git - mirror_libseccomp.git/blame - src/python/seccomp.pyx
man: clarify syscall number rewriting
[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
62c6598e
PM
153cdef class Arch:
154 """ Python object representing the SyscallFilter architecture values.
155
156 Data values:
157 NATIVE - the native architecture
158 X86 - 32-bit x86
159 X86_64 - 64-bit x86
e9b5a6eb 160 X32 - 64-bit x86 using the x32 ABI
db440d1e 161 ARM - ARM
ab63dc7f 162 AARCH64 - 64-bit ARM
5a703f60
PM
163 MIPS - MIPS O32 ABI
164 MIPS64 - MIPS 64-bit ABI
165 MIPS64N32 - MIPS N32 ABI
166 MIPSEL - MIPS little endian O32 ABI
167 MIPSEL64 - MIPS little endian 64-bit ABI
168 MIPSEL64N32 - MIPS little endian N32 ABI
c86e1f56
HD
169 PARISC - 32-bit PA-RISC
170 PARISC64 - 64-bit PA-RISC
daed219e 171 PPC64 - 64-bit PowerPC
a2ad734f 172 PPC - 32-bit PowerPC
62c6598e 173 """
aeac2736 174
f05fc7cb
PM
175 cdef int _token
176
62c6598e
PM
177 NATIVE = libseccomp.SCMP_ARCH_NATIVE
178 X86 = libseccomp.SCMP_ARCH_X86
179 X86_64 = libseccomp.SCMP_ARCH_X86_64
e9b5a6eb 180 X32 = libseccomp.SCMP_ARCH_X32
db440d1e 181 ARM = libseccomp.SCMP_ARCH_ARM
ab63dc7f 182 AARCH64 = libseccomp.SCMP_ARCH_AARCH64
2b9c637c 183 MIPS = libseccomp.SCMP_ARCH_MIPS
5a703f60
PM
184 MIPS64 = libseccomp.SCMP_ARCH_MIPS64
185 MIPS64N32 = libseccomp.SCMP_ARCH_MIPS64N32
2b9c637c 186 MIPSEL = libseccomp.SCMP_ARCH_MIPSEL
5a703f60
PM
187 MIPSEL64 = libseccomp.SCMP_ARCH_MIPSEL64
188 MIPSEL64N32 = libseccomp.SCMP_ARCH_MIPSEL64N32
c86e1f56
HD
189 PARISC = libseccomp.SCMP_ARCH_PARISC
190 PARISC64 = libseccomp.SCMP_ARCH_PARISC64
fc886cbe 191 PPC = libseccomp.SCMP_ARCH_PPC
daed219e 192 PPC64 = libseccomp.SCMP_ARCH_PPC64
a2ad734f 193 PPC64LE = libseccomp.SCMP_ARCH_PPC64LE
c5d3e1d6
PM
194 S390 = libseccomp.SCMP_ARCH_S390
195 S390X = libseccomp.SCMP_ARCH_S390X
62c6598e 196
f05fc7cb
PM
197 def __cinit__(self, arch=libseccomp.SCMP_ARCH_NATIVE):
198 """ Initialize the architecture object.
199
200 Arguments:
201 arch - the architecture name or token value
202
203 Description:
204 Create an architecture object using the given name or token value.
205 """
206 if isinstance(arch, int):
207 if arch == libseccomp.SCMP_ARCH_NATIVE:
208 self._token = libseccomp.seccomp_arch_native()
209 elif arch == libseccomp.SCMP_ARCH_X86:
210 self._token = libseccomp.SCMP_ARCH_X86
211 elif arch == libseccomp.SCMP_ARCH_X86_64:
212 self._token = libseccomp.SCMP_ARCH_X86_64
213 elif arch == libseccomp.SCMP_ARCH_X32:
214 self._token = libseccomp.SCMP_ARCH_X32
215 elif arch == libseccomp.SCMP_ARCH_ARM:
216 self._token = libseccomp.SCMP_ARCH_ARM
ab63dc7f
MJ
217 elif arch == libseccomp.SCMP_ARCH_AARCH64:
218 self._token = libseccomp.SCMP_ARCH_AARCH64
f05fc7cb
PM
219 elif arch == libseccomp.SCMP_ARCH_MIPS:
220 self._token = libseccomp.SCMP_ARCH_MIPS
5a703f60
PM
221 elif arch == libseccomp.SCMP_ARCH_MIPS64:
222 self._token = libseccomp.SCMP_ARCH_MIPS64
223 elif arch == libseccomp.SCMP_ARCH_MIPS64N32:
224 self._token = libseccomp.SCMP_ARCH_MIPS64N32
f05fc7cb
PM
225 elif arch == libseccomp.SCMP_ARCH_MIPSEL:
226 self._token = libseccomp.SCMP_ARCH_MIPSEL
5a703f60
PM
227 elif arch == libseccomp.SCMP_ARCH_MIPSEL64:
228 self._token = libseccomp.SCMP_ARCH_MIPSEL64
229 elif arch == libseccomp.SCMP_ARCH_MIPSEL64N32:
230 self._token = libseccomp.SCMP_ARCH_MIPSEL64N32
c86e1f56
HD
231 elif arch == libseccomp.SCMP_ARCH_PARISC:
232 self._token = libseccomp.SCMP_ARCH_PARISC
233 elif arch == libseccomp.SCMP_ARCH_PARISC64:
234 self._token = libseccomp.SCMP_ARCH_PARISC64
fc886cbe
PM
235 elif arch == libseccomp.SCMP_ARCH_PPC:
236 self._token = libseccomp.SCMP_ARCH_PPC
daed219e
PM
237 elif arch == libseccomp.SCMP_ARCH_PPC64:
238 self._token = libseccomp.SCMP_ARCH_PPC64
239 elif arch == libseccomp.SCMP_ARCH_PPC64LE:
240 self._token = libseccomp.SCMP_ARCH_PPC64LE
c5d3e1d6
PM
241 elif arch == libseccomp.SCMP_ARCH_S390:
242 self._token = libseccomp.SCMP_ARCH_S390
243 elif arch == libseccomp.SCMP_ARCH_S390X:
244 self._token = libseccomp.SCMP_ARCH_S390X
f05fc7cb
PM
245 else:
246 self._token = 0;
247 elif isinstance(arch, basestring):
ce5aea6a 248 self._token = libseccomp.seccomp_arch_resolve_name(c_str(arch))
f05fc7cb
PM
249 else:
250 raise TypeError("Architecture must be an int or str type")
251 if self._token == 0:
252 raise ValueError("Invalid architecture")
253
254 def __int__(self):
255 """ Convert the architecture object to a token value.
256
257 Description:
258 Convert the architecture object to an integer representing the
259 architecture's token value.
260 """
261 return self._token
262
62c6598e
PM
263cdef class Attr:
264 """ Python object representing the SyscallFilter attributes.
265
266 Data values:
267 ACT_DEFAULT - the filter's default action
268 ACT_BADARCH - the filter's bad architecture action
269 CTL_NNP - the filter's "no new privileges" flag
4d29f586 270 CTL_NNP - the filter's thread sync flag
62c6598e
PM
271 """
272 ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT
273 ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH
274 CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP
4d29f586 275 CTL_TSYNC = libseccomp.SCMP_FLTATR_CTL_TSYNC
62c6598e
PM
276
277cdef class Arg:
278 """ Python object representing a SyscallFilter syscall argument.
279 """
280 cdef libseccomp.scmp_arg_cmp _arg
281
282 def __cinit__(self, arg, op, datum_a, datum_b = 0):
283 """ Initialize the argument comparison.
284
285 Arguments:
46a0ab2f 286 arg - the argument number, starting at 0
62c6598e
PM
287 op - the argument comparison operator, e.g. {NE,LT,LE,...}
288 datum_a - argument value
289 datum_b - argument value, only valid when op == MASKED_EQ
290
291 Description:
292 Create an argument comparison object for use with SyscallFilter.
293 """
294 self._arg.arg = arg
295 self._arg.op = op
8e1b4634
AL
296 self._arg.datum_a = datum_a
297 self._arg.datum_b = datum_b
62c6598e 298
dd673b51 299 cdef libseccomp.scmp_arg_cmp to_c(self):
62c6598e
PM
300 """ Convert the object into a C structure.
301
302 Description:
303 Helper function which should only be used internally by
304 SyscallFilter objects and exists for the sole purpose of making it
305 easier to deal with the varadic functions of the libseccomp API,
306 e.g. seccomp_rule_add().
307 """
308 return self._arg
309
310cdef class SyscallFilter:
311 """ Python object representing a seccomp syscall filter. """
312 cdef int _defaction
313 cdef libseccomp.scmp_filter_ctx _ctx
314
315 def __cinit__(self, int defaction):
4021195b
AL
316 self._ctx = libseccomp.seccomp_init(defaction)
317 if self._ctx == NULL:
318 raise RuntimeError("Library error")
319 _defaction = defaction
320
321 def __init__(self, defaction):
62c6598e
PM
322 """ Initialize the filter state
323
324 Arguments:
325 defaction - the default filter action
326
327 Description:
328 Initializes the seccomp filter state to the defaults.
329 """
62c6598e
PM
330
331 def __dealloc__(self):
332 """ Destroys the filter state and releases any resources.
333
334 Description:
335 Destroys the seccomp filter state and releases any resources
336 associated with the filter state. This function does not affect
337 any seccomp filters already loaded into the kernel.
338 """
339 if self._ctx != NULL:
340 libseccomp.seccomp_release(self._ctx)
341
342 def reset(self, int defaction = -1):
343 """ Reset the filter state.
344
345 Arguments:
346 defaction - the default filter action
347
348 Description:
349 Resets the seccomp filter state to an initial default state, if a
350 default filter action is not specified in the reset call the
351 original action will be reused. This function does not affect any
352 seccomp filters alread loaded into the kernel.
353 """
354 if defaction == -1:
355 defaction = self._defaction
356 rc = libseccomp.seccomp_reset(self._ctx, defaction)
357 if rc == -errno.EINVAL:
358 raise ValueError("Invalid action")
359 if rc != 0:
360 raise RuntimeError(str.format("Library error (errno = {0})", rc))
361 _defaction = defaction
362
363 def merge(self, SyscallFilter filter):
364 """ Merge two existing SyscallFilter objects.
365
366 Arguments:
367 filter - a valid SyscallFilter object
368
369 Description:
370 Merges a valid SyscallFilter object with the current SyscallFilter
371 object; the passed filter object will be reset on success. In
372 order to successfully merge two seccomp filters they must have the
373 same attribute values and not share any of the same architectures.
374 """
375 rc = libseccomp.seccomp_merge(self._ctx, filter._ctx)
376 if rc != 0:
377 raise RuntimeError(str.format("Library error (errno = {0})", rc))
378 filter._ctx = NULL
379 filter = SyscallFilter(filter._defaction)
380
381 def exist_arch(self, arch):
382 """ Check if the seccomp filter contains a given architecture.
383
384 Arguments:
385 arch - the architecture value, e.g. Arch.*
386
387 Description:
388 Test to see if a given architecture is included in the filter.
389 Return True is the architecture exists, False if it does not
390 exist.
391 """
392 rc = libseccomp.seccomp_arch_exist(self._ctx, arch)
393 if rc == 0:
394 return True
395 elif rc == -errno.EEXIST:
396 return False
397 elif rc == -errno.EINVAL:
398 raise ValueError("Invalid architecture")
399 else:
400 raise RuntimeError(str.format("Library error (errno = {0})", rc))
401
402 def add_arch(self, arch):
403 """ Add an architecture to the filter.
404
405 Arguments:
406 arch - the architecture value, e.g. Arch.*
407
408 Description:
409 Add the given architecture to the filter. Any new rules added
410 after this method returns successfully will be added to this new
411 architecture, but any existing rules will not be added to the new
412 architecture.
413 """
414 rc = libseccomp.seccomp_arch_add(self._ctx, arch)
415 if rc == -errno.EINVAL:
416 raise ValueError("Invalid architecture")
417 elif rc != 0:
418 raise RuntimeError(str.format("Library error (errno = {0})", rc))
419
420 def remove_arch(self, arch):
421 """ Remove an architecture from the filter.
422
423 Arguments:
424 arch - the architecture value, e.g. Arch.*
425
426 Description:
427 Remove the given architecture from the filter. The filter must
428 always contain at least one architecture, so if only one
429 architecture exists in the filter this method will fail.
430 """
431 rc = libseccomp.seccomp_arch_remove(self._ctx, arch)
432 if rc == -errno.EINVAL:
433 raise ValueError("Invalid architecture")
434 elif rc != 0:
435 raise RuntimeError(str.format("Library error (errno = {0})", rc))
436
437 def load(self):
438 """ Load the filter into the Linux Kernel.
439
440 Description:
441 Load the current filter into the Linux Kernel. As soon as the
442 method returns the filter will be active and enforcing.
443 """
444 rc = libseccomp.seccomp_load(self._ctx)
445 if rc != 0:
446 raise RuntimeError(str.format("Library error (errno = {0})", rc))
447
448 def get_attr(self, attr):
449 """ Get an attribute value from the filter.
450
451 Arguments:
452 attr - the attribute, e.g. Attr.*
453
454 Description:
455 Lookup the given attribute in the filter and return the
456 attribute's value to the caller.
457 """
4367b1b4 458 cdef uint32_t value = 0
62c6598e
PM
459 rc = libseccomp.seccomp_attr_get(self._ctx,
460 attr, <uint32_t *>&value)
461 if rc == -errno.EINVAL:
462 raise ValueError("Invalid attribute")
463 elif rc != 0:
464 raise RuntimeError(str.format("Library error (errno = {0})", rc))
465 return value
466
467 def set_attr(self, attr, int value):
468 """ Set a filter attribute.
469
470 Arguments:
471 attr - the attribute, e.g. Attr.*
472 value - the attribute value
473
474 Description:
475 Lookup the given attribute in the filter and assign it the given
476 value.
477 """
478 rc = libseccomp.seccomp_attr_set(self._ctx, attr, value)
479 if rc == -errno.EINVAL:
480 raise ValueError("Invalid attribute")
481 elif rc != 0:
482 raise RuntimeError(str.format("Library error (errno = {0})", rc))
483
484 def syscall_priority(self, syscall, int priority):
485 """ Set the filter priority of a syscall.
486
487 Arguments:
488 syscall - the syscall name or number
489 priority - the priority of the syscall
490
491 Description:
492 Set the filter priority of the given syscall. A syscall with a
493 higher priority will have less overhead in the generated filter
494 code which is loaded into the system. Priority values can range
495 from 0 to 255 inclusive.
496 """
497 if priority < 0 or priority > 255:
6220c8c0 498 raise ValueError("Syscall priority must be between 0 and 255")
62c6598e
PM
499 if isinstance(syscall, str):
500 syscall_str = syscall.encode()
501 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
502 elif isinstance(syscall, int):
503 syscall_num = syscall
504 else:
6220c8c0 505 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
506 rc = libseccomp.seccomp_syscall_priority(self._ctx,
507 syscall_num, priority)
508 if rc != 0:
509 raise RuntimeError(str.format("Library error (errno = {0})", rc))
510
511 def add_rule(self, int action, syscall, *args):
512 """ Add a new rule to filter.
513
514 Arguments:
515 action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
516 syscall - the syscall name or number
517 args - variable number of Arg objects
518
519 Description:
520 Add a new rule to the filter, matching on the given syscall and an
521 optional list of argument comparisons. If the rule is triggered
522 the given action will be taken by the kernel. In order for the
523 rule to trigger, the syscall as well as each argument comparison
524 must be true.
525
526 In the case where the specific rule is not valid on a specific
527 architecture, e.g. socket() on 32-bit x86, this method rewrites
528 the rule to the best possible match. If you don't want this fule
529 rewriting to take place use add_rule_exactly().
530 """
531 cdef libseccomp.scmp_arg_cmp c_arg[6]
532 if isinstance(syscall, str):
533 syscall_str = syscall.encode()
534 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
535 elif isinstance(syscall, int):
536 syscall_num = syscall
537 else:
6220c8c0 538 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
539 """ NOTE: the code below exists solely to deal with the varadic
540 nature of seccomp_rule_add() function and the inability of Cython
541 to handle this automatically """
2f65c7f4
PM
542 if len(args) > 6:
543 raise RuntimeError("Maximum number of arguments exceeded")
dd673b51 544 cdef Arg arg
62c6598e
PM
545 for i, arg in enumerate(args):
546 c_arg[i] = arg.to_c()
547 if len(args) == 0:
548 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, 0)
549 elif len(args) == 1:
550 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
551 len(args),
552 c_arg[0])
553 elif len(args) == 2:
554 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
555 len(args),
556 c_arg[0],
557 c_arg[1])
558 elif len(args) == 3:
559 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
560 len(args),
561 c_arg[0],
562 c_arg[1],
563 c_arg[2])
564 elif len(args) == 4:
565 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
566 len(args),
567 c_arg[0],
568 c_arg[1],
569 c_arg[2],
570 c_arg[3])
571 elif len(args) == 5:
572 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
573 len(args),
574 c_arg[0],
575 c_arg[1],
576 c_arg[2],
577 c_arg[3],
578 c_arg[4])
579 elif len(args) == 6:
580 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
581 len(args),
582 c_arg[0],
583 c_arg[1],
584 c_arg[2],
585 c_arg[3],
586 c_arg[4],
587 c_arg[5])
588 else:
589 raise RuntimeError("Maximum number of arguments exceeded")
590 if rc != 0:
591 raise RuntimeError(str.format("Library error (errno = {0})", rc))
592
593 def add_rule_exactly(self, int action, syscall, *args):
594 """ Add a new rule to filter.
595
596 Arguments:
597 action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
598 syscall - the syscall name or number
599 args - variable number of Arg objects
600
601 Description:
602 Add a new rule to the filter, matching on the given syscall and an
603 optional list of argument comparisons. If the rule is triggered
604 the given action will be taken by the kernel. In order for the
605 rule to trigger, the syscall as well as each argument comparison
606 must be true.
607
608 This method attempts to add the filter rule exactly as specified
609 which can cause problems on certain architectures, e.g. socket()
610 on 32-bit x86. For a architecture independent version of this
611 method use add_rule().
612 """
613 cdef libseccomp.scmp_arg_cmp c_arg[6]
614 if isinstance(syscall, str):
615 syscall_str = syscall.encode()
616 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
617 elif isinstance(syscall, int):
618 syscall_num = syscall
619 else:
6220c8c0 620 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
621 """ NOTE: the code below exists solely to deal with the varadic
622 nature of seccomp_rule_add_exact() function and the inability of
623 Cython to handle this automatically """
2f65c7f4
PM
624 if len(args) > 6:
625 raise RuntimeError("Maximum number of arguments exceeded")
dd673b51 626 cdef Arg arg
62c6598e
PM
627 for i, arg in enumerate(args):
628 c_arg[i] = arg.to_c()
629 if len(args) == 0:
630 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
631 syscall_num, 0)
632 elif len(args) == 1:
633 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
634 syscall_num, len(args),
635 c_arg[0])
636 elif len(args) == 2:
637 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
638 syscall_num, len(args),
639 c_arg[0],
640 c_arg[1])
641 elif len(args) == 3:
642 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
643 syscall_num, len(args),
644 c_arg[0],
645 c_arg[1],
646 c_arg[2])
647 elif len(args) == 4:
648 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
649 syscall_num, len(args),
650 c_arg[0],
651 c_arg[1],
652 c_arg[2],
653 c_arg[3])
654 elif len(args) == 5:
655 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
656 syscall_num, len(args),
657 c_arg[0],
658 c_arg[1],
659 c_arg[2],
660 c_arg[3],
661 c_arg[4])
662 elif len(args) == 6:
663 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
664 syscall_num, len(args),
665 c_arg[0],
666 c_arg[1],
667 c_arg[2],
668 c_arg[3],
669 c_arg[4],
670 c_arg[5])
671 else:
672 raise RuntimeError("Maximum number of arguments exceeded")
673 if rc != 0:
674 raise RuntimeError(str.format("Library error (errno = {0})", rc))
675
676 def export_pfc(self, file):
677 """ Export the filter in PFC format.
678
679 Arguments:
680 file - the output file
681
682 Description:
683 Output the filter in Pseudo Filter Code (PFC) to the given file.
684 The output is functionally equivalent to the BPF based filter
685 which is loaded into the Linux Kernel.
686 """
687 rc = libseccomp.seccomp_export_pfc(self._ctx, file.fileno())
688 if rc != 0:
689 raise RuntimeError(str.format("Library error (errno = {0})", rc))
690
691 def export_bpf(self, file):
692 """ Export the filter in BPF format.
693
694 Arguments:
695 file - the output file
696
697 Output the filter in Berkley Packet Filter (BPF) to the given
698 file. The output is identical to what is loaded into the
699 Linux Kernel.
700 """
701 rc = libseccomp.seccomp_export_bpf(self._ctx, file.fileno())
702 if rc != 0:
703 raise RuntimeError(str.format("Library error (errno = {0})", rc))
704
705# kate: syntax python;
706# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off;