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