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