]> git.proxmox.com Git - mirror_libseccomp.git/blame - src/python/seccomp.pyx
build: ship seccomp-syscalls.h
[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
d390edad
PM
22# cython: language_level = 3str
23
62c6598e
PM
24""" Python bindings for the libseccomp library
25
26The libseccomp library provides and easy to use, platform independent,
27interface to the Linux Kernel's syscall filtering mechanism: seccomp. The
28libseccomp API is designed to abstract away the underlying BPF based
29syscall filter language and present a more conventional function-call
30based filtering interface that should be familiar to, and easily adopted
31by application developers.
32
33Filter action values:
b2f15f3d
TH
34 KILL_PROCESS - kill the process
35 KILL - kill the thread
3b22b153 36 LOG - allow the syscall to be executed after the action has been logged
62c6598e
PM
37 ALLOW - allow the syscall to execute
38 TRAP - a SIGSYS signal will be thrown
e15f4157 39 NOTIFY - a notification event will be sent via the notification API
62c6598e
PM
40 ERRNO(x) - syscall will return (x)
41 TRACE(x) - if the process is being traced, (x) will be returned to the
42 tracing process via PTRACE_EVENT_SECCOMP and the
43 PTRACE_GETEVENTMSG option
44
70c89434
PM
45Argument comparison values (see the Arg class):
46
47 NE - arg != datum_a
48 LT - arg < datum_a
49 LE - arg <= datum_a
50 EQ - arg == datum_a
51 GT - arg > datum_a
52 GE - arg >= datum_a
0f589d15 53 MASKED_EQ - (arg & datum_a) == datum_b
62c6598e
PM
54
55
56Example:
57
58 import sys
59 from seccomp import *
60
61 # create a filter object with a default KILL action
62 f = SyscallFilter(defaction=KILL)
63
853a24c8
JP
64 # add some basic syscalls which python typically wants
65 f.add_rule(ALLOW, "rt_sigaction")
66 f.add_rule(ALLOW, "rt_sigreturn")
67 f.add_rule(ALLOW, "exit_group")
68 f.add_rule(ALLOW, "brk")
69
62c6598e
PM
70 # add syscall filter rules to allow certain syscalls
71 f.add_rule(ALLOW, "open")
72 f.add_rule(ALLOW, "close")
853a24c8
JP
73 f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin.fileno()))
74 f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno()))
75 f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno()))
62c6598e
PM
76
77 # load the filter into the kernel
78 f.load()
79"""
80__author__ = 'Paul Moore <paul@paul-moore.com>'
ce5aea6a 81__date__ = "3 February 2017"
62c6598e 82
ce5aea6a 83from cpython.version cimport PY_MAJOR_VERSION
e15f4157
PM
84from libc.stdint cimport int8_t, int16_t, int32_t, int64_t
85from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t
86from libc.stdlib cimport free
62c6598e
PM
87import errno
88
89cimport libseccomp
90
ce5aea6a
PM
91def c_str(string):
92 """ Convert a Python string to a C string.
93
94 Arguments:
95 string - the Python string
96
97 Description:
98 Convert the Python string into a form usable by C taking into consideration
99 the Python major version, e.g. Python 2.x or Python 3.x.
100 See http://docs.cython.org/en/latest/src/tutorial/strings.html for more
101 information.
102 """
103 if PY_MAJOR_VERSION < 3:
104 return string
105 else:
106 return bytes(string, "ascii")
107
b2f15f3d 108KILL_PROCESS = libseccomp.SCMP_ACT_KILL_PROCESS
62c6598e
PM
109KILL = libseccomp.SCMP_ACT_KILL
110TRAP = libseccomp.SCMP_ACT_TRAP
3b22b153 111LOG = libseccomp.SCMP_ACT_LOG
62c6598e 112ALLOW = libseccomp.SCMP_ACT_ALLOW
e15f4157 113NOTIFY = libseccomp.SCMP_ACT_NOTIFY
62c6598e 114def ERRNO(int errno):
28a57d88
AL
115 """The action ERRNO(x) means that the syscall will return (x).
116 To conform to Linux syscall calling conventions, the syscall return
117 value should almost always be a negative number.
118 """
62c6598e
PM
119 return libseccomp.SCMP_ACT_ERRNO(errno)
120def TRACE(int value):
28a57d88
AL
121 """The action TRACE(x) means that, if the process is being traced, (x)
122 will be returned to the tracing process via PTRACE_EVENT_SECCOMP
123 and the PTRACE_GETEVENTMSG option.
124 """
62c6598e
PM
125 return libseccomp.SCMP_ACT_TRACE(value)
126
127NE = libseccomp.SCMP_CMP_NE
128LT = libseccomp.SCMP_CMP_LT
129LE = libseccomp.SCMP_CMP_LE
130EQ = libseccomp.SCMP_CMP_EQ
131GE = libseccomp.SCMP_CMP_GE
132GT = libseccomp.SCMP_CMP_GT
133MASKED_EQ = libseccomp.SCMP_CMP_MASKED_EQ
134
aeac2736
PM
135def system_arch():
136 """ Return the system architecture value.
137
138 Description:
139 Returns the native system architecture value.
140 """
141 return libseccomp.seccomp_arch_native()
142
6220c8c0
PM
143def resolve_syscall(arch, syscall):
144 """ Resolve the syscall.
145
146 Arguments:
147 arch - the architecture value, e.g. Arch.*
148 syscall - the syscall name or number
149
150 Description:
151 Resolve an architecture's syscall name to the correct number or the
152 syscall number to the correct name.
153 """
f7c11d67
AL
154 cdef char *ret_str
155
f05fc7cb 156 if isinstance(syscall, basestring):
ce5aea6a
PM
157 return libseccomp.seccomp_syscall_resolve_name_rewrite(arch,
158 c_str(syscall))
f05fc7cb 159 elif isinstance(syscall, int):
f7c11d67
AL
160 ret_str = libseccomp.seccomp_syscall_resolve_num_arch(arch, syscall)
161 if ret_str is NULL:
162 raise ValueError('Unknown syscall %d on arch %d' % (syscall, arch))
163 else:
164 return ret_str
6220c8c0
PM
165 else:
166 raise TypeError("Syscall must either be an int or str type")
167
4f16fe20
TH
168def get_api():
169 """ Query the level of API support
170
171 Description:
172 Returns the API level value indicating the current supported
173 functionality.
174 """
175 level = libseccomp.seccomp_api_get()
176 if level < 0:
177 raise RuntimeError(str.format("Library error (errno = {0})", level))
178
179 return level
180
181def set_api(unsigned int level):
182 """ Set the level of API support
183
184 Arguments:
185 level - the API level
186
187 Description:
188 This function forcibly sets the API level at runtime. General use
189 of this function is strongly discouraged.
190 """
191 rc = libseccomp.seccomp_api_set(level)
192 if rc == -errno.EINVAL:
193 raise ValueError("Invalid level")
194 elif rc != 0:
195 raise RuntimeError(str.format("Library error (errno = {0})", rc))
196
62c6598e
PM
197cdef class Arch:
198 """ Python object representing the SyscallFilter architecture values.
199
200 Data values:
201 NATIVE - the native architecture
202 X86 - 32-bit x86
203 X86_64 - 64-bit x86
e9b5a6eb 204 X32 - 64-bit x86 using the x32 ABI
db440d1e 205 ARM - ARM
ab63dc7f 206 AARCH64 - 64-bit ARM
5a703f60
PM
207 MIPS - MIPS O32 ABI
208 MIPS64 - MIPS 64-bit ABI
209 MIPS64N32 - MIPS N32 ABI
210 MIPSEL - MIPS little endian O32 ABI
211 MIPSEL64 - MIPS little endian 64-bit ABI
212 MIPSEL64N32 - MIPS little endian N32 ABI
c86e1f56
HD
213 PARISC - 32-bit PA-RISC
214 PARISC64 - 64-bit PA-RISC
daed219e 215 PPC64 - 64-bit PowerPC
a2ad734f 216 PPC - 32-bit PowerPC
62c6598e 217 """
aeac2736 218
f05fc7cb
PM
219 cdef int _token
220
62c6598e
PM
221 NATIVE = libseccomp.SCMP_ARCH_NATIVE
222 X86 = libseccomp.SCMP_ARCH_X86
223 X86_64 = libseccomp.SCMP_ARCH_X86_64
e9b5a6eb 224 X32 = libseccomp.SCMP_ARCH_X32
db440d1e 225 ARM = libseccomp.SCMP_ARCH_ARM
ab63dc7f 226 AARCH64 = libseccomp.SCMP_ARCH_AARCH64
2b9c637c 227 MIPS = libseccomp.SCMP_ARCH_MIPS
5a703f60
PM
228 MIPS64 = libseccomp.SCMP_ARCH_MIPS64
229 MIPS64N32 = libseccomp.SCMP_ARCH_MIPS64N32
2b9c637c 230 MIPSEL = libseccomp.SCMP_ARCH_MIPSEL
5a703f60
PM
231 MIPSEL64 = libseccomp.SCMP_ARCH_MIPSEL64
232 MIPSEL64N32 = libseccomp.SCMP_ARCH_MIPSEL64N32
c86e1f56
HD
233 PARISC = libseccomp.SCMP_ARCH_PARISC
234 PARISC64 = libseccomp.SCMP_ARCH_PARISC64
fc886cbe 235 PPC = libseccomp.SCMP_ARCH_PPC
daed219e 236 PPC64 = libseccomp.SCMP_ARCH_PPC64
a2ad734f 237 PPC64LE = libseccomp.SCMP_ARCH_PPC64LE
c5d3e1d6
PM
238 S390 = libseccomp.SCMP_ARCH_S390
239 S390X = libseccomp.SCMP_ARCH_S390X
62c6598e 240
f05fc7cb
PM
241 def __cinit__(self, arch=libseccomp.SCMP_ARCH_NATIVE):
242 """ Initialize the architecture object.
243
244 Arguments:
245 arch - the architecture name or token value
246
247 Description:
248 Create an architecture object using the given name or token value.
249 """
250 if isinstance(arch, int):
251 if arch == libseccomp.SCMP_ARCH_NATIVE:
252 self._token = libseccomp.seccomp_arch_native()
253 elif arch == libseccomp.SCMP_ARCH_X86:
254 self._token = libseccomp.SCMP_ARCH_X86
255 elif arch == libseccomp.SCMP_ARCH_X86_64:
256 self._token = libseccomp.SCMP_ARCH_X86_64
257 elif arch == libseccomp.SCMP_ARCH_X32:
258 self._token = libseccomp.SCMP_ARCH_X32
259 elif arch == libseccomp.SCMP_ARCH_ARM:
260 self._token = libseccomp.SCMP_ARCH_ARM
ab63dc7f
MJ
261 elif arch == libseccomp.SCMP_ARCH_AARCH64:
262 self._token = libseccomp.SCMP_ARCH_AARCH64
f05fc7cb
PM
263 elif arch == libseccomp.SCMP_ARCH_MIPS:
264 self._token = libseccomp.SCMP_ARCH_MIPS
5a703f60
PM
265 elif arch == libseccomp.SCMP_ARCH_MIPS64:
266 self._token = libseccomp.SCMP_ARCH_MIPS64
267 elif arch == libseccomp.SCMP_ARCH_MIPS64N32:
268 self._token = libseccomp.SCMP_ARCH_MIPS64N32
f05fc7cb
PM
269 elif arch == libseccomp.SCMP_ARCH_MIPSEL:
270 self._token = libseccomp.SCMP_ARCH_MIPSEL
5a703f60
PM
271 elif arch == libseccomp.SCMP_ARCH_MIPSEL64:
272 self._token = libseccomp.SCMP_ARCH_MIPSEL64
273 elif arch == libseccomp.SCMP_ARCH_MIPSEL64N32:
274 self._token = libseccomp.SCMP_ARCH_MIPSEL64N32
c86e1f56
HD
275 elif arch == libseccomp.SCMP_ARCH_PARISC:
276 self._token = libseccomp.SCMP_ARCH_PARISC
277 elif arch == libseccomp.SCMP_ARCH_PARISC64:
278 self._token = libseccomp.SCMP_ARCH_PARISC64
fc886cbe
PM
279 elif arch == libseccomp.SCMP_ARCH_PPC:
280 self._token = libseccomp.SCMP_ARCH_PPC
daed219e
PM
281 elif arch == libseccomp.SCMP_ARCH_PPC64:
282 self._token = libseccomp.SCMP_ARCH_PPC64
283 elif arch == libseccomp.SCMP_ARCH_PPC64LE:
284 self._token = libseccomp.SCMP_ARCH_PPC64LE
c5d3e1d6
PM
285 elif arch == libseccomp.SCMP_ARCH_S390:
286 self._token = libseccomp.SCMP_ARCH_S390
287 elif arch == libseccomp.SCMP_ARCH_S390X:
288 self._token = libseccomp.SCMP_ARCH_S390X
f05fc7cb
PM
289 else:
290 self._token = 0;
291 elif isinstance(arch, basestring):
ce5aea6a 292 self._token = libseccomp.seccomp_arch_resolve_name(c_str(arch))
f05fc7cb
PM
293 else:
294 raise TypeError("Architecture must be an int or str type")
295 if self._token == 0:
296 raise ValueError("Invalid architecture")
297
298 def __int__(self):
299 """ Convert the architecture object to a token value.
300
301 Description:
302 Convert the architecture object to an integer representing the
303 architecture's token value.
304 """
305 return self._token
306
62c6598e
PM
307cdef class Attr:
308 """ Python object representing the SyscallFilter attributes.
309
310 Data values:
311 ACT_DEFAULT - the filter's default action
312 ACT_BADARCH - the filter's bad architecture action
313 CTL_NNP - the filter's "no new privileges" flag
4d29f586 314 CTL_NNP - the filter's thread sync flag
e15f4157
PM
315 CTL_TSYNC - sync threads on filter load
316 CTL_TSKIP - allow rules with a -1 syscall number
317 CTL_LOG - log not-allowed actions
318 CTL_SSB - disable SSB mitigations
62c6598e
PM
319 """
320 ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT
321 ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH
322 CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP
4d29f586 323 CTL_TSYNC = libseccomp.SCMP_FLTATR_CTL_TSYNC
dc879990 324 API_TSKIP = libseccomp.SCMP_FLTATR_API_TSKIP
d0e11951 325 CTL_LOG = libseccomp.SCMP_FLTATR_CTL_LOG
a15a87c3 326 CTL_SSB = libseccomp.SCMP_FLTATR_CTL_SSB
62c6598e
PM
327
328cdef class Arg:
329 """ Python object representing a SyscallFilter syscall argument.
330 """
331 cdef libseccomp.scmp_arg_cmp _arg
332
333 def __cinit__(self, arg, op, datum_a, datum_b = 0):
334 """ Initialize the argument comparison.
335
336 Arguments:
46a0ab2f 337 arg - the argument number, starting at 0
62c6598e
PM
338 op - the argument comparison operator, e.g. {NE,LT,LE,...}
339 datum_a - argument value
340 datum_b - argument value, only valid when op == MASKED_EQ
341
342 Description:
343 Create an argument comparison object for use with SyscallFilter.
344 """
345 self._arg.arg = arg
346 self._arg.op = op
8e1b4634
AL
347 self._arg.datum_a = datum_a
348 self._arg.datum_b = datum_b
62c6598e 349
dd673b51 350 cdef libseccomp.scmp_arg_cmp to_c(self):
62c6598e
PM
351 """ Convert the object into a C structure.
352
353 Description:
354 Helper function which should only be used internally by
355 SyscallFilter objects and exists for the sole purpose of making it
356 easier to deal with the varadic functions of the libseccomp API,
357 e.g. seccomp_rule_add().
358 """
359 return self._arg
360
e15f4157
PM
361cdef class Notification:
362 """ Python object representing a seccomp notification.
363 """
364 cdef uint64_t _id
365 cdef uint32_t _pid
366 cdef uint32_t _flags
367 cdef int _syscall
368 cdef uint32_t _syscall_arch
369 cdef uint64_t _syscall_ip
370 cdef uint64_t _syscall_args[6]
371
372 def __cinit__(self, id, pid, flags, syscall, arch, ip, args):
373 """ Initialize the notification.
374
375 Arguments:
376 id - the notification ID
377 pid - the process ID
378 flags - the notification flags
379 syscall - the syscall number
380 ip - the instruction pointer
381 args - list of the six syscall arguments
382
383 Description:
384 Create a seccomp Notification object.
385 """
386 self._id = id
387 self._pid = pid
388 self._flags = flags
389 self._syscall = syscall
390 self._syscall_arch = arch
391 self._syscall_ip = ip
392 self._syscall_args[0] = args[0]
393 self._syscall_args[1] = args[1]
394 self._syscall_args[2] = args[2]
395 self._syscall_args[3] = args[3]
396 self._syscall_args[4] = args[4]
397 self._syscall_args[5] = args[5]
398
399 @property
400 def id(self):
401 """ Get the seccomp notification ID.
402
403 Description:
404 Get the seccomp notification ID.
405 """
406 return self._id
407
408 @property
409 def pid(self):
410 """ Get the seccomp notification process ID.
411
412 Description:
413 Get the seccomp notification process ID.
414 """
415 return self._pid
416
417 @property
418 def flags(self):
419 """ Get the seccomp notification flags.
420
421 Description:
422 Get the seccomp notification flags.
423 """
424 return self._flags
425
426 @property
427 def syscall(self):
428 """ Get the seccomp notification syscall.
429
430 Description:
431 Get the seccomp notification syscall.
432 """
433 return self._syscall
434
435 @property
436 def syscall_arch(self):
437 """ Get the seccomp notification syscall architecture.
438
439 Description:
440 Get the seccomp notification syscall architecture.
441 """
442 return self._syscall_arch
443
444 @property
445 def syscall_ip(self):
446 """ Get the seccomp notification syscall instruction pointer.
447
448 Description:
449 Get the seccomp notification syscall instruction pointer.
450 """
451 return self._syscall_ip
452
453 @property
454 def syscall_args(self):
455 """ Get the seccomp notification syscall arguments.
456
457 Description:
458 Get the seccomp notification syscall arguments in a six element list.
459 """
460 return [self._syscall_args[0], self._syscall_args[1],
461 self._syscall_args[2], self._syscall_args[3],
462 self._syscall_args[4], self._syscall_args[5]]
463
464cdef class NotificationResponse:
465 """ Python object representing a seccomp notification response.
466 """
467 cdef uint64_t _id
468 cdef int64_t _val
469 cdef int32_t _error
470 cdef uint32_t _flags
471
472 def __cinit__(self, notify, val = 0, error = 0, flags = 0):
473 """ Initialize the notification response.
474
475 Arguments:
476 notify - a Notification object
477 val - the notification response value
478 error - the notification response error
479 flags - the notification response flags
480
481 Description:
482 Create a seccomp NotificationResponse object.
483 """
484 self._id = notify.id
485 self._val = val
486 self._error = error
487 self._flags = flags
488
489 @property
490 def id(self):
491 """ Get the seccomp notification response ID.
492
493 Description:
494 Get the seccomp notification response ID.
495 """
496 return self._id
497
498 @id.setter
499 def id(self, value):
500 """ Set the seccomp notification response ID.
501
502 Arguments:
503 id - the notification response ID
504
505 Description:
506 Set the seccomp notification response ID.
507 """
508 self._id = value
509
510 @property
511 def val(self):
512 """ Get the seccomp notification response value.
513
514 Description:
515 Get the seccomp notification response value.
516 """
517 return self._val
518
519 @val.setter
520 def val(self, value):
521 """ Set the seccomp notification response value.
522
523 Arguments:
524 val - the notification response value
525
526 Description:
527 Set the seccomp notification response value.
528 """
529 self._val = value
530
531 @property
532 def error(self):
533 """ Get the seccomp notification response error.
534
535 Description:
536 Get the seccomp notification response error.
537 """
538 return self._error
539
540 @error.setter
541 def error(self, value):
542 """ Set the seccomp notification response error.
543
544 Arguments:
545 error - the notification response error
546
547 Description:
548 Set the seccomp notification response error.
549 """
550 self._error = value
551
552 @property
553 def flags(self):
554 """ Get the seccomp notification response flags.
555
556 Description:
557 Get the seccomp notification response flags.
558 """
559 return self._flags
560
561 @flags.setter
562 def flags(self, value):
563 """ Set the seccomp notification response flags.
564
565 Arguments:
566 flags - the notification response flags
567
568 Description:
569 Set the seccomp notification response flags.
570 """
571 self._flags = value
572
62c6598e
PM
573cdef class SyscallFilter:
574 """ Python object representing a seccomp syscall filter. """
575 cdef int _defaction
576 cdef libseccomp.scmp_filter_ctx _ctx
577
578 def __cinit__(self, int defaction):
4021195b
AL
579 self._ctx = libseccomp.seccomp_init(defaction)
580 if self._ctx == NULL:
581 raise RuntimeError("Library error")
582 _defaction = defaction
583
584 def __init__(self, defaction):
62c6598e
PM
585 """ Initialize the filter state
586
587 Arguments:
588 defaction - the default filter action
589
590 Description:
591 Initializes the seccomp filter state to the defaults.
592 """
62c6598e
PM
593
594 def __dealloc__(self):
595 """ Destroys the filter state and releases any resources.
596
597 Description:
598 Destroys the seccomp filter state and releases any resources
599 associated with the filter state. This function does not affect
600 any seccomp filters already loaded into the kernel.
601 """
602 if self._ctx != NULL:
603 libseccomp.seccomp_release(self._ctx)
604
605 def reset(self, int defaction = -1):
606 """ Reset the filter state.
607
608 Arguments:
609 defaction - the default filter action
610
611 Description:
612 Resets the seccomp filter state to an initial default state, if a
613 default filter action is not specified in the reset call the
614 original action will be reused. This function does not affect any
615 seccomp filters alread loaded into the kernel.
616 """
617 if defaction == -1:
618 defaction = self._defaction
619 rc = libseccomp.seccomp_reset(self._ctx, defaction)
620 if rc == -errno.EINVAL:
621 raise ValueError("Invalid action")
622 if rc != 0:
623 raise RuntimeError(str.format("Library error (errno = {0})", rc))
624 _defaction = defaction
625
626 def merge(self, SyscallFilter filter):
627 """ Merge two existing SyscallFilter objects.
628
629 Arguments:
630 filter - a valid SyscallFilter object
631
632 Description:
633 Merges a valid SyscallFilter object with the current SyscallFilter
634 object; the passed filter object will be reset on success. In
635 order to successfully merge two seccomp filters they must have the
636 same attribute values and not share any of the same architectures.
637 """
638 rc = libseccomp.seccomp_merge(self._ctx, filter._ctx)
639 if rc != 0:
640 raise RuntimeError(str.format("Library error (errno = {0})", rc))
641 filter._ctx = NULL
642 filter = SyscallFilter(filter._defaction)
643
644 def exist_arch(self, arch):
645 """ Check if the seccomp filter contains a given architecture.
646
647 Arguments:
648 arch - the architecture value, e.g. Arch.*
649
650 Description:
651 Test to see if a given architecture is included in the filter.
652 Return True is the architecture exists, False if it does not
653 exist.
654 """
655 rc = libseccomp.seccomp_arch_exist(self._ctx, arch)
656 if rc == 0:
657 return True
658 elif rc == -errno.EEXIST:
659 return False
660 elif rc == -errno.EINVAL:
661 raise ValueError("Invalid architecture")
662 else:
663 raise RuntimeError(str.format("Library error (errno = {0})", rc))
664
665 def add_arch(self, arch):
666 """ Add an architecture to the filter.
667
668 Arguments:
669 arch - the architecture value, e.g. Arch.*
670
671 Description:
672 Add the given architecture to the filter. Any new rules added
673 after this method returns successfully will be added to this new
674 architecture, but any existing rules will not be added to the new
675 architecture.
676 """
677 rc = libseccomp.seccomp_arch_add(self._ctx, arch)
678 if rc == -errno.EINVAL:
679 raise ValueError("Invalid architecture")
680 elif rc != 0:
681 raise RuntimeError(str.format("Library error (errno = {0})", rc))
682
683 def remove_arch(self, arch):
684 """ Remove an architecture from the filter.
685
686 Arguments:
687 arch - the architecture value, e.g. Arch.*
688
689 Description:
690 Remove the given architecture from the filter. The filter must
691 always contain at least one architecture, so if only one
692 architecture exists in the filter this method will fail.
693 """
694 rc = libseccomp.seccomp_arch_remove(self._ctx, arch)
695 if rc == -errno.EINVAL:
696 raise ValueError("Invalid architecture")
697 elif rc != 0:
698 raise RuntimeError(str.format("Library error (errno = {0})", rc))
699
700 def load(self):
701 """ Load the filter into the Linux Kernel.
702
703 Description:
704 Load the current filter into the Linux Kernel. As soon as the
705 method returns the filter will be active and enforcing.
706 """
707 rc = libseccomp.seccomp_load(self._ctx)
708 if rc != 0:
709 raise RuntimeError(str.format("Library error (errno = {0})", rc))
710
711 def get_attr(self, attr):
712 """ Get an attribute value from the filter.
713
714 Arguments:
715 attr - the attribute, e.g. Attr.*
716
717 Description:
718 Lookup the given attribute in the filter and return the
719 attribute's value to the caller.
720 """
4367b1b4 721 cdef uint32_t value = 0
62c6598e
PM
722 rc = libseccomp.seccomp_attr_get(self._ctx,
723 attr, <uint32_t *>&value)
724 if rc == -errno.EINVAL:
725 raise ValueError("Invalid attribute")
726 elif rc != 0:
727 raise RuntimeError(str.format("Library error (errno = {0})", rc))
728 return value
729
730 def set_attr(self, attr, int value):
731 """ Set a filter attribute.
732
733 Arguments:
734 attr - the attribute, e.g. Attr.*
735 value - the attribute value
736
737 Description:
738 Lookup the given attribute in the filter and assign it the given
739 value.
740 """
741 rc = libseccomp.seccomp_attr_set(self._ctx, attr, value)
742 if rc == -errno.EINVAL:
743 raise ValueError("Invalid attribute")
744 elif rc != 0:
745 raise RuntimeError(str.format("Library error (errno = {0})", rc))
746
747 def syscall_priority(self, syscall, int priority):
748 """ Set the filter priority of a syscall.
749
750 Arguments:
751 syscall - the syscall name or number
752 priority - the priority of the syscall
753
754 Description:
755 Set the filter priority of the given syscall. A syscall with a
756 higher priority will have less overhead in the generated filter
757 code which is loaded into the system. Priority values can range
758 from 0 to 255 inclusive.
759 """
760 if priority < 0 or priority > 255:
6220c8c0 761 raise ValueError("Syscall priority must be between 0 and 255")
62c6598e
PM
762 if isinstance(syscall, str):
763 syscall_str = syscall.encode()
764 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
765 elif isinstance(syscall, int):
766 syscall_num = syscall
767 else:
6220c8c0 768 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
769 rc = libseccomp.seccomp_syscall_priority(self._ctx,
770 syscall_num, priority)
771 if rc != 0:
772 raise RuntimeError(str.format("Library error (errno = {0})", rc))
773
774 def add_rule(self, int action, syscall, *args):
775 """ Add a new rule to filter.
776
777 Arguments:
b2f15f3d
TH
778 action - the rule action: KILL_PROCESS, KILL, TRAP, ERRNO(), TRACE(),
779 LOG, or ALLOW
62c6598e
PM
780 syscall - the syscall name or number
781 args - variable number of Arg objects
782
783 Description:
784 Add a new rule to the filter, matching on the given syscall and an
785 optional list of argument comparisons. If the rule is triggered
786 the given action will be taken by the kernel. In order for the
787 rule to trigger, the syscall as well as each argument comparison
788 must be true.
789
790 In the case where the specific rule is not valid on a specific
791 architecture, e.g. socket() on 32-bit x86, this method rewrites
792 the rule to the best possible match. If you don't want this fule
793 rewriting to take place use add_rule_exactly().
794 """
795 cdef libseccomp.scmp_arg_cmp c_arg[6]
796 if isinstance(syscall, str):
797 syscall_str = syscall.encode()
798 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
799 elif isinstance(syscall, int):
800 syscall_num = syscall
801 else:
6220c8c0 802 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
803 """ NOTE: the code below exists solely to deal with the varadic
804 nature of seccomp_rule_add() function and the inability of Cython
805 to handle this automatically """
2f65c7f4
PM
806 if len(args) > 6:
807 raise RuntimeError("Maximum number of arguments exceeded")
dd673b51 808 cdef Arg arg
62c6598e
PM
809 for i, arg in enumerate(args):
810 c_arg[i] = arg.to_c()
811 if len(args) == 0:
812 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, 0)
813 elif len(args) == 1:
814 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
815 len(args),
816 c_arg[0])
817 elif len(args) == 2:
818 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
819 len(args),
820 c_arg[0],
821 c_arg[1])
822 elif len(args) == 3:
823 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
824 len(args),
825 c_arg[0],
826 c_arg[1],
827 c_arg[2])
828 elif len(args) == 4:
829 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
830 len(args),
831 c_arg[0],
832 c_arg[1],
833 c_arg[2],
834 c_arg[3])
835 elif len(args) == 5:
836 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
837 len(args),
838 c_arg[0],
839 c_arg[1],
840 c_arg[2],
841 c_arg[3],
842 c_arg[4])
843 elif len(args) == 6:
844 rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
845 len(args),
846 c_arg[0],
847 c_arg[1],
848 c_arg[2],
849 c_arg[3],
850 c_arg[4],
851 c_arg[5])
852 else:
853 raise RuntimeError("Maximum number of arguments exceeded")
854 if rc != 0:
855 raise RuntimeError(str.format("Library error (errno = {0})", rc))
856
857 def add_rule_exactly(self, int action, syscall, *args):
858 """ Add a new rule to filter.
859
860 Arguments:
b2f15f3d
TH
861 action - the rule action: KILL_PROCESS, KILL, TRAP, ERRNO(), TRACE(),
862 LOG, or ALLOW
62c6598e
PM
863 syscall - the syscall name or number
864 args - variable number of Arg objects
865
866 Description:
867 Add a new rule to the filter, matching on the given syscall and an
868 optional list of argument comparisons. If the rule is triggered
869 the given action will be taken by the kernel. In order for the
870 rule to trigger, the syscall as well as each argument comparison
871 must be true.
872
873 This method attempts to add the filter rule exactly as specified
874 which can cause problems on certain architectures, e.g. socket()
875 on 32-bit x86. For a architecture independent version of this
876 method use add_rule().
877 """
878 cdef libseccomp.scmp_arg_cmp c_arg[6]
879 if isinstance(syscall, str):
880 syscall_str = syscall.encode()
881 syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
882 elif isinstance(syscall, int):
883 syscall_num = syscall
884 else:
6220c8c0 885 raise TypeError("Syscall must either be an int or str type")
62c6598e
PM
886 """ NOTE: the code below exists solely to deal with the varadic
887 nature of seccomp_rule_add_exact() function and the inability of
888 Cython to handle this automatically """
2f65c7f4
PM
889 if len(args) > 6:
890 raise RuntimeError("Maximum number of arguments exceeded")
dd673b51 891 cdef Arg arg
62c6598e
PM
892 for i, arg in enumerate(args):
893 c_arg[i] = arg.to_c()
894 if len(args) == 0:
895 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
896 syscall_num, 0)
897 elif len(args) == 1:
898 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
899 syscall_num, len(args),
900 c_arg[0])
901 elif len(args) == 2:
902 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
903 syscall_num, len(args),
904 c_arg[0],
905 c_arg[1])
906 elif len(args) == 3:
907 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
908 syscall_num, len(args),
909 c_arg[0],
910 c_arg[1],
911 c_arg[2])
912 elif len(args) == 4:
913 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
914 syscall_num, len(args),
915 c_arg[0],
916 c_arg[1],
917 c_arg[2],
918 c_arg[3])
919 elif len(args) == 5:
920 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
921 syscall_num, len(args),
922 c_arg[0],
923 c_arg[1],
924 c_arg[2],
925 c_arg[3],
926 c_arg[4])
927 elif len(args) == 6:
928 rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
929 syscall_num, len(args),
930 c_arg[0],
931 c_arg[1],
932 c_arg[2],
933 c_arg[3],
934 c_arg[4],
935 c_arg[5])
936 else:
937 raise RuntimeError("Maximum number of arguments exceeded")
938 if rc != 0:
939 raise RuntimeError(str.format("Library error (errno = {0})", rc))
940
e15f4157
PM
941 def receive_notify(self):
942 """ Receive seccomp notifications.
943
944 Description:
945 Receive a seccomp notification from the system, requires the use of
946 the NOTIFY action.
947 """
948 cdef libseccomp.seccomp_notif *req
949
950 fd = libseccomp.seccomp_notify_fd(self._ctx)
951 if fd < 0:
952 raise RuntimeError("Notifications not enabled/active")
953 rc = libseccomp.seccomp_notify_alloc(&req, NULL)
954 if rc < 0:
955 raise RuntimeError(str.format("Library error (errno = {0})", rc))
956 rc = libseccomp.seccomp_notify_receive(fd, req)
957 if rc < 0:
958 raise RuntimeError(str.format("Library error (errno = {0})", rc))
959 rc = libseccomp.seccomp_notify_id_valid(fd, req.id)
960 if rc < 0:
961 raise RuntimeError(str.format("Library error (errno = {0})", rc))
962 notify = Notification(req.id, req.pid, req.flags, req.data.nr,
963 req.data.arch, req.data.instruction_pointer,
964 [req.data.args[0], req.data.args[1],
965 req.data.args[2], req.data.args[3],
966 req.data.args[4], req.data.args[5]])
967 free(req)
968 return notify
969
970 def respond_notify(self, response):
971 """ Send a seccomp notification response.
972
973 Arguments:
974 response - the response to send to the system
975
976 Description:
977 Respond to a seccomp notification.
978 """
979 cdef libseccomp.seccomp_notif_resp *resp
980
981 fd = libseccomp.seccomp_notify_fd(self._ctx)
982 if fd < 0:
983 raise RuntimeError("Notifications not enabled/active")
984 rc = libseccomp.seccomp_notify_alloc(NULL, &resp)
985 if rc < 0:
986 raise RuntimeError(str.format("Library error (errno = {0})", rc))
987 resp.id = response.id
988 resp.val = response.val
989 resp.error = response.error
990 resp.flags = response.flags
991 rc = libseccomp.seccomp_notify_respond(fd, resp)
992 if rc < 0:
993 raise RuntimeError(str.format("Library error (errno = {0})", rc))
994
62c6598e
PM
995 def export_pfc(self, file):
996 """ Export the filter in PFC format.
997
998 Arguments:
999 file - the output file
1000
1001 Description:
1002 Output the filter in Pseudo Filter Code (PFC) to the given file.
1003 The output is functionally equivalent to the BPF based filter
1004 which is loaded into the Linux Kernel.
1005 """
1006 rc = libseccomp.seccomp_export_pfc(self._ctx, file.fileno())
1007 if rc != 0:
1008 raise RuntimeError(str.format("Library error (errno = {0})", rc))
1009
1010 def export_bpf(self, file):
1011 """ Export the filter in BPF format.
1012
1013 Arguments:
1014 file - the output file
1015
e15f4157 1016 Description:
62c6598e
PM
1017 Output the filter in Berkley Packet Filter (BPF) to the given
1018 file. The output is identical to what is loaded into the
1019 Linux Kernel.
1020 """
1021 rc = libseccomp.seccomp_export_bpf(self._ctx, file.fileno())
1022 if rc != 0:
1023 raise RuntimeError(str.format("Library error (errno = {0})", rc))
1024
1025# kate: syntax python;
1026# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off;