From 016ee2428d181b69d16ad511b020d97293a23caa Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 12 Apr 2014 18:44:22 +0100 Subject: [PATCH 1/1] Import libseccomp_2.1.1.orig.tar.gz [dgit import orig libseccomp_2.1.1.orig.tar.gz] --- CHANGELOG | 47 + CREDITS | 15 + LICENSE | 456 +++++ Makefile | 126 ++ README | 48 + configure | 277 +++ doc/Makefile | 74 + doc/man/man1/scmp_sys_resolver.1 | 60 + doc/man/man3/seccomp_arch_add.3 | 125 ++ doc/man/man3/seccomp_arch_exist.3 | 1 + doc/man/man3/seccomp_arch_native.3 | 1 + doc/man/man3/seccomp_arch_remove.3 | 1 + doc/man/man3/seccomp_attr_get.3 | 1 + doc/man/man3/seccomp_attr_set.3 | 121 ++ doc/man/man3/seccomp_export_bpf.3 | 108 + doc/man/man3/seccomp_export_pfc.3 | 1 + doc/man/man3/seccomp_init.3 | 136 ++ doc/man/man3/seccomp_load.3 | 83 + doc/man/man3/seccomp_merge.3 | 122 ++ doc/man/man3/seccomp_release.3 | 77 + doc/man/man3/seccomp_reset.3 | 1 + doc/man/man3/seccomp_rule_add.3 | 295 +++ doc/man/man3/seccomp_rule_add_array.3 | 1 + doc/man/man3/seccomp_rule_add_exact.3 | 1 + doc/man/man3/seccomp_rule_add_exact_array.3 | 1 + doc/man/man3/seccomp_syscall_priority.3 | 111 ++ doc/man/man3/seccomp_syscall_resolve_name.3 | 113 ++ .../man3/seccomp_syscall_resolve_name_arch.3 | 1 + .../man3/seccomp_syscall_resolve_num_arch.3 | 1 + include/Makefile | 57 + include/seccomp.h.in | 1164 +++++++++++ install.mk | 31 + libseccomp.pc.in | 31 + macros.mk | 234 +++ src/Makefile | 92 + src/api.c | 589 ++++++ src/arch-arm-syscalls.c | 479 +++++ src/arch-arm.c | 34 + src/arch-arm.h | 37 + src/arch-x32-syscalls.c | 67 + src/arch-x32.c | 35 + src/arch-x32.h | 39 + src/arch-x86-syscalls.c | 468 +++++ src/arch-x86.c | 112 ++ src/arch-x86.h | 43 + src/arch-x86_64-syscalls.c | 468 +++++ src/arch-x86_64.c | 34 + src/arch-x86_64.h | 40 + src/arch.c | 322 +++ src/arch.h | 106 + src/db.c | 1314 ++++++++++++ src/db.h | 194 ++ src/gen_bpf.c | 1755 +++++++++++++++++ src/gen_bpf.h | 42 + src/gen_pfc.c | 336 ++++ src/gen_pfc.h | 29 + src/hash.c | 674 +++++++ src/hash.h | 26 + src/python/Makefile | 54 + src/python/libseccomp.pxd | 98 + src/python/seccomp.pyx | 572 ++++++ src/python/setup.py | 45 + src/system.h | 92 + tags | 779 ++++++++ tests/00-test.c | 60 + tests/01-sim-allow.c | 49 + tests/01-sim-allow.py | 40 + tests/01-sim-allow.tests | 21 + tests/02-sim-basic.c | 72 + tests/02-sim-basic.py | 44 + tests/02-sim-basic.tests | 30 + tests/03-sim-basic_chains.c | 73 + tests/03-sim-basic_chains.py | 45 + tests/03-sim-basic_chains.tests | 32 + tests/04-sim-multilevel_chains.c | 87 + tests/04-sim-multilevel_chains.py | 56 + tests/04-sim-multilevel_chains.tests | 42 + tests/05-sim-long_jumps.c | 79 + tests/05-sim-long_jumps.py | 56 + tests/05-sim-long_jumps.tests | 37 + tests/06-sim-actions.c | 68 + tests/06-sim-actions.py | 45 + tests/06-sim-actions.tests | 27 + tests/07-sim-db_bug_looping.c | 67 + tests/07-sim-db_bug_looping.py | 45 + tests/07-sim-db_bug_looping.tests | 23 + tests/08-sim-subtree_checks.c | 178 ++ tests/08-sim-subtree_checks.py | 122 ++ tests/08-sim-subtree_checks.tests | 47 + tests/09-sim-syscall_priority_pre.c | 75 + tests/09-sim-syscall_priority_pre.py | 47 + tests/09-sim-syscall_priority_pre.tests | 26 + tests/10-sim-syscall_priority_post.c | 75 + tests/10-sim-syscall_priority_post.py | 47 + tests/10-sim-syscall_priority_post.tests | 26 + tests/11-basic-basic_errors.c | 168 ++ tests/11-basic-basic_errors.py | 88 + tests/11-basic-basic_errors.tests | 11 + tests/12-sim-basic_masked_ops.c | 87 + tests/12-sim-basic_masked_ops.py | 61 + tests/12-sim-basic_masked_ops.tests | 42 + tests/13-basic-attrs.c | 78 + tests/13-basic-attrs.py | 49 + tests/13-basic-attrs.tests | 11 + tests/14-sim-reset.c | 62 + tests/14-sim-reset.py | 43 + tests/14-sim-reset.tests | 29 + tests/15-basic-resolver.c | 59 + tests/15-basic-resolver.py | 54 + tests/15-basic-resolver.tests | 11 + tests/16-sim-arch_basic.c | 102 + tests/16-sim-arch_basic.py | 55 + tests/16-sim-arch_basic.tests | 32 + tests/17-sim-arch_merge.c | 110 ++ tests/17-sim-arch_merge.py | 55 + tests/17-sim-arch_merge.tests | 29 + tests/18-sim-basic_whitelist.c | 73 + tests/18-sim-basic_whitelist.py | 45 + tests/18-sim-basic_whitelist.tests | 32 + tests/19-sim-missing_syscalls.c | 66 + tests/19-sim-missing_syscalls.py | 48 + tests/19-sim-missing_syscalls.tests | 21 + tests/20-live-basic_die.c | 69 + tests/20-live-basic_die.py | 48 + tests/20-live-basic_die.tests | 13 + tests/21-live-basic_allow.c | 76 + tests/21-live-basic_allow.py | 59 + tests/21-live-basic_allow.tests | 11 + tests/22-sim-basic_chains_array.c | 77 + tests/22-sim-basic_chains_array.py | 48 + tests/22-sim-basic_chains_array.tests | 31 + tests/23-sim-arch_all_basic.c | 93 + tests/23-sim-arch_all_basic.py | 53 + tests/23-sim-arch_all_basic.tests | 28 + tests/24-live-arg_allow.c | 93 + tests/24-live-arg_allow.py | 60 + tests/24-live-arg_allow.tests | 11 + tests/25-sim-multilevel_chains_adv.c | 62 + tests/25-sim-multilevel_chains_adv.py | 47 + tests/25-sim-multilevel_chains_adv.tests | 30 + tests/Makefile | 95 + tests/regression | 885 +++++++++ tests/testdiff | 126 ++ tests/testgen | 206 ++ tests/util.c | 209 ++ tests/util.h | 40 + tests/util.py | 109 + tools/Makefile | 66 + tools/bpf.h | 124 ++ tools/check-syntax | 116 ++ tools/scmp_app_inspector | 103 + tools/scmp_arch_detect.c | 88 + tools/scmp_bpf_disasm.c | 322 +++ tools/scmp_bpf_sim.c | 310 +++ tools/scmp_sys_resolver.c | 104 + version.h | 8 + version_info | 8 + 157 files changed, 19987 insertions(+) create mode 100644 CHANGELOG create mode 100644 CREDITS create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100755 configure create mode 100644 doc/Makefile create mode 100644 doc/man/man1/scmp_sys_resolver.1 create mode 100644 doc/man/man3/seccomp_arch_add.3 create mode 100644 doc/man/man3/seccomp_arch_exist.3 create mode 100644 doc/man/man3/seccomp_arch_native.3 create mode 100644 doc/man/man3/seccomp_arch_remove.3 create mode 100644 doc/man/man3/seccomp_attr_get.3 create mode 100644 doc/man/man3/seccomp_attr_set.3 create mode 100644 doc/man/man3/seccomp_export_bpf.3 create mode 100644 doc/man/man3/seccomp_export_pfc.3 create mode 100644 doc/man/man3/seccomp_init.3 create mode 100644 doc/man/man3/seccomp_load.3 create mode 100644 doc/man/man3/seccomp_merge.3 create mode 100644 doc/man/man3/seccomp_release.3 create mode 100644 doc/man/man3/seccomp_reset.3 create mode 100644 doc/man/man3/seccomp_rule_add.3 create mode 100644 doc/man/man3/seccomp_rule_add_array.3 create mode 100644 doc/man/man3/seccomp_rule_add_exact.3 create mode 100644 doc/man/man3/seccomp_rule_add_exact_array.3 create mode 100644 doc/man/man3/seccomp_syscall_priority.3 create mode 100644 doc/man/man3/seccomp_syscall_resolve_name.3 create mode 100644 doc/man/man3/seccomp_syscall_resolve_name_arch.3 create mode 100644 doc/man/man3/seccomp_syscall_resolve_num_arch.3 create mode 100644 include/Makefile create mode 100644 include/seccomp.h.in create mode 100644 install.mk create mode 100644 libseccomp.pc.in create mode 100644 macros.mk create mode 100644 src/Makefile create mode 100644 src/api.c create mode 100644 src/arch-arm-syscalls.c create mode 100644 src/arch-arm.c create mode 100644 src/arch-arm.h create mode 100644 src/arch-x32-syscalls.c create mode 100644 src/arch-x32.c create mode 100644 src/arch-x32.h create mode 100644 src/arch-x86-syscalls.c create mode 100644 src/arch-x86.c create mode 100644 src/arch-x86.h create mode 100644 src/arch-x86_64-syscalls.c create mode 100644 src/arch-x86_64.c create mode 100644 src/arch-x86_64.h create mode 100644 src/arch.c create mode 100644 src/arch.h create mode 100644 src/db.c create mode 100644 src/db.h create mode 100644 src/gen_bpf.c create mode 100644 src/gen_bpf.h create mode 100644 src/gen_pfc.c create mode 100644 src/gen_pfc.h create mode 100644 src/hash.c create mode 100644 src/hash.h create mode 100644 src/python/Makefile create mode 100644 src/python/libseccomp.pxd create mode 100644 src/python/seccomp.pyx create mode 100644 src/python/setup.py create mode 100644 src/system.h create mode 100644 tags create mode 100644 tests/00-test.c create mode 100644 tests/01-sim-allow.c create mode 100755 tests/01-sim-allow.py create mode 100644 tests/01-sim-allow.tests create mode 100644 tests/02-sim-basic.c create mode 100755 tests/02-sim-basic.py create mode 100644 tests/02-sim-basic.tests create mode 100644 tests/03-sim-basic_chains.c create mode 100755 tests/03-sim-basic_chains.py create mode 100644 tests/03-sim-basic_chains.tests create mode 100644 tests/04-sim-multilevel_chains.c create mode 100755 tests/04-sim-multilevel_chains.py create mode 100644 tests/04-sim-multilevel_chains.tests create mode 100644 tests/05-sim-long_jumps.c create mode 100755 tests/05-sim-long_jumps.py create mode 100644 tests/05-sim-long_jumps.tests create mode 100644 tests/06-sim-actions.c create mode 100755 tests/06-sim-actions.py create mode 100644 tests/06-sim-actions.tests create mode 100644 tests/07-sim-db_bug_looping.c create mode 100755 tests/07-sim-db_bug_looping.py create mode 100644 tests/07-sim-db_bug_looping.tests create mode 100644 tests/08-sim-subtree_checks.c create mode 100755 tests/08-sim-subtree_checks.py create mode 100644 tests/08-sim-subtree_checks.tests create mode 100644 tests/09-sim-syscall_priority_pre.c create mode 100755 tests/09-sim-syscall_priority_pre.py create mode 100644 tests/09-sim-syscall_priority_pre.tests create mode 100644 tests/10-sim-syscall_priority_post.c create mode 100755 tests/10-sim-syscall_priority_post.py create mode 100644 tests/10-sim-syscall_priority_post.tests create mode 100644 tests/11-basic-basic_errors.c create mode 100755 tests/11-basic-basic_errors.py create mode 100644 tests/11-basic-basic_errors.tests create mode 100644 tests/12-sim-basic_masked_ops.c create mode 100755 tests/12-sim-basic_masked_ops.py create mode 100644 tests/12-sim-basic_masked_ops.tests create mode 100644 tests/13-basic-attrs.c create mode 100755 tests/13-basic-attrs.py create mode 100644 tests/13-basic-attrs.tests create mode 100644 tests/14-sim-reset.c create mode 100755 tests/14-sim-reset.py create mode 100644 tests/14-sim-reset.tests create mode 100644 tests/15-basic-resolver.c create mode 100755 tests/15-basic-resolver.py create mode 100644 tests/15-basic-resolver.tests create mode 100644 tests/16-sim-arch_basic.c create mode 100755 tests/16-sim-arch_basic.py create mode 100644 tests/16-sim-arch_basic.tests create mode 100644 tests/17-sim-arch_merge.c create mode 100755 tests/17-sim-arch_merge.py create mode 100644 tests/17-sim-arch_merge.tests create mode 100644 tests/18-sim-basic_whitelist.c create mode 100755 tests/18-sim-basic_whitelist.py create mode 100644 tests/18-sim-basic_whitelist.tests create mode 100644 tests/19-sim-missing_syscalls.c create mode 100755 tests/19-sim-missing_syscalls.py create mode 100644 tests/19-sim-missing_syscalls.tests create mode 100644 tests/20-live-basic_die.c create mode 100755 tests/20-live-basic_die.py create mode 100644 tests/20-live-basic_die.tests create mode 100644 tests/21-live-basic_allow.c create mode 100755 tests/21-live-basic_allow.py create mode 100644 tests/21-live-basic_allow.tests create mode 100644 tests/22-sim-basic_chains_array.c create mode 100755 tests/22-sim-basic_chains_array.py create mode 100644 tests/22-sim-basic_chains_array.tests create mode 100644 tests/23-sim-arch_all_basic.c create mode 100755 tests/23-sim-arch_all_basic.py create mode 100644 tests/23-sim-arch_all_basic.tests create mode 100644 tests/24-live-arg_allow.c create mode 100755 tests/24-live-arg_allow.py create mode 100644 tests/24-live-arg_allow.tests create mode 100644 tests/25-sim-multilevel_chains_adv.c create mode 100755 tests/25-sim-multilevel_chains_adv.py create mode 100644 tests/25-sim-multilevel_chains_adv.tests create mode 100644 tests/Makefile create mode 100755 tests/regression create mode 100755 tests/testdiff create mode 100755 tests/testgen create mode 100644 tests/util.c create mode 100644 tests/util.h create mode 100644 tests/util.py create mode 100644 tools/Makefile create mode 100644 tools/bpf.h create mode 100755 tools/check-syntax create mode 100755 tools/scmp_app_inspector create mode 100644 tools/scmp_arch_detect.c create mode 100644 tools/scmp_bpf_disasm.c create mode 100644 tools/scmp_bpf_sim.c create mode 100644 tools/scmp_sys_resolver.c create mode 100644 version.h create mode 100644 version_info diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..d63d8e6 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,47 @@ +libseccomp: Releases +=============================================================================== +http://libseccomp.sf.net + +* Version 2.1.1 - October 31, 2013 +- Build system improvements +- Automated test improvments, including a "check" target for use by + packagers to verify the build +- Numerous bug fixes related to the filter's internal rule database which + affect those creating rules with syscall arguments +- Introduced tools to verify the style/formatting of the code, including a + "check-syntax" target for use by developers +- Non-public symbols are now hidden in the library + +* Version 2.1.0 - June 11, 2013 +- Add support for the x32 and ARM architectures +- Improvements to the regression tests, including support for live tests +- More verbose PFC output, including translation of syscall numbers to names +- Several assorted bugfixes affecting the seccomp BPF generation +- The syscall number/name resolver tool is now available to install + +* Version 2.0.0 - January 28, 2013 +- Fixes for the x86 multiplexed syscalls +- Additions to the API to better support non-native architecures +- Additions to the API to support multiple architecures in one filter +- Additions to the API to resolve syscall name/number mappings +- Assorted minor bug fixes +- Improved build messages regardless of build verbosity +- More automated tests added as well as a number of improvements to the test + harness + +* Version 1.0.1 - November 12, 2012 +- The header file is now easier to use with C++ compilers +- Minor documentation fixes +- Minor memory leak fixes +- Corrected x86 filter generation on x86_64 systems +- Corrected problems with small filters and filters with arguments + +* Version 1.0.0 - July 31, 2012 +- Change the API to be context-aware; eliminates all internal state but breaks + compatibility with the previous 0.1.0 release +- Added support for multiple build jobs ("make -j8") and verbose builds using + the "V=1" build variable ("make V=1") +- Minor tweaks to the regression test script output + +* Version 0.1.0 - June 8, 2012 +- Initial release diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..d62a39c --- /dev/null +++ b/CREDITS @@ -0,0 +1,15 @@ +libseccomp: Contributors +=============================================================================== +http://libseccomp.sf.net + +Andy Lutomirski +Ashley Lai +Corey Bryant +Eduardo Otubo +Eric Paris +Jake Edge +Joe MacDonald +Kees Cook +Paul Moore +Thiago Marcos P. Santos +Vitaly Vi Shukela diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ca4f73b --- /dev/null +++ b/LICENSE @@ -0,0 +1,456 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1f61f20 --- /dev/null +++ b/Makefile @@ -0,0 +1,126 @@ +# +# Enhanced Seccomp Library Makefile +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# +# macros +# + +include macros.mk + +# +# configuration +# + +-include version_info.mk +-include configure.mk +include install.mk + +# +# targets +# + +CONFIGS = configure.mk configure.h version_info.mk libseccomp.pc +SUBDIRS_BUILD = include src tests tools +SUBDIRS_INSTALL = include src tools doc + +.PHONY: tarball install check check-syntax ctags cstags clean dist-clean \ + $(SUBDIRS_BUILD) + +all: $(SUBDIRS_BUILD) + +$(CONFIGS): version_info + @$(ECHO_INFO) "automatically generating configuration ..." + @./configure + +tarball: dist-clean + @ver=$(VERSION_RELEASE); \ + tarball=libseccomp-$$ver.tar.gz; \ + $(ECHO_INFO) "creating the tarball ../$$tarball"; \ + tmp_dir=$$(mktemp -d /tmp/libseccomp.XXXXX); \ + rel_dir=$$tmp_dir/libseccomp-$$ver; \ + $(MKDIR) $$rel_dir; \ + $(TAR) cf - --exclude=*~ --exclude=.git* --exclude=.stgit* . | \ + (cd $$rel_dir; tar xf -); \ + (cd $$tmp_dir; $(TAR) zcf $$tarball libseccomp-$$ver); \ + $(MV) $$tmp_dir/$$tarball ..; \ + $(RM) -rf $$tmp_dir; + +$(VERSION_HDR): version_info.mk + @$(ECHO_INFO) "creating the version header file" + @hdr="$(VERSION_HDR)"; \ + $(ECHO) "/* automatically generated - do not edit */" > $$hdr; \ + $(ECHO) "#ifndef _VERSION_H" >> $$hdr; \ + $(ECHO) "#define _VERSION_H" >> $$hdr; \ + $(ECHO) "#define VERSION_RELEASE \"$(VERSION_RELEASE)\"" >> $$hdr; \ + $(ECHO) "#define VERSION_MAJOR $(VERSION_MAJOR)" >> $$hdr; \ + $(ECHO) "#define VERSION_MINOR $(VERSION_MINOR)" >> $$hdr; \ + $(ECHO) "#define VERSION_MICRO $(VERSION_MICRO)" >> $$hdr; \ + $(ECHO) "#endif" >> $$hdr; + +include: $(VERSION_HDR) $(CONFIGS) + @$(ECHO_INFO) "building in directory $@/ ..." + @$(MAKE) -C $@ + +src: $(VERSION_HDR) $(CONFIGS) include + @$(ECHO_INFO) "building in directory $@/ ..." + @$(MAKE) -C $@ + +tests: src include + @$(ECHO_INFO) "building in directory $@/ ..." + @$(MAKE) -C $@ + +tools: src include + @$(ECHO_INFO) "building in directory $@/ ..." + @$(MAKE) -C $@ + +install: $(SUBDIRS_BUILD) + @$(ECHO_INFO) "installing in $(INSTALL_PREFIX) ..." + $(INSTALL_PC_MACRO) libseccomp.pc + @for dir in $(SUBDIRS_INSTALL); do \ + $(ECHO_INFO) "installing from $$dir/"; \ + $(MAKE) -C $$dir install; \ + done + +check: tools tests + @$(ECHO_INFO) "checking in directory tests/ ..." + @$(MAKE) -C tests check + +check-syntax: + @./tools/check-syntax + +ctags: + @$(ECHO_INFO) "generating ctags for the project ..." + @ctags -R * + +cstags: + @$(ECHO_INFO) "generating cscope tags for the project ..." + @find -iname *.[ch] > cscope.files + @cscope -b -q -k + +clean: + @$(ECHO_INFO) "cleaning up libseccomp" + @for dir in $(SUBDIRS_BUILD); do \ + $(MAKE) -C $$dir clean; \ + done + +dist-clean: clean + @$(ECHO_INFO) "removing the configuration files" + @$(RM) $(CONFIGS) diff --git a/README b/README new file mode 100644 index 0000000..37b9709 --- /dev/null +++ b/README @@ -0,0 +1,48 @@ +libseccomp: An Enhanced Seccomp (mode 2) Helper Library +=============================================================================== +http://libseccomp.sf.net + +The libseccomp library provides and easy to use, platform independent, +interface to the Linux Kernel's syscall filtering mechanism: seccomp. The +libseccomp API is designed to abstract away the underlying BPF based syscall +filter language and present a more conventional function-call based filtering +interface that should be familiar to, and easily adopted by application +developers. + +* Documentation + +The "doc/" directory contains all of the documentation aside from the README +file (this file) and the LICENSE file which can be found in the top level +directory. + +* Building and Installing the Library + +In order to build the library you should follow the familiar three step +process used by most applications: + + # ./configure + # make [V=0|1] + # make install + +As usual, running "./configure -h" will display a list of build-time +configuration options. + +* Testing the Library + +There are a number of tests located in the "tests/" directory and a script +which can be used to help automate their execution, "regression". If you want +to run all of the tests you can simply run the script: + + # ./configure + # make + # cd tests + # ./regression + +However, the script takes a number of options to customize its execution; the +options can be displayed by running "./regression -h". + +* Other Useful Tools + +The "tools/" directory includes a number of tools which may be helpful in the +development of the library, or applications using the library, but for various +reasons are not installed by default. diff --git a/configure b/configure new file mode 100755 index 0000000..7c9f990 --- /dev/null +++ b/configure @@ -0,0 +1,277 @@ +#!/bin/bash + +# +# Enhanced Seccomp Library Configure Script +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# configuration defaults +opt_prefix="/usr/local" +opt_libdir="" +opt_sysinc_seccomp="yes" +opt_bindings_python="no" + +# output files +cnf_mk_file="configure.mk" +cnf_h_file="configure.h" + +#### +# functions + +function test_deps() { + [[ -z "$1" ]] && return 0 + which "$1" >& /dev/null && return 0 + return 1 +} + +function verify_deps() { + [[ -z "$1" ]] && return + if ! test_deps "$1"; then + echo "error: install \"$1\" and include it in your \$PATH" + exit 1 + fi +} + +function msg_usage() { + cat << EOF +Configure the enhanced seccomp library, libseccomp, for this system. + +Usage: + ./configure + +Options: +* general configuration + -h, --help display this help and exit +* installation configuration + --prefix=PREFIX installation base [/usr/local] + --libdir=DIR library directory [/usr/local/lib] +EOF +} + +function msg_summary() { + cat << EOF + CONFIGURATION SUMMARY + libseccomp version: ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO} + installation base: $opt_prefix + library directory: $opt_libdir + use system includes: $opt_sysinc_seccomp +EOF +} + +function msg_error() { + echo "error: $@" +} + +function cnf_mk_header() { + echo "# generated by configure on $(date -R)" >> $cnf_mk_file + echo "# options: \"$opt_str\"" >> $cnf_mk_file + echo "" >> $cnf_mk_file +} + +function cnf_mk_footer() { + echo "" >> $cnf_mk_file +} + +function cnf_mk_entry() { + [[ $# -ne 2 ]] && return + case "$2" in + no) + echo "$1 = 0" >> $cnf_mk_file + ;; + yes) + echo "$1 = 1" >> $cnf_mk_file + ;; + *) + echo "$1 = \"$2\"" >> $cnf_mk_file + esac +} + +function cnf_h_header() { + echo "/* generated by configure on $(date -R) */" >> $cnf_h_file + echo "/* options: \"$opt_str\" */" >> $cnf_h_file + echo "" >> $cnf_h_file + echo "#ifndef _CONFIGURE_H" >> $cnf_h_file + echo "#define _CONFIGURE_H" >> $cnf_h_file + echo "" >> $cnf_h_file +} + +function cnf_h_footer() { + echo "" >> $cnf_h_file + echo "#endif" >> $cnf_h_file + echo "" >> $cnf_h_file +} + +function cnf_h_entry() { + [[ $# -ne 2 ]] && return + case "$2" in + no) + echo "#undef $1" >> $cnf_h_file + ;; + yes) + echo "#define $1 1" >> $cnf_h_file + ;; + *) + echo "#define $1 $2" >> $cnf_h_file + esac +} + +function cnf_reset() { + cat /dev/null > $cnf_mk_file + cat /dev/null > $cnf_h_file +} + +function cnf_header() { + cnf_mk_header + cnf_h_header +} + +function cnf_entry() { + cnf_mk_entry "$1" "$2" + cnf_h_entry "$1" "$2" +} + +function cnf_footer() { + cnf_mk_footer + cnf_h_footer +} + +function tmpl_filter() { + name="echo \$$1" + val="$(eval $name)" + cat - | sed -e 's/%%'"$1"'%%/'"${val//\//\\/}"'/g;' +} + +#### +# main + +# +# setup +# + +# verify script dependencies +verify_deps getopt + +# parse the command line options +opt_str="$@" +opt=$(getopt -n "$0" --options "h" --longoptions "help,prefix:,libdir:" -- "$@") +eval set -- "$opt" +while [[ $# -gt 0 ]]; do + case "$1" in + --prefix) + opt_prefix="$2" + shift 2 + ;; + --libdir) + opt_libdir="$2" + shift 2 + ;; + -h|--help) + msg_usage + exit 0 + ;; + --) + shift + ;; + *) + msg_usage + exit 1 + esac +done + +# +# validate the command line options +# + +if [[ -e "$opt_prefix" && ! -d "$opt_prefix" ]]; then + msg_error "install prefix ($opt_prefix) is not a directory" + exit 1 +fi + +if [[ -z $opt_libdir ]]; then + opt_libdir="$opt_prefix/lib" +fi +if [[ -e "$opt_libdir" && ! -d "$opt_libdir" ]]; then + msg_error "libdir ($opt_libdir) is not a directory" + exit 1 +fi + +if [[ "$opt_bindings_python" = "yes" ]]; then + if ! test_deps cython; then + msg_error "python bindings require the cython package" + exit 1 + fi + cython_ver=$(cython -V 2>&1 | cut -d' ' -f 3) + if [[ $(echo $cython_ver | cut -d'.' -f 1) -lt 1 && + $(echo $cython_ver | cut -d'.' -f 2) -lt 16 ]]; then + msg_error "python bindings require cython 0.16 or higher" + exit 1 + fi +fi + +# +# automatic configuration +# + +# system seccomp includes +if [[ -r "/usr/include/linux/seccomp.h" ]]; then + opt_sysinc_seccomp="yes" +else + opt_sysinc_seccomp="no" +fi + +# generate the version files +. ./version_info +VERSION_RELEASE="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}" +rm -f ./version_info.mk +echo "# generated by configure on $(date -R)" >> ./version_info.mk +echo "VERSION_MAJOR=$VERSION_MAJOR" >> ./version_info.mk +echo "VERSION_MINOR=$VERSION_MINOR" >> ./version_info.mk +echo "VERSION_MICRO=$VERSION_MICRO" >> ./version_info.mk +echo "VERSION_RELEASE=$VERSION_RELEASE" >> ./version_info.mk + +# generate the pkg-config metadata +INSTALL_PREFIX="$opt_prefix" +INSTALL_LIBDIR="$opt_libdir" +rm -f ./libseccomp.pc +cat ./libseccomp.pc.in | \ + tmpl_filter INSTALL_PREFIX | \ + tmpl_filter INSTALL_LIBDIR | \ + tmpl_filter VERSION_RELEASE \ + >> ./libseccomp.pc + +# +# finish +# + +# reset the configuration files +cnf_reset +cnf_header + +# output the configuration files +cnf_mk_entry "CONF_INSTALL_PREFIX" "$opt_prefix" +cnf_mk_entry "CONF_INSTALL_LIBDIR" "$opt_libdir" +cnf_entry "CONF_SYSINC_SECCOMP" "$opt_sysinc_seccomp" +cnf_entry "CONF_BINDINGS_PYTHON" "$opt_bindings_python" + +# configuration footer +cnf_footer + +# display a summary and exit +msg_summary +exit 0 diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..2cef056 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,74 @@ +# +# Enhanced Seccomp Library Makefile +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# +# macros +# + +include ../macros.mk + +# +# configuration +# + +include $(TOPDIR)/version_info.mk +include $(TOPDIR)/configure.mk +include $(TOPDIR)/install.mk + +MAN1 = \ + man/man1/scmp_sys_resolver.1 + +MAN3 = \ + man/man3/seccomp_init.3 \ + man/man3/seccomp_load.3 \ + man/man3/seccomp_release.3 \ + man/man3/seccomp_reset.3 \ + man/man3/seccomp_rule_add.3 \ + man/man3/seccomp_rule_add_exact.3 \ + man/man3/seccomp_syscall_priority.3 \ + man/man3/seccomp_syscall_resolve_name.3 \ + man/man3/seccomp_syscall_resolve_name_arch.3 \ + man/man3/seccomp_syscall_resolve_num_arch.3 \ + man/man3/seccomp_export_bpf.3 \ + man/man3/seccomp_export_pfc.3 \ + man/man3/seccomp_attr_set.3 \ + man/man3/seccomp_attr_get.3 \ + man/man3/seccomp_arch_add.3 \ + man/man3/seccomp_arch_exist.3 \ + man/man3/seccomp_arch_native.3 \ + man/man3/seccomp_arch_remove.3 \ + man/man3/seccomp_merge.3 + +# +# targets +# + +.PHONY: all install install_man1 install_man3 + +all: + +install: install_man1 install_man3 + +install_man1: $(MAN1) + $(INSTALL_MAN1_MACRO) + +install_man3: $(MAN3) + $(INSTALL_MAN3_MACRO) diff --git a/doc/man/man1/scmp_sys_resolver.1 b/doc/man/man1/scmp_sys_resolver.1 new file mode 100644 index 0000000..fc28eaa --- /dev/null +++ b/doc/man/man1/scmp_sys_resolver.1 @@ -0,0 +1,60 @@ +.TH "scmp_sys_resolver" 1 "23 May 2013" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +scmp_sys_resolver \- Resolve system calls +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.B scmp_sys_resolver +[\-h] [\-a +.I ARCH +] [\-t] +.I SYSCALL_NAME +| +.I SYSCALL_NUMBER +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +This command resolves both system call names and numbers with respect to the +given architecture supplied in the optional +.I ARCH +argument. If the architecture is not supplied on the command line then the +native architecture is used. If the "\-t" argument is specified along with a +system call name, then the system call will be translated as necessary for the +given architecture. The "\-t" argument has no effect if a system call number +is specified. +.P +In some combinations of architecture and system call, a negative system call +number will be displayed. A negative system call number indicates that the +system call is not defined for the given architecture and is treated in a +special manner by libseccomp depending on the operation. +.TP +.B \-a \fIARCH +The architecture to use for resolving the system call. Valid +.I ARCH +values are "x86", "x86_64", "x32", and "arm". +.TP +.B \-t +If neccessary, translate the system call name to the proper system call number, +even if the system call name is different, e.g. socket(2) on x86. +.TP +.B \-h +A simple one-line usage display. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXIT STATUS +.\" ////////////////////////////////////////////////////////////////////////// +Returns zero on success, errno values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This tool, as well as +the libseccomp library, is currently under development, please report any bugs +at the project site or directly to the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore diff --git a/doc/man/man3/seccomp_arch_add.3 b/doc/man/man3/seccomp_arch_add.3 new file mode 100644 index 0000000..fd1da55 --- /dev/null +++ b/doc/man/man3/seccomp_arch_add.3 @@ -0,0 +1,125 @@ +.TH "seccomp_arch_add" 3 "26 November 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_arch_add, seccomp_arch_remove, seccomp_arch_exist, seccomp_arch_native \- Manage seccomp filter architectures +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.B #define SCMP_ARCH_NATIVE +.B #define SCMP_ARCH_X86 +.B #define SCMP_ARCH_X86_64 +.sp +.BI "uint32_t seccomp_arch_native();" +.BI "int seccomp_arch_exist(const scmp_filter_ctx " ctx ", uint32_t " arch_token ");" +.BI "int seccomp_arch_add(scmp_filter_ctx " ctx ", uint32_t " arch_token ");" +.BI "int seccomp_arch_remove(scmp_filter_ctx " ctx ", uint32_t " arch_token ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_arch_exist () +function tests to see if a given architecture has been added to the seccomp +filter in +.I ctx +, where the +.BR seccomp_arch_add () +and +.BR seccomp_arch_remove () +add and remove, respectively, architectures from the seccomp filter. In all +three functions, the architecture values given in +.I arch_token +should be the +.BR SCMP_ARCH_* +defined constants; with the +.BR SCMP_ARCH_NATIVE +constant always referring to the native compiled architecture. The +.BR seccomp_arch_native () +function returns the system's architecture such that it will match one of the +.BR SCMP_ARCH_* +constants. +.P +When a seccomp filter is initialized with the call to +.BR seccomp_init (3) +the native architecture is automatically added to the filter. If you want to +remove the native architecture from the filter, you first need to add another +architecture to the filter as a seccomp filter must contain at least one +architecture at all times. After you have added a second architecture to the +seccomp filter, you can remove the native architecture. +.P +When adding a new architecture to an existing filter, the existing rules will +not be added to the new architecture. However, rules added after adding the +new architecture will be added to all of the architectures in the filter. +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +The +.BR seccomp_arch_add () +and +.BR seccomp_arch_remove () +functions return zero on success, negative errno values on failure. The +.BR seccomp_arch_exist () +function returns zero if the architecture exists, \-EEXIST if it does not, and +other negative errno values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + if (seccomp_arch_exist(ctx, SCMP_ARCH_X86) == \-EEXIST) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X86); + if (rc != 0) + goto out_all; + rc = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE); + if (rc != 0) + goto out_all; + } + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_init (3), +.BR seccomp_reset (3), +.BR seccom_merge (3) diff --git a/doc/man/man3/seccomp_arch_exist.3 b/doc/man/man3/seccomp_arch_exist.3 new file mode 100644 index 0000000..f72602b --- /dev/null +++ b/doc/man/man3/seccomp_arch_exist.3 @@ -0,0 +1 @@ +.so man3/seccomp_arch_add.3 diff --git a/doc/man/man3/seccomp_arch_native.3 b/doc/man/man3/seccomp_arch_native.3 new file mode 100644 index 0000000..f72602b --- /dev/null +++ b/doc/man/man3/seccomp_arch_native.3 @@ -0,0 +1 @@ +.so man3/seccomp_arch_add.3 diff --git a/doc/man/man3/seccomp_arch_remove.3 b/doc/man/man3/seccomp_arch_remove.3 new file mode 100644 index 0000000..f72602b --- /dev/null +++ b/doc/man/man3/seccomp_arch_remove.3 @@ -0,0 +1 @@ +.so man3/seccomp_arch_add.3 diff --git a/doc/man/man3/seccomp_attr_get.3 b/doc/man/man3/seccomp_attr_get.3 new file mode 100644 index 0000000..c1e85be --- /dev/null +++ b/doc/man/man3/seccomp_attr_get.3 @@ -0,0 +1 @@ +.so man3/seccomp_attr_set.3 diff --git a/doc/man/man3/seccomp_attr_set.3 b/doc/man/man3/seccomp_attr_set.3 new file mode 100644 index 0000000..9a58cec --- /dev/null +++ b/doc/man/man3/seccomp_attr_set.3 @@ -0,0 +1,121 @@ +.TH "seccomp_attr_set" 3 "25 July 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_attr_set, seccomp_attr_get \- Manage the seccomp filter attributes +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.B enum scmp_filter_attr; +.sp +.BI "int seccomp_attr_set(scmp_filter_ctx " ctx "," +.BI " enum scmp_filter_attr " attr ", uint32_t " value ");" +.BI "int seccomp_attr_get(scmp_filter_ctx " ctx "," +.BI " enum scmp_filter_attr " attr ", uint32_t *" value ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_attr_set () +function sets the different seccomp filter attributes while the +.BR seccomp_attr_get () +function fetches the filter attributes. The seccomp filter attributes are +tunable values that affect how the library behaves when generating and loading +the seccomp filter into the kernel. The attributes are reset to their default +values whenever the filter is initialized or reset via +.BR seccomp_filter_init (3) +or +.BR seccomp_filter_reset (3). +.P +The filter context +.I ctx +is the value returned by the call to +.BR seccomp_init (3). +.P +Valid +.I attr +values are as follows: +.TP +.B SCMP_FLTATR_ACT_DEFAULT +The default filter action as specified in the call to +.BR seccomp_filter_init (3) +or +.BR seccomp_filter_reset (3). +This attribute is read-only. +.TP +.B SCMP_FLTATR_ACT_BADARCH +The filter action taken when the loaded filter does not match the architecture +of the executing application. Defaults to the +.B SCMP_ACT_KILL +action. +.TP +.B SCMP_FLTATR_CTL_NNP +A flag to specify if the NO_NEW_PRIVS functionality should be enabled before +loading the seccomp filter into the kernel. If set to off ( +.I value +== 0) then loading the seccomp filter into the kernel will fail if CAP_SYS_ADMIN +is not set. Defaults to on ( +.I value +== 1). +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +Returns zero on success, negative errno values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + goto out; + + /* ... */ + + rc = seccomp_attr_set(ctx, SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_TRAP); + if (rc < 0) + goto out; + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_init (3), +.BR seccomp_reset (3), +.BR seccomp_load (3) diff --git a/doc/man/man3/seccomp_export_bpf.3 b/doc/man/man3/seccomp_export_bpf.3 new file mode 100644 index 0000000..0d18638 --- /dev/null +++ b/doc/man/man3/seccomp_export_bpf.3 @@ -0,0 +1,108 @@ +.TH "seccomp_export_bpf" 3 "25 July 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_export_bpf, seccomp_export_pfc \- Export the seccomp filter +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.BI "int seccomp_export_bpf(const scmp_filter_ctx " ctx ", int " fd ");" +.BI "int seccomp_export_pfc(const scmp_filter_ctx " ctx ", int " fd ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_export_bpf () +and +.BR seccomp_export_pfc () +functions generate and output the current seccomp filter in either BPF (Berkley +Packet Filter) or PFC (Pseudo Filter Code). The output of +.BR seccomp_export_bpf () +is suitable for loading into the kernel, while the output of +.BR seccomp_export_pfc () +is human readable and is intended primarily as a debugging tool for developers +using libseccomp. Both functions write the filter to the +.I fd +file descriptor. +.P +The filter context +.I ctx +is the value returned by the call to +.BR seccomp_init (3). +.P +While the two output formats are guaranteed to be functionally equivalent for +the given seccomp filter configuration, the filter instructions, and their +ordering, are not guaranteed to be the same in both the BPF and PFC formats. +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +Returns zero on success, negative errno values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + int filter_fd; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* ... */ + + filter_fd = open("/tmp/seccomp_filter.bpf", O_WRONLY); + if (filter_fd == \-1) { + rc = \-errno; + goto out; + } + + rc = seccomp_export_bpf(ctx, filter_fd); + if (rc < 0) { + close(filter_fd); + goto out; + } + close(filter_fd); + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_init (3), +.BR seccomp_release (3) + diff --git a/doc/man/man3/seccomp_export_pfc.3 b/doc/man/man3/seccomp_export_pfc.3 new file mode 100644 index 0000000..45c49a3 --- /dev/null +++ b/doc/man/man3/seccomp_export_pfc.3 @@ -0,0 +1 @@ +.so man3/seccomp_export_bpf.3 diff --git a/doc/man/man3/seccomp_init.3 b/doc/man/man3/seccomp_init.3 new file mode 100644 index 0000000..6c79d41 --- /dev/null +++ b/doc/man/man3/seccomp_init.3 @@ -0,0 +1,136 @@ +.TH "seccomp_init" 3 "25 July 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_init, seccomp_reset \- Initialize the seccomp filter state +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.BI "scmp_filter_ctx seccomp_init(uint32_t " def_action ");" +.BI "int seccomp_reset(scmp_filter_ctx " ctx ", uint32_t " def_action ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_init () +and +.BR seccomp_reset () +functions (re)initialize the internal seccomp filter state, prepares it for +use, and sets the default action based on the +.I def_action +parameter. The +.BR seccomp_init () +function must be called before any other libseccomp functions as the rest +of the library API will fail if the filter context is not initialized properly. +The +.BR seccomp_reset () +function releases the existing filter context state before reinitializing it +and can only be called after a call to +.BR seccomp_init () +has succeeded. +.P +When the caller is finished configuring the seccomp filter and has loaded it +into the kernel, the caller should call +.BR seccomp_release (3) +to release all of the filter context state. +.P +Valid +.I def_action +values are as follows: +.TP +.B SCMP_ACT_KILL +The process will be killed by the kernel when it calls a syscall that does not +match any of the configured seccomp filter rules. +.TP +.B SCMP_ACT_TRAP +The process will throw a SIGSYS signal when it calls a syscall that does not +match any of the configured seccomp filter rules. +.TP +.B SCMP_ACT_ERRNO(uint16_t errno) +The process will receive a return value of +.I errno +when it calls a syscall that does not match any of the configured seccomp filter +rules. +.TP +.B SCMP_ACT_TRACE(uint16_t msg_num) +If the process is being traced and the tracing process specified the +.B PTRACE_O_TRACESECCOMP +option in the call to +.BR ptrace (2), +the tracing process will be notified, via +.B PTRACE_EVENT_SECCOMP +, and the value provided in +.I msg_num +can be retrieved using the +.B PTRACE_GETEVENTMSG +option. +.TP +.B SCMP_ACT_ALLOW +The seccomp filter will have no effect on the process calling the syscall if it +does not match any of the configured seccomp filter rules. +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +The +.BR seccomp_init () +function returns a filter context on success, NULL on failure. The +.BR seccomp_reset () +function returns zero on success, negative errno values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* ... */ + + rc = seccomp_reset(ctx, SCMP_ACT_KILL); + if (rc < 0) + goto out; + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_release (3) + diff --git a/doc/man/man3/seccomp_load.3 b/doc/man/man3/seccomp_load.3 new file mode 100644 index 0000000..87e0766 --- /dev/null +++ b/doc/man/man3/seccomp_load.3 @@ -0,0 +1,83 @@ +.TH "seccomp_load" 3 "25 July 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_load \- Load the current seccomp filter into the kernel +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.BI "int seccomp_load(scmp_filter_ctx " ctx ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +Loads the seccomp filter provided by +.I ctx +into the kernel; if the function +succeeds the new seccomp filter will be active when the function returns. +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +Returns zero on success, negative errno values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* ... */ + + rc = seccomp_load(ctx); + if (rc < 0) + goto out; + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_init (3), +.BR seccomp_reset (3), +.BR seccomp_release (3), +.BR seccomp_rule_add (3), +.BR seccomp_rule_add_exact (3) + + diff --git a/doc/man/man3/seccomp_merge.3 b/doc/man/man3/seccomp_merge.3 new file mode 100644 index 0000000..3a00bcd --- /dev/null +++ b/doc/man/man3/seccomp_merge.3 @@ -0,0 +1,122 @@ +.TH "seccomp_merge" 3 "28 September 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_merge \- Merge two seccomp filters +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.BI "int seccomp_merge(scmp_filter_ctx " dst ", scmp_filter_ctx " src ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_merge () +function merges the seccomp filter in +.I src +with the filter in +.I dst +and stores the resulting in the +.I dst +filter. If successfull, the +.I src +seccomp filter is released and all internal memory assocated with the filter +is freed; there is no need to call +.BR seccomp_release (3) +on +.I src +and the caller should discard any references to the filter. +.P +In order to merge two seccomp filters, both filters must have the same +attribute values and no overlapping architectures. +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +Returns zero on success and negative values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx_32, ctx_64; + + ctx_32 = seccomp_init(SCMP_ACT_KILL); + if (ctx_32 == NULL) + goto out_all; + ctx_64 = seccomp_init(SCMP_ACT_KILL); + if (ctx_64 == NULL) + goto out_all; + + if (seccomp_arch_exist(ctx_32, SCMP_ARCH_X86) == \-EEXIST) { + rc = seccomp_arch_add(ctx_32, SCMP_ARCH_X86); + if (rc != 0) + goto out_all; + rc = seccomp_arch_remove(ctx_32, SCMP_ARCH_NATIVE); + if (rc != 0) + goto out_all; + } + if (seccomp_arch_exist(ctx_64, SCMP_ARCH_X86_64) == \-EEXIST) { + rc = seccomp_arch_add(ctx_64, SCMP_ARCH_X86_64); + if (rc != 0) + goto out_all; + rc = seccomp_arch_remove(ctx_64, SCMP_ARCH_NATIVE); + if (rc != 0) + goto out_all; + } + + /* ... */ + + rc = seccomp_merge(ctx_64, ctx_32); + if (rc != 0) + goto out_all; + + /* NOTE: the 'ctx_32' filter is no longer valid at this point */ + + /* ... */ + +out: + seccomp_release(ctx_64); + return \-rc; +out_all: + seccomp_release(ctx_32); + goto out; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_init (3), +.BR seccomp_reset (3), +.BR seccomp_arch_add (3), +.BR seccomp_arch_remove (3), +.BR seccomp_attr_get (3), +.BR seccomp_attr_set (3) diff --git a/doc/man/man3/seccomp_release.3 b/doc/man/man3/seccomp_release.3 new file mode 100644 index 0000000..8a61c9c --- /dev/null +++ b/doc/man/man3/seccomp_release.3 @@ -0,0 +1,77 @@ +.TH "seccomp_release" 3 "25 July 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_release \- Release the seccomp filter state +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.BI "void seccomp_release(scmp_filter_ctx " ctx ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +Releases the seccomp filter in +.I ctx +which was first initialized by +.BR seccomp_init (3) +or +.BR seccomp_reset (3) +and frees any memory associated with the given seccomp filter context. +Any seccomp filters loaded into the kernel are not affected. +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +Does not return a value. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + return \-1; + + /* ... */ + + seccomp_release(ctx); + return 0; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_init (3), +.BR seccomp_reset (3) + + diff --git a/doc/man/man3/seccomp_reset.3 b/doc/man/man3/seccomp_reset.3 new file mode 100644 index 0000000..6f551cd --- /dev/null +++ b/doc/man/man3/seccomp_reset.3 @@ -0,0 +1 @@ +.so man3/seccomp_init.3 diff --git a/doc/man/man3/seccomp_rule_add.3 b/doc/man/man3/seccomp_rule_add.3 new file mode 100644 index 0000000..98878fb --- /dev/null +++ b/doc/man/man3/seccomp_rule_add.3 @@ -0,0 +1,295 @@ +.TH "seccomp_rule_add" 3 "25 July 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_rule_add, seccomp_rule_add_exact \- Add a seccomp filter rule +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.BI "int SCMP_SYS(" syscall_name ");" +.sp +.BI "struct scmp_arg_cmp SCMP_CMP(unsigned int " arg "," +.BI " enum scmp_compare " op ", " ... ");" +.BI "struct scmp_arg_cmp SCMP_A0(enum scmp_compare " op ", " ... ");" +.BI "struct scmp_arg_cmp SCMP_A1(enum scmp_compare " op ", " ... ");" +.BI "struct scmp_arg_cmp SCMP_A2(enum scmp_compare " op ", " ... ");" +.BI "struct scmp_arg_cmp SCMP_A3(enum scmp_compare " op ", " ... ");" +.BI "struct scmp_arg_cmp SCMP_A4(enum scmp_compare " op ", " ... ");" +.BI "struct scmp_arg_cmp SCMP_A5(enum scmp_compare " op ", " ... ");" +.sp +.BI "int seccomp_rule_add(scmp_filter_ctx " ctx ", uint32_t " action "," +.BI " int " syscall ", unsigned int " arg_cnt ", " ... ");" +.BI "int seccomp_rule_add_exact(scmp_filter_ctx " ctx ", uint32_t " action "," +.BI " int " syscall ", unsigned int " arg_cnt ", " ... ");" +.sp +.BI "int seccomp_rule_add_array(scmp_filter_ctx " ctx "," +.BI " uint32_t " action ", int " syscall "," +.BI " unsigned int " arg_cnt "," +.BI " const struct scmp_arg_cmp *"arg_array ");" +.BI "int seccomp_rule_add_exact_array(scmp_filter_ctx " ctx "," +.BI " uint32_t " action ", int " syscall "," +.BI " unsigned int " arg_cnt "," +.BI " const struct scmp_arg_cmp *"arg_array ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_rule_add (), +.BR seccomp_rule_add_array (), +.BR seccomp_rule_add_exact (), +and +.BR seccomp_rule_add_exact_array () +functions all add a new filter rule to the current seccomp filter. The +.BR seccomp_rule_add () +and +.BR seccomp_rule_add_array () +functions will make a "best effort" to add the rule as specified, but may alter +the rule slightly due to architecture specifics, e.g. socket and ipc functions +on x86. The +.BR seccomp_rule_add_exact () +and +.BR seccomp_rule_add_exact_array () +functions will attempt to add the rule exactly as specified so it may behave +differently on different architectures. While it does not guarantee a exact +filter ruleset, +.BR seccomp_rule_add () +and +.BR seccomp_rule_add_array () +do guarantee the same behavior regardless of the architecture. +.P +The newly added filter rule does not take effect until the entire filter is +loaded into the kernel using +.BR seccomp_load (3). +.P +The +.BR SCMP_CMP () +and +.BR SCMP_A{0-5} () +macros generate a scmp_arg_cmp structure for use with the above functions. The +.BR SCMP_CMP () +macro allows the caller to specify an arbitrary argument along with the +comparison operator, mask, and datum values where the +.BR SCMP_A{0-5} () +macros are specific to a certain argument. See the EXAMPLES section below. +.P +While it is possible to specify the +.I syscall +value directly using the standard +.B __NR_syscall +values, in order to ensure proper operation across multiple architectures it +is highly recommended to use the +.BR SCMP_SYS () +macro instead. See the EXAMPLES section below. +.P +The filter context +.I ctx +is the value returned by the call to +.BR seccomp_init (3). +.P +Valid +.I action +values are as follows: +.TP +.B SCMP_ACT_KILL +The process will be killed by the kernel when it calls a syscall that does not +match any of the configured seccomp filter rules. +.TP +.B SCMP_ACT_TRAP +The process will throw a SIGSYS signal when it calls a syscall that does not +match any of the configured seccomp filter rules. +.TP +.B SCMP_ACT_ERRNO(uint16_t errno) +The process will receive a return value of +.I errno +when it calls a syscall that does not match any of the configured seccomp filter +rules. +.TP +.B SCMP_ACT_TRACE(uint16_t msg_num) +If the process is being traced and the tracing process specified the +.B PTRACE_O_TRACESECCOMP +option in the call to +.BR ptrace (2), +the tracing process will be notified, via +.B PTRACE_EVENT_SECCOMP +, and the value provided in +.I msg_num +can be retrieved using the +.B PTRACE_GETEVENTMSG +option. +.TP +.B SCMP_ACT_ALLOW +The seccomp filter will have no effect on the process calling the syscall if it +does not match any of the configured seccomp filter rules. +.P +Valid comparison +.I op +values are as follows: +.TP +.B SCMP_CMP_NE +Matches when the argument value is not equal to the datum value, example: +.sp +SCMP_CMP( +.I arg +, SCMP_CMP_NE , +.I datum +) +.TP +.B SCMP_CMP_LT +Matches when the argument value is less than the datum value, example: +.sp +SCMP_CMP( +.I arg +, SCMP_CMP_LT , +.I datum +) +.TP +.B SCMP_CMP_LE +Matches when the argument value is less than or equal to the datum value, +example: +.sp +SCMP_CMP( +.I arg +, SCMP_CMP_LE , +.I datum +) +.TP +.B SCMP_CMP_EQ +Matches when the argument value is equal to the datum value, example: +.sp +SCMP_CMP( +.I arg +, SCMP_CMP_EQ , +.I datum +) +.TP +.B SCMP_CMP_GE +Matches when the argument value is greater than or equal to the datum value, +example: +.sp +SCMP_CMP( +.I arg +, SCMP_CMP_GE , +.I datum +) +.TP +.B SCMP_CMP_GT +Matches when the argument value is greater than the datum value, example: +.sp +SCMP_CMP( +.I arg +, SCMP_CMP_GT , +.I datum +) +.TP +.B SCMP_CMP_MASKED_EQ +Matches when the masked argument value is equal to the masked datum value, +example: +.sp +SCMP_CMP( +.I arg +, SCMP_CMP_MASKED_EQ , +.I mask +, +.I datum +) +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +The +.BR seccomp_rule_add (), +.BR seccomp_rule_add_array (), +.BR seccomp_rule_add_exact (), +and +.BR seccomp_rule_add_exact_array () +functions return zero on success, negative errno values on failure. +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include +#include +#include +#include + +#define BUF_SIZE 256 + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + struct scmp_arg_cmp arg_cmp[] = { SCMP_A0(SCMP_CMP_EQ, 2) }; + int fd; + unsigned char buf[BUF_SIZE]; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* ... */ + + fd = open("file.txt", 0); + + /* ... */ + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc < 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 3, + SCMP_A0(SCMP_CMP_EQ, fd), + SCMP_A1(SCMP_CMP_EQ, (scmp_datum_t)buf), + SCMP_A2(SCMP_CMP_LE, BUF_SIZE)); + if (rc < 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_CMP(0, SCMP_CMP_EQ, fd)); + if (rc < 0) + goto out; + + rc = seccomp_rule_add_array(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + arg_cmp); + if (rc < 0) + goto out; + + rc = seccomp_load(ctx); + if (rc < 0) + goto out; + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_syscall_priority (3), +.BR seccomp_load (3) diff --git a/doc/man/man3/seccomp_rule_add_array.3 b/doc/man/man3/seccomp_rule_add_array.3 new file mode 100644 index 0000000..53714e7 --- /dev/null +++ b/doc/man/man3/seccomp_rule_add_array.3 @@ -0,0 +1 @@ +.so man3/seccomp_rule_add.3 diff --git a/doc/man/man3/seccomp_rule_add_exact.3 b/doc/man/man3/seccomp_rule_add_exact.3 new file mode 100644 index 0000000..53714e7 --- /dev/null +++ b/doc/man/man3/seccomp_rule_add_exact.3 @@ -0,0 +1 @@ +.so man3/seccomp_rule_add.3 diff --git a/doc/man/man3/seccomp_rule_add_exact_array.3 b/doc/man/man3/seccomp_rule_add_exact_array.3 new file mode 100644 index 0000000..53714e7 --- /dev/null +++ b/doc/man/man3/seccomp_rule_add_exact_array.3 @@ -0,0 +1 @@ +.so man3/seccomp_rule_add.3 diff --git a/doc/man/man3/seccomp_syscall_priority.3 b/doc/man/man3/seccomp_syscall_priority.3 new file mode 100644 index 0000000..7cffde8 --- /dev/null +++ b/doc/man/man3/seccomp_syscall_priority.3 @@ -0,0 +1,111 @@ +.TH "seccomp_syscall_priority" 3 "25 July 2012" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_syscall_priority \- Prioritize syscalls in the seccomp filter +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.B typedef void * scmp_filter_ctx; +.sp +.BI "int SCMP_SYS(" syscall_name ");" +.sp +.BI "int seccomp_syscall_priority(scmp_filter_ctx " ctx "," +.BI " int " syscall ", uint8_t " priority ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_syscall_priority () +function provides a priority hint to the seccomp filter generator in libseccomp +such that higher priority syscalls are placed earlier in the seccomp filter code +so that they incur less overhead at the expense of lower priority syscalls. A +syscall's priority can be set regardless of if any rules currently exist for +that syscall; the library will remember the priority and it will be assigned to +the syscall if and when a rule for that syscall is created. +.P +While it is possible to specify the +.I syscall +value directly using the standard +.B __NR_syscall +values, in order to ensure proper operation across multiple architectures it +is highly recommended to use the +.BR SCMP_SYS () +macro instead. See the EXAMPLES section below. +.P +The +.I priority +parameter takes an 8-bit value ranging from 0 \- 255; a higher value represents +a higher priority. +.P +The filter context +.I ctx +is the value returned by the call to +.BR seccomp_init (). +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +The +.BR seccomp_syscall_priority () +function returns zero on success, negative errno values on failure. The +.BR SCMP_SYS () +macro returns a value suitable for use as the +.I syscall +value in +.BR seccomp_syscall_priority (). +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* ... */ + + rc = seccomp_syscall_priority(ctx, SCMP_SYS(read), 200); + if (rc < 0) + goto out; + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_rule_add (3), +.BR seccomp_rule_add_exact (3) diff --git a/doc/man/man3/seccomp_syscall_resolve_name.3 b/doc/man/man3/seccomp_syscall_resolve_name.3 new file mode 100644 index 0000000..0e78b55 --- /dev/null +++ b/doc/man/man3/seccomp_syscall_resolve_name.3 @@ -0,0 +1,113 @@ +.TH "seccomp_syscall_resolve_name" 3 "7 January 2013" "paul@paul-moore.com" "libseccomp Documentation" +.\" ////////////////////////////////////////////////////////////////////////// +.SH NAME +.\" ////////////////////////////////////////////////////////////////////////// +seccomp_syscall_resolve_name \- Resolve a syscall name +.\" ////////////////////////////////////////////////////////////////////////// +.SH SYNOPSIS +.\" ////////////////////////////////////////////////////////////////////////// +.nf +.B #include +.sp +.BI "int seccomp_syscall_resolve_name(const char *" name ");" +.BI "int seccomp_syscall_resolve_name_arch(uint32_t " arch_token "," +.BI " const char *" name ");" +.BI "char *seccomp_syscall_resolve_num_arch(uint32_t " arch_token ", int " num ");" +.sp +Link with \fI\-lseccomp\fP. +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH DESCRIPTION +.\" ////////////////////////////////////////////////////////////////////////// +.P +The +.BR seccomp_syscall_resolve_name () +and +.BR seccomp_syscall_resolve_name_arch() +functions resolve the commonly used syscall name to the syscall number used by +the kernel and the rest of the libseccomp API. The +.BR seccomp_syscall_resolve_num_arch() +function resolves the syscall number used by the kernel to the commonly used +syscall name. +.P +The caller is responsible for freeing the returned string from +.BR seccomp_syscall_resolve_num_arch() . +.\" ////////////////////////////////////////////////////////////////////////// +.SH RETURN VALUE +.\" ////////////////////////////////////////////////////////////////////////// +.P +In the case of +.BR seccomp_syscall_resolve_name () +and +.BR seccomp_syscall_resolve_name_arch() +the associated syscall number is returned, with the negative pseudo syscall +number being returned in cases where the given syscall does not exist for the +architeture. The value +.BR __NR_SCMP_ERROR +is returned in case of error. In all cases, the return value is suitable for +use in any libseccomp API function which requires the syscall number, examples include +.BR seccomp_rule_add () +and +.BR seccomp_rule_add_exact (). +.P +In the case of +.BR seccomp_syscall_resolve_num_arch() +the associated syscall name is returned and it remains the callers +responsibility to free the returned string via +.BR free (3). +.\" ////////////////////////////////////////////////////////////////////////// +.SH EXAMPLES +.\" ////////////////////////////////////////////////////////////////////////// +.nf +#include + +int main(int argc, char *argv[]) +{ + int rc = \-1; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* ... */ + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, + seccomp_syscall_resolve_name("open"), 0); + if (rc < 0) + goto out; + + /* ... */ + + rc = seccomp_load(ctx); + if (rc < 0) + goto out; + + /* ... */ + +out: + seccomp_release(ctx); + return \-rc; +} +.fi +.\" ////////////////////////////////////////////////////////////////////////// +.SH NOTES +.\" ////////////////////////////////////////////////////////////////////////// +.P +While the seccomp filter can be generated independent of the kernel, kernel +support is required to load and enforce the seccomp filter generated by +libseccomp. +.P +The libseccomp project site, with more information and the source code +repository, can be found at http://libseccomp.sf.net. This library is currently +under development, please report any bugs at the project site or directly to +the author. +.\" ////////////////////////////////////////////////////////////////////////// +.SH AUTHOR +.\" ////////////////////////////////////////////////////////////////////////// +Paul Moore +.\" ////////////////////////////////////////////////////////////////////////// +.SH SEE ALSO +.\" ////////////////////////////////////////////////////////////////////////// +.BR seccomp_rule_add (3), +.BR seccomp_rule_add_exact (3) diff --git a/doc/man/man3/seccomp_syscall_resolve_name_arch.3 b/doc/man/man3/seccomp_syscall_resolve_name_arch.3 new file mode 100644 index 0000000..f6d4472 --- /dev/null +++ b/doc/man/man3/seccomp_syscall_resolve_name_arch.3 @@ -0,0 +1 @@ +.so man3/seccomp_syscall_resolve_name.3 diff --git a/doc/man/man3/seccomp_syscall_resolve_num_arch.3 b/doc/man/man3/seccomp_syscall_resolve_num_arch.3 new file mode 100644 index 0000000..f6d4472 --- /dev/null +++ b/doc/man/man3/seccomp_syscall_resolve_num_arch.3 @@ -0,0 +1 @@ +.so man3/seccomp_syscall_resolve_name.3 diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 0000000..aba3f71 --- /dev/null +++ b/include/Makefile @@ -0,0 +1,57 @@ +# +# Enhanced Seccomp Library Makefile +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# +# macros +# + +include ../macros.mk + +# +# configuration +# + +include $(TOPDIR)/version_info.mk +include $(TOPDIR)/configure.mk +include $(TOPDIR)/install.mk + +HDR_BUILD = seccomp.h + +# +# targets +# + +.PHONY: all install clean + +all: $(HDR_BUILD) + +install: $(HDR_BUILD) + $(INSTALL_INC_MACRO) + +seccomp.h: seccomp.h.in + @$(ECHO) " GEN $@" + $(CAT) $< | \ + $(SED) -e 's/%%VERSION_MAJOR%%/$(VERSION_MAJOR)/g' | \ + $(SED) -e 's/%%VERSION_MINOR%%/$(VERSION_MINOR)/g' | \ + $(SED) -e 's/%%VERSION_MICRO%%/$(VERSION_MICRO)/g' > $@ + +clean: + @$(RM) $(HDR_BUILD) diff --git a/include/seccomp.h.in b/include/seccomp.h.in new file mode 100644 index 0000000..e150fbd --- /dev/null +++ b/include/seccomp.h.in @@ -0,0 +1,1164 @@ +/** + * Seccomp Library + * + * Copyright (c) 2012,2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _SECCOMP_H +#define _SECCOMP_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * version information + */ + +#define SCMP_VER_MAJOR %%VERSION_MAJOR%% +#define SCMP_VER_MINOR %%VERSION_MINOR%% +#define SCMP_VER_MICRO %%VERSION_MICRO%% + +/* + * types + */ + +/** + * Filter context/handle + */ +typedef void *scmp_filter_ctx; + +/** + * Filter attributes + */ +enum scmp_filter_attr { + _SCMP_FLTATR_MIN = 0, + SCMP_FLTATR_ACT_DEFAULT = 1, /**< default filter action */ + SCMP_FLTATR_ACT_BADARCH = 2, /**< bad architecture action */ + SCMP_FLTATR_CTL_NNP = 3, /**< set NO_NEW_PRIVS on filter load */ + _SCMP_FLTATR_MAX, +}; + +/** + * Comparison operators + */ +enum scmp_compare { + _SCMP_CMP_MIN = 0, + SCMP_CMP_NE = 1, /**< not equal */ + SCMP_CMP_LT = 2, /**< less than */ + SCMP_CMP_LE = 3, /**< less than or equal */ + SCMP_CMP_EQ = 4, /**< equal */ + SCMP_CMP_GE = 5, /**< greater than or equal */ + SCMP_CMP_GT = 6, /**< greater than */ + SCMP_CMP_MASKED_EQ = 7, /**< masked equality */ + _SCMP_CMP_MAX, +}; + +/** + * Argument datum + */ +typedef uint64_t scmp_datum_t; + +/** + * Argument / Value comparison definition + */ +struct scmp_arg_cmp { + unsigned int arg; /**< argument number, starting at 0 */ + enum scmp_compare op; /**< the comparison op, e.g. SCMP_CMP_* */ + scmp_datum_t datum_a; + scmp_datum_t datum_b; +}; + +/* + * macros/defines + */ + +/** + * The native architecture token + */ +#define SCMP_ARCH_NATIVE 0 + +/** + * The x86 (32-bit) architecture token + */ +#define SCMP_ARCH_X86 AUDIT_ARCH_I386 + +/** + * The x86-64 (64-bit) architecture token + */ +#define SCMP_ARCH_X86_64 AUDIT_ARCH_X86_64 + +/** + * The x32 (32-bit x86_64) architecture token + * + * NOTE: this is different from the value used by the kernel because we need to + * be able to distinguish between x32 and x86_64 + */ +#define SCMP_ARCH_X32 (EM_X86_64|__AUDIT_ARCH_LE) + +/** + * The ARM architecture token + */ +#define SCMP_ARCH_ARM AUDIT_ARCH_ARM + +/** + * Convert a syscall name into the associated syscall number + * @param x the syscall name + */ +#define SCMP_SYS(x) (__NR_##x) + +/** + * Specify an argument comparison struct for use in declaring rules + * @param arg the argument number, starting at 0 + * @param op the comparison operator, e.g. SCMP_CMP_* + * @param datum_a dependent on comparison + * @param datum_b dependent on comparison, optional + */ +#define SCMP_CMP(...) ((struct scmp_arg_cmp){__VA_ARGS__}) + +/** + * Specify an argument comparison struct for argument 0 + */ +#define SCMP_A0(...) SCMP_CMP(0, __VA_ARGS__) + +/** + * Specify an argument comparison struct for argument 1 + */ +#define SCMP_A1(...) SCMP_CMP(1, __VA_ARGS__) + +/** + * Specify an argument comparison struct for argument 2 + */ +#define SCMP_A2(...) SCMP_CMP(2, __VA_ARGS__) + +/** + * Specify an argument comparison struct for argument 3 + */ +#define SCMP_A3(...) SCMP_CMP(3, __VA_ARGS__) + +/** + * Specify an argument comparison struct for argument 4 + */ +#define SCMP_A4(...) SCMP_CMP(4, __VA_ARGS__) + +/** + * Specify an argument comparison struct for argument 5 + */ +#define SCMP_A5(...) SCMP_CMP(5, __VA_ARGS__) + +/* + * seccomp actions + */ + +/** + * Kill the process + */ +#define SCMP_ACT_KILL 0x00000000U +/** + * Throw a SIGSYS signal + */ +#define SCMP_ACT_TRAP 0x00030000U +/** + * Return the specified error code + */ +#define SCMP_ACT_ERRNO(x) (0x00050000U | ((x) & 0x0000ffffU)) +/** + * Notify a tracing process with the specified value + */ +#define SCMP_ACT_TRACE(x) (0x7ff00000U | ((x) & 0x0000ffffU)) +/** + * Allow the syscall to be executed + */ +#define SCMP_ACT_ALLOW 0x7fff0000U + +/* + * functions + */ + +/** + * Initialize the filter state + * @param def_action the default filter action + * + * This function initializes the internal seccomp filter state and should + * be called before any other functions in this library to ensure the filter + * state is initialized. Returns a filter context on success, NULL on failure. + * + */ +scmp_filter_ctx seccomp_init(uint32_t def_action); + +/** + * Reset the filter state + * @param ctx the filter context + * @param def_action the default filter action + * + * This function resets the given seccomp filter state and ensures the + * filter state is reinitialized. This function does not reset any seccomp + * filters already loaded into the kernel. Returns zero on success, negative + * values on failure. + * + */ +int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action); + +/** + * Destroys the filter state and releases any resources + * @param ctx the filter context + * + * This functions destroys the given seccomp filter state and releases any + * resources, including memory, associated with the filter state. This + * function does not reset any seccomp filters already loaded into the kernel. + * The filter context can no longer be used after calling this function. + * + */ +void seccomp_release(scmp_filter_ctx ctx); + +/** + * Merge two filters + * @param ctx_dst the destination filter context + * @param ctx_src the source filter context + * + * This function merges two filter contexts into a single filter context and + * destroys the second filter context. The two filter contexts must have the + * same attribute values and not contain any of the same architectures; if they + * do, the merge operation will fail. On success, the source filter context + * will be destroyed and should no longer be used; it is not necessary to + * call seccomp_release() on the source filter context. Returns zero on + * success, negative values on failure. + * + */ +int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src); + +/** + * Return the native architecture token + * + * This function returns the native architecture token value, e.g. SCMP_ARCH_*. + * + */ +uint32_t seccomp_arch_native(void); + +/** + * Check to see if an existing architecture is present in the filter + * @param ctx the filter context + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * + * This function tests to see if a given architecture is included in the filter + * context. If the architecture token is SCMP_ARCH_NATIVE then the native + * architecture will be assumed. Returns zero if the architecture exists in + * the filter, -EEXIST if it is not present, and other negative values on + * failure. + * + */ +int seccomp_arch_exist(const scmp_filter_ctx ctx, uint32_t arch_token); + +/** + * Adds an architecture to the filter + * @param ctx the filter context + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * + * This function adds a new architecture to the given seccomp filter context. + * Any new rules added after this function successfully returns will be added + * to this architecture but existing rules will not be added to this + * architecture. If the architecture token is SCMP_ARCH_NATIVE then the native + * architecture will be assumed. Returns zero on success, negative values on + * failure. + * + */ +int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token); + +/** + * Removes an architecture from the filter + * @param ctx the filter context + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * + * This function removes an architecture from the given seccomp filter context. + * If the architecture token is SCMP_ARCH_NATIVE then the native architecture + * will be assumed. Returns zero on success, negative values on failure. + * + */ +int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token); + +/** + * Loads the filter into the kernel + * @param ctx the filter context + * + * This function loads the given seccomp filter context into the kernel. If + * the filter was loaded correctly, the kernel will be enforcing the filter + * when this function returns. Returns zero on success, negative values on + * error. + * + */ +int seccomp_load(const scmp_filter_ctx ctx); + +/** + * Get the value of a filter attribute + * @param ctx the filter context + * @param attr the filter attribute name + * @param value the filter attribute value + * + * This function fetches the value of the given attribute name and returns it + * via @value. Returns zero on success, negative values on failure. + * + */ +int seccomp_attr_get(const scmp_filter_ctx ctx, + enum scmp_filter_attr attr, uint32_t *value); + +/** + * Set the value of a filter attribute + * @param ctx the filter context + * @param attr the filter attribute name + * @param value the filter attribute value + * + * This function sets the value of the given attribute. Returns zero on + * success, negative values on failure. + * + */ +int seccomp_attr_set(scmp_filter_ctx ctx, + enum scmp_filter_attr attr, uint32_t value); + +/** + * Resolve a syscall number to a name + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * @param num the syscall number + * + * Resolve the given syscall number to the syscall name for the given + * architecture; it is up to the caller to free the returned string. Returns + * the syscall name on success, NULL on failure. + * + */ +char *seccomp_syscall_resolve_num_arch(uint32_t arch_token, int num); + +/** + * Resolve a syscall name to a number + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * @param name the syscall name + * + * Resolve the given syscall name to the syscall number for the given + * architecture. Returns the syscall number on success, including negative + * pseudo syscall numbers (e.g. __PNR_*); returns __NR_SCMP_ERROR on failure. + * + */ +int seccomp_syscall_resolve_name_arch(uint32_t arch_token, const char *name); + +/** + * Resolve a syscall name to a number + * @param name the syscall name + * + * Resolve the given syscall name to the syscall number. Returns the syscall + * number on success, including negative pseudo syscall numbers (e.g. __PNR_*); + * returns __NR_SCMP_ERROR on failure. + * + */ +int seccomp_syscall_resolve_name(const char *name); + +/** + * Set the priority of a given syscall + * @param ctx the filter context + * @param syscall the syscall number + * @param priority priority value, higher value == higher priority + * + * This function sets the priority of the given syscall; this value is used + * when generating the seccomp filter code such that higher priority syscalls + * will incur less filter code overhead than the lower priority syscalls in the + * filter. Returns zero on success, negative values on failure. + * + */ +int seccomp_syscall_priority(scmp_filter_ctx ctx, + int syscall, uint8_t priority); + +/** + * Add a new rule to the filter + * @param ctx the filter context + * @param action the filter action + * @param syscall the syscall number + * @param arg_cnt the number of argument filters in the argument filter chain + * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended) + * + * This function adds a series of new argument/value checks to the seccomp + * filter for the given syscall; multiple argument/value checks can be + * specified and they will be chained together (AND'd together) in the filter. + * If the specified rule needs to be adjusted due to architecture specifics it + * will be adjusted without notification. Returns zero on success, negative + * values on failure. + * + */ +int seccomp_rule_add(scmp_filter_ctx ctx, + uint32_t action, int syscall, unsigned int arg_cnt, ...); + + +/** + * Add a new rule to the filter + * @param ctx the filter context + * @param action the filter action + * @param syscall the syscall number + * @param arg_cnt the number of elements in the arg_array parameter + * @param arg_array array of scmp_arg_cmp structs + * + * This function adds a series of new argument/value checks to the seccomp + * filter for the given syscall; multiple argument/value checks can be + * specified and they will be chained together (AND'd together) in the filter. + * If the specified rule needs to be adjusted due to architecture specifics it + * will be adjusted without notification. Returns zero on success, negative + * values on failure. + * + */ +int seccomp_rule_add_array(scmp_filter_ctx ctx, + uint32_t action, int syscall, unsigned int arg_cnt, + const struct scmp_arg_cmp *arg_array); + +/** + * Add a new rule to the filter + * @param ctx the filter context + * @param action the filter action + * @param syscall the syscall number + * @param arg_cnt the number of argument filters in the argument filter chain + * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended) + * + * This function adds a series of new argument/value checks to the seccomp + * filter for the given syscall; multiple argument/value checks can be + * specified and they will be chained together (AND'd together) in the filter. + * If the specified rule can not be represented on the architecture the + * function will fail. Returns zero on success, negative values on failure. + * + */ +int seccomp_rule_add_exact(scmp_filter_ctx ctx, uint32_t action, + int syscall, unsigned int arg_cnt, ...); + +/** + * Add a new rule to the filter + * @param ctx the filter context + * @param action the filter action + * @param syscall the syscall number + * @param arg_cnt the number of elements in the arg_array parameter + * @param arg_array array of scmp_arg_cmp structs + * + * This function adds a series of new argument/value checks to the seccomp + * filter for the given syscall; multiple argument/value checks can be + * specified and they will be chained together (AND'd together) in the filter. + * If the specified rule can not be represented on the architecture the + * function will fail. Returns zero on success, negative values on failure. + * + */ +int seccomp_rule_add_exact_array(scmp_filter_ctx ctx, + uint32_t action, int syscall, + unsigned int arg_cnt, + const struct scmp_arg_cmp *arg_array); + +/** + * Generate seccomp Pseudo Filter Code (PFC) and export it to a file + * @param ctx the filter context + * @param fd the destination fd + * + * This function generates seccomp Pseudo Filter Code (PFC) and writes it to + * the given fd. Returns zero on success, negative values on failure. + * + */ +int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd); + +/** + * Generate seccomp Berkley Packet Filter (BPF) code and export it to a file + * @param ctx the filter context + * @param fd the destination fd + * + * This function generates seccomp Berkley Packer Filter (BPF) code and writes + * it to the given fd. Returns zero on success, negative values on failure. + * + */ +int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd); + +/* + * pseudo syscall definitions + */ + +/* NOTE - pseudo syscall values {-1..-99} are reserved */ +#define __NR_SCMP_ERROR -1 + +/* socket syscalls */ + +#define __PNR_socket -101 +#ifndef __NR_socket +#define __NR_socket __PNR_socket +#endif /* __NR_socket */ + +#define __PNR_bind -102 +#ifndef __NR_bind +#define __NR_bind __PNR_bind +#endif /* __NR_bind */ + +#define __PNR_connect -103 +#ifndef __NR_connect +#define __NR_connect __PNR_connect +#endif /* __NR_connect */ + +#define __PNR_listen -104 +#ifndef __NR_listen +#define __NR_listen __PNR_listen +#endif /* __NR_listen */ + +#define __PNR_accept -105 +#ifndef __NR_accept +#define __NR_accept __PNR_accept +#endif /* __NR_accept */ + +#define __PNR_getsockname -106 +#ifndef __NR_getsockname +#define __NR_getsockname __PNR_getsockname +#endif /* __NR_getsockname */ + +#define __PNR_getpeername -107 +#ifndef __NR_getpeername +#define __NR_getpeername __PNR_getpeername +#endif /* __NR_getpeername */ + +#define __PNR_socketpair -108 +#ifndef __NR_socketpair +#define __NR_socketpair __PNR_socketpair +#endif /* __NR_socketpair */ + +#define __PNR_send -109 +#ifndef __NR_send +#define __NR_send __PNR_send +#endif /* __NR_send */ + +#define __PNR_recv -110 +#ifndef __NR_recv +#define __NR_recv __PNR_recv +#endif /* __NR_recv */ + +#define __PNR_sendto -111 +#ifndef __NR_sendto +#define __NR_sendto __PNR_sendto +#endif /* __NR_sendto */ + +#define __PNR_recvfrom -112 +#ifndef __NR_recvfrom +#define __NR_recvfrom __PNR_recvfrom +#endif /* __NR_recvfrom */ + +#define __PNR_shutdown -113 +#ifndef __NR_shutdown +#define __NR_shutdown __PNR_shutdown +#endif /* __NR_shutdown */ + +#define __PNR_setsockopt -114 +#ifndef __NR_setsockopt +#define __NR_setsockopt __PNR_setsockopt +#endif /* __NR_getsockopt */ + +#define __PNR_getsockopt -115 +#ifndef __NR_getsockopt +#define __NR_getsockopt __PNR_getsockopt +#endif /* __NR_getsockopt */ + +#define __PNR_sendmsg -116 +#ifndef __NR_sendmsg +#define __NR_sendmsg __PNR_sendmsg +#endif /* __NR_sendmsg */ + +#define __PNR_recvmsg -117 +#ifndef __NR_recvmsg +#define __NR_recvmsg __PNR_recvmsg +#endif /* __NR_recvmsg */ + +#define __PNR_accept4 -118 +#ifndef __NR_accept4 +#define __NR_accept4 __PNR_accept4 +#endif /* __NR_accept4 */ + +#define __PNR_recvmmsg -119 +#ifndef __NR_recvmmsg +#define __NR_recvmmsg __PNR_recvmmsg +#endif /* __NR_recvmmsg */ + +#define __PNR_sendmmsg -120 +#ifndef __NR_sendmmsg +#define __NR_sendmmsg __PNR_sendmmsg +#endif /* __NR_sendmmsg */ + +/* ipc syscalls */ + +#define __PNR_semop -201 +#ifndef __NR_semop +#define __NR_semop __PNR_semop +#endif /* __NR_semop */ + +#define __PNR_semget -202 +#ifndef __NR_semget +#define __NR_semget __PNR_semget +#endif /* __NR_semget */ + +#define __PNR_semctl -203 +#ifndef __NR_semctl +#define __NR_semctl __PNR_semctl +#endif /* __NR_semctl */ + +#define __PNR_semtimedop -204 +#ifndef __NR_semtimedop +#define __NR_semtimedop __PNR_semtimedop +#endif /* __NR_semtime */ + +#define __PNR_msgsnd -211 +#ifndef __NR_msgsnd +#define __NR_msgsnd __PNR_msgsnd +#endif /* __NR_msgsnd */ + +#define __PNR_msgrcv -212 +#ifndef __NR_msgrcv +#define __NR_msgrcv __PNR_msgrcv +#endif /* __NR_msgrcv */ + +#define __PNR_msgget -213 +#ifndef __NR_msgget +#define __NR_msgget __PNR_msgget +#endif /* __NR_msgget */ + +#define __PNR_msgctl -214 +#ifndef __NR_msgctl +#define __NR_msgctl __PNR_msgctl +#endif /* __NR_msgctl */ + +#define __PNR_shmat -221 +#ifndef __NR_shmat +#define __NR_shmat __PNR_shmat +#endif /* __NR_shmat */ + +#define __PNR_shmdt -222 +#ifndef __NR_shmdt +#define __NR_shmdt __PNR_shmdt +#endif /* __NR_shmdt */ + +#define __PNR_shmget -223 +#ifndef __NR_shmget +#define __NR_shmget __PNR_shmget +#endif /* __NR_shmget */ + +#define __PNR_shmctl -224 +#ifndef __NR_shmctl +#define __NR_shmctl __PNR_shmctl +#endif /* __NR_shmctl */ + +/* single syscalls */ + +#define __PNR_arch_prctl -10001 +#ifndef __NR_arch_prctl +#define __NR_arch_prctl __PNR_arch_prctl +#endif /* __NR_arch_prctl */ + +#define __PNR_bdflush -10002 +#ifndef __NR_bdflush +#define __NR_bdflush __PNR_bdflush +#endif /* __NR_bdflush */ + +#define __PNR_break -10003 +#ifndef __NR_break +#define __NR_break __PNR_break +#endif /* __NR_break */ + +#define __PNR_chown32 -10004 +#ifndef __NR_chown32 +#define __NR_chown32 __PNR_chown32 +#endif /* __NR_chown32 */ + +#define __PNR_epoll_ctl_old -10005 +#ifndef __NR_epoll_ctl_old +#define __NR_epoll_ctl_old __PNR_epoll_ctl_old +#endif /* __NR_epoll_ctl_old */ + +#define __PNR_epoll_wait_old -10006 +#ifndef __NR_epoll_wait_old +#define __NR_epoll_wait_old __PNR_epoll_wait_old +#endif /* __NR_epoll_wait_old */ + +#define __PNR_fadvise64_64 -10007 +#ifndef __NR_fadvise64_64 +#define __NR_fadvise64_64 __PNR_fadvise64_64 +#endif /* __NR_fadvise64_64 */ + +#define __PNR_fchown32 -10008 +#ifndef __NR_fchown32 +#define __NR_fchown32 __PNR_fchown32 +#endif /* __NR_fchown32 */ + +#define __PNR_fcntl64 -10009 +#ifndef __NR_fcntl64 +#define __NR_fcntl64 __PNR_fcntl64 +#endif /* __NR_fcntl64 */ + +#define __PNR_fstat64 -10010 +#ifndef __NR_fstat64 +#define __NR_fstat64 __PNR_fstat64 +#endif /* __NR_fstat64 */ + +#define __PNR_fstatat64 -10011 +#ifndef __NR_fstatat64 +#define __NR_fstatat64 __PNR_fstatat64 +#endif /* __NR_fstatat64 */ + +#define __PNR_fstatfs64 -10012 +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 __PNR_fstatfs64 +#endif /* __NR_fstatfs64 */ + +#define __PNR_ftime -10013 +#ifndef __NR_ftime +#define __NR_ftime __PNR_ftime +#endif /* __NR_ftime */ + +#define __PNR_ftruncate64 -10014 +#ifndef __NR_ftruncate64 +#define __NR_ftruncate64 __PNR_ftruncate64 +#endif /* __NR_ftruncate64 */ + +#define __PNR_getegid32 -10015 +#ifndef __NR_getegid32 +#define __NR_getegid32 __PNR_getegid32 +#endif /* __NR_getegid32 */ + +#define __PNR_geteuid32 -10016 +#ifndef __NR_geteuid32 +#define __NR_geteuid32 __PNR_geteuid32 +#endif /* __NR_geteuid32 */ + +#define __PNR_getgid32 -10017 +#ifndef __NR_getgid32 +#define __NR_getgid32 __PNR_getgid32 +#endif /* __NR_getgid32 */ + +#define __PNR_getgroups32 -10018 +#ifndef __NR_getgroups32 +#define __NR_getgroups32 __PNR_getgroups32 +#endif /* __NR_getgroups32 */ + +#define __PNR_getresgid32 -10019 +#ifndef __NR_getresgid32 +#define __NR_getresgid32 __PNR_getresgid32 +#endif /* __NR_getresgid32 */ + +#define __PNR_getresuid32 -10020 +#ifndef __NR_getresuid32 +#define __NR_getresuid32 __PNR_getresuid32 +#endif /* __NR_getresuid32 */ + +#define __PNR_getuid32 -10021 +#ifndef __NR_getuid32 +#define __NR_getuid32 __PNR_getuid32 +#endif /* __NR_getuid32 */ + +#define __PNR_gtty -10022 +#ifndef __NR_gtty +#define __NR_gtty __PNR_gtty +#endif /* __NR_gtty */ + +#define __PNR_idle -10023 +#ifndef __NR_idle +#define __NR_idle __PNR_idle +#endif /* __NR_idle */ + +#define __PNR_ipc -10024 +#ifndef __NR_ipc +#define __NR_ipc __PNR_ipc +#endif /* __NR_ipc */ + +#define __PNR_lchown32 -10025 +#ifndef __NR_lchown32 +#define __NR_lchown32 __PNR_lchown32 +#endif /* __NR_lchown32 */ + +#define __PNR__llseek -10026 +#ifndef __NR__llseek +#define __NR__llseek __PNR__llseek +#endif /* __NR__llseek */ + +#define __PNR_lock -10027 +#ifndef __NR_lock +#define __NR_lock __PNR_lock +#endif /* __NR_lock */ + +#define __PNR_lstat64 -10028 +#ifndef __NR_lstat64 +#define __NR_lstat64 __PNR_lstat64 +#endif /* __NR_lstat64 */ + +#define __PNR_mmap2 -10029 +#ifndef __NR_mmap2 +#define __NR_mmap2 __PNR_mmap2 +#endif /* __NR_mmap2 */ + +#define __PNR_mpx -10030 +#ifndef __NR_mpx +#define __NR_mpx __PNR_mpx +#endif /* __NR_mpx */ + +#define __PNR_newfstatat -10031 +#ifndef __NR_newfstatat +#define __NR_newfstatat __PNR_newfstatat +#endif /* __NR_newfstatat */ + +#define __PNR__newselect -10032 +#ifndef __NR__newselect +#define __NR__newselect __PNR__newselect +#endif /* __NR__newselect */ + +#define __PNR_nice -10033 +#ifndef __NR_nice +#define __NR_nice __PNR_nice +#endif /* __NR_nice */ + +#define __PNR_oldfstat -10034 +#ifndef __NR_oldfstat +#define __NR_oldfstat __PNR_oldfstat +#endif /* __NR_oldfstat */ + +#define __PNR_oldlstat -10035 +#ifndef __NR_oldlstat +#define __NR_oldlstat __PNR_oldlstat +#endif /* __NR_oldlstat */ + +#define __PNR_oldolduname -10036 +#ifndef __NR_oldolduname +#define __NR_oldolduname __PNR_oldolduname +#endif /* __NR_oldolduname */ + +#define __PNR_oldstat -10037 +#ifndef __NR_oldstat +#define __NR_oldstat __PNR_oldstat +#endif /* __NR_oldstat */ + +#define __PNR_olduname -10038 +#ifndef __NR_olduname +#define __NR_olduname __PNR_olduname +#endif /* __NR_olduname */ + +#define __PNR_prof -10039 +#ifndef __NR_prof +#define __NR_prof __PNR_prof +#endif /* __NR_prof */ + +#define __PNR_profil -10040 +#ifndef __NR_profil +#define __NR_profil __PNR_profil +#endif /* __NR_profil */ + +#define __PNR_readdir -10041 +#ifndef __NR_readdir +#define __NR_readdir __PNR_readdir +#endif /* __NR_readdir */ + +#define __PNR_security -10042 +#ifndef __NR_security +#define __NR_security __PNR_security +#endif /* __NR_security */ + +#define __PNR_sendfile64 -10043 +#ifndef __NR_sendfile64 +#define __NR_sendfile64 __PNR_sendfile64 +#endif /* __NR_sendfile64 */ + +#define __PNR_setfsgid32 -10044 +#ifndef __NR_setfsgid32 +#define __NR_setfsgid32 __PNR_setfsgid32 +#endif /* __NR_setfsgid32 */ + +#define __PNR_setfsuid32 -10045 +#ifndef __NR_setfsuid32 +#define __NR_setfsuid32 __PNR_setfsuid32 +#endif /* __NR_setfsuid32 */ + +#define __PNR_setgid32 -10046 +#ifndef __NR_setgid32 +#define __NR_setgid32 __PNR_setgid32 +#endif /* __NR_setgid32 */ + +#define __PNR_setgroups32 -10047 +#ifndef __NR_setgroups32 +#define __NR_setgroups32 __PNR_setgroups32 +#endif /* __NR_setgroups32 */ + +#define __PNR_setregid32 -10048 +#ifndef __NR_setregid32 +#define __NR_setregid32 __PNR_setregid32 +#endif /* __NR_setregid32 */ + +#define __PNR_setresgid32 -10049 +#ifndef __NR_setresgid32 +#define __NR_setresgid32 __PNR_setresgid32 +#endif /* __NR_setresgid32 */ + +#define __PNR_setresuid32 -10050 +#ifndef __NR_setresuid32 +#define __NR_setresuid32 __PNR_setresuid32 +#endif /* __NR_setresuid32 */ + +#define __PNR_setreuid32 -10051 +#ifndef __NR_setreuid32 +#define __NR_setreuid32 __PNR_setreuid32 +#endif /* __NR_setreuid32 */ + +#define __PNR_setuid32 -10052 +#ifndef __NR_setuid32 +#define __NR_setuid32 __PNR_setuid32 +#endif /* __NR_setuid32 */ + +#define __PNR_sgetmask -10053 +#ifndef __NR_sgetmask +#define __NR_sgetmask __PNR_sgetmask +#endif /* __NR_sgetmask */ + +#define __PNR_sigaction -10054 +#ifndef __NR_sigaction +#define __NR_sigaction __PNR_sigaction +#endif /* __NR_sigaction */ + +#define __PNR_signal -10055 +#ifndef __NR_signal +#define __NR_signal __PNR_signal +#endif /* __NR_signal */ + +#define __PNR_sigpending -10056 +#ifndef __NR_sigpending +#define __NR_sigpending __PNR_sigpending +#endif /* __NR_sigpending */ + +#define __PNR_sigprocmask -10057 +#ifndef __NR_sigprocmask +#define __NR_sigprocmask __PNR_sigprocmask +#endif /* __NR_sigprocmask */ + +#define __PNR_sigreturn -10058 +#ifndef __NR_sigreturn +#define __NR_sigreturn __PNR_sigreturn +#endif /* __NR_sigreturn */ + +#define __PNR_sigsuspend -10059 +#ifndef __NR_sigsuspend +#define __NR_sigsuspend __PNR_sigsuspend +#endif /* __NR_sigsuspend */ + +#define __PNR_socketcall -10060 +#ifndef __NR_socketcall +#define __NR_socketcall __PNR_socketcall +#endif /* __NR_socketcall */ + +#define __PNR_ssetmask -10061 +#ifndef __NR_ssetmask +#define __NR_ssetmask __PNR_ssetmask +#endif /* __NR_ssetmask */ + +#define __PNR_stat64 -10062 +#ifndef __NR_stat64 +#define __NR_stat64 __PNR_stat64 +#endif /* __NR_stat64 */ + +#define __PNR_statfs64 -10063 +#ifndef __NR_statfs64 +#define __NR_statfs64 __PNR_statfs64 +#endif /* __NR_statfs64 */ + +#define __PNR_stime -10064 +#ifndef __NR_stime +#define __NR_stime __PNR_stime +#endif /* __NR_stime */ + +#define __PNR_stty -10065 +#ifndef __NR_stty +#define __NR_stty __PNR_stty +#endif /* __NR_stty */ + +#define __PNR_truncate64 -10066 +#ifndef __NR_truncate64 +#define __NR_truncate64 __PNR_truncate64 +#endif /* __NR_truncate64 */ + +#define __PNR_tuxcall -10067 +#ifndef __NR_tuxcall +#define __NR_tuxcall __PNR_tuxcall +#endif /* __NR_tuxcall */ + +#define __PNR_ugetrlimit -10068 +#ifndef __NR_ugetrlimit +#define __NR_ugetrlimit __PNR_ugetrlimit +#endif /* __NR_ugetrlimit */ + +#define __PNR_ulimit -10069 +#ifndef __NR_ulimit +#define __NR_ulimit __PNR_ulimit +#endif /* __NR_ulimit */ + +#define __PNR_umount -10070 +#ifndef __NR_umount +#define __NR_umount __PNR_umount +#endif /* __NR_umount */ + +#define __PNR_vm86 -10071 +#ifndef __NR_vm86 +#define __NR_vm86 __PNR_vm86 +#endif /* __NR_vm86 */ + +#define __PNR_vm86old -10072 +#ifndef __NR_vm86old +#define __NR_vm86old __PNR_vm86old +#endif /* __NR_vm86old */ + +#define __PNR_waitpid -10073 +#ifndef __NR_waitpid +#define __NR_waitpid __PNR_waitpid +#endif /* __NR_waitpid */ + +#define __PNR_create_module -10074 +#ifndef __NR_create_module +#define __NR_create_module __PNR_create_module +#endif /* __NR_create_module */ + +#define __PNR_get_kernel_syms -10075 +#ifndef __NR_get_kernel_syms +#define __NR_get_kernel_syms __PNR_get_kernel_syms +#endif /* __NR_get_kernel_syms */ + +#define __PNR_get_thread_area -10076 +#ifndef __NR_get_thread_area +#define __NR_get_thread_area __PNR_get_thread_area +#endif /* __NR_get_thread_area */ + +#define __PNR_nfsservctl -10077 +#ifndef __NR_nfsservctl +#define __NR_nfsservctl __PNR_nfsservctl +#endif /* __NR_nfsservctl */ + +#define __PNR_query_module -10078 +#ifndef __NR_query_module +#define __NR_query_module __PNR_query_module +#endif /* __NR_query_module */ + +#define __PNR_set_thread_area -10079 +#ifndef __NR_set_thread_area +#define __NR_set_thread_area __PNR_set_thread_area +#endif /* __NR_set_thread_area */ + +#define __PNR__sysctl -10080 +#ifndef __NR__sysctl +#define __NR__sysctl __PNR__sysctl +#endif /* __NR__sysctl */ + +#define __PNR_uselib -10081 +#ifndef __NR_uselib +#define __NR_uselib __PNR_uselib +#endif /* __NR_uselib */ + +#define __PNR_vserver -10082 +#ifndef __NR_vserver +#define __NR_vserver __PNR_vserver +#endif /* __NR_vserver */ + +#define __PNR_arm_fadvise64_64 -10083 +#ifndef __NR_arm_fadvise64_64 +#define __NR_arm_fadvise64_64 __PNR_arm_fadvise64_64 +#endif /* __NR_arm_fadvise64_64 */ + +#define __PNR_arm_sync_file_range -10084 +#ifndef __NR_arm_sync_file_range +#define __NR_arm_sync_file_range __PNR_arm_sync_file_range +#endif /* __NR_arm_sync_file_range */ + +#define __PNR_finit_module -10085 +#ifndef __NR_finit_module +#define __NR_finit_module __PNR_finit_module +#endif /* __NR_finit_module */ + +#define __PNR_pciconfig_iobase -10086 +#ifndef __NR_pciconfig_iobase +#define __NR_pciconfig_iobase __PNR_pciconfig_iobase +#endif /* __NR_pciconfig_iobase */ + +#define __PNR_pciconfig_read -10087 +#ifndef __NR_pciconfig_read +#define __NR_pciconfig_read __PNR_pciconfig_read +#endif /* __NR_pciconfig_read */ + +#define __PNR_pciconfig_write -10088 +#ifndef __NR_pciconfig_write +#define __NR_pciconfig_write __PNR_pciconfig_write +#endif /* __NR_pciconfig_write */ + +#define __PNR_sync_file_range2 -10089 +#ifndef __NR_sync_file_range2 +#define __NR_sync_file_range2 __PNR_sync_file_range2 +#endif /* __NR_sync_file_range2 */ + +#define __PNR_syscall -10090 +#ifndef __NR_syscall +#define __NR_syscall __PNR_syscall +#endif /* __NR_syscall */ + +#define __PNR_afs_syscall -10091 +#ifndef __NR_afs_syscall +#define __NR_afs_syscall __PNR_afs_syscall +#endif /* __NR_afs_syscall */ + +#define __PNR_fadvise64 -10092 +#ifndef __NR_fadvise64 +#define __NR_fadvise64 __PNR_fadvise64 +#endif /* __NR_fadvise64 */ + +#define __PNR_getpmsg -10093 +#ifndef __NR_getpmsg +#define __NR_getpmsg __PNR_getpmsg +#endif /* __NR_getpmsg */ + +#define __PNR_ioperm -10094 +#ifndef __NR_ioperm +#define __NR_ioperm __PNR_ioperm +#endif /* __NR_ioperm */ + +#define __PNR_iopl -10095 +#ifndef __NR_iopl +#define __NR_iopl __PNR_iopl +#endif /* __NR_iopl */ + +#define __PNR_kcmp -10096 +#ifndef __NR_kcmp +#define __NR_kcmp __PNR_kcmp +#endif /* __NR_kcmp */ + +#define __PNR_migrate_pages -10097 +#ifndef __NR_migrate_pages +#define __NR_migrate_pages __PNR_migrate_pages +#endif /* __NR_migrate_pages */ + +#define __PNR_modify_ldt -10098 +#ifndef __NR_modify_ldt +#define __NR_modify_ldt __PNR_modify_ldt +#endif /* __NR_modify_ldt */ + +#define __PNR_putpmsg -10099 +#ifndef __NR_putpmsg +#define __NR_putpmsg __PNR_putpmsg +#endif /* __NR_putpmsg */ + +#define __PNR_sync_file_range -10100 +#ifndef __NR_sync_file_range +#define __NR_sync_file_range __PNR_sync_file_range +#endif /* __NR_sync_file_range */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/install.mk b/install.mk new file mode 100644 index 0000000..123af33 --- /dev/null +++ b/install.mk @@ -0,0 +1,31 @@ +# +# Enhanced Seccomp Library Installation Defaults +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +INSTALL_PREFIX ?= $(CONF_INSTALL_PREFIX) + +INSTALL_SBIN_DIR ?= $(DESTDIR)/$(INSTALL_PREFIX)/sbin +INSTALL_BIN_DIR ?= $(DESTDIR)/$(INSTALL_PREFIX)/bin +INSTALL_LIB_DIR ?= $(DESTDIR)/$(CONF_INSTALL_LIBDIR) +INSTALL_INC_DIR ?= $(DESTDIR)/$(INSTALL_PREFIX)/include +INSTALL_MAN_DIR ?= $(DESTDIR)/$(INSTALL_PREFIX)/share/man + +INSTALL_OWNER ?= $$(id -u) +INSTALL_GROUP ?= $$(id -g) diff --git a/libseccomp.pc.in b/libseccomp.pc.in new file mode 100644 index 0000000..c195831 --- /dev/null +++ b/libseccomp.pc.in @@ -0,0 +1,31 @@ +# +# Enhanced Seccomp Library pkg-config Configuration +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +prefix=%%INSTALL_PREFIX%% +libdir=%%INSTALL_LIBDIR%% +includedir=${prefix}/include + +Name: libseccomp +Description: The enhanced seccomp library +URL: http://libseccomp.sf.net +Version: %%VERSION_RELEASE%% +Cflags: -I${includedir} +Libs: -L${libdir} -lseccomp diff --git a/macros.mk b/macros.mk new file mode 100644 index 0000000..6df5b3a --- /dev/null +++ b/macros.mk @@ -0,0 +1,234 @@ +# +# Enhanced Seccomp Library Build Macros +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +SHELL = /bin/bash + +# +# simple /bin/bash script to find the top of the tree +# + +TOPDIR := $(shell \ + ftd() { \ + cd $$1; \ + if [[ -r "macros.mk" ]]; then \ + pwd; \ + else \ + ftd "../"; \ + fi \ + }; \ + ftd .) + +# +# build configuration +# + +V ?= 0 + +CPPFLAGS += -I$(TOPDIR) -I$(TOPDIR)/include +LIBFLAGS = + +CFLAGS ?= -Wl,-z,relro -Wall -O0 -g -fvisibility=hidden +CFLAGS += -fPIC +PYCFLAGS ?= -fvisibility=default +LDFLAGS ?= -z relro -g + +# +# build tools +# + +LN ?= ln +MV ?= mv +CAT ?= cat +ECHO ?= echo +TAR ?= tar +MKDIR ?= mkdir + +SED ?= sed +AWK ?= awk + +PYTHON ?= /usr/bin/env python + +# we require gcc specific functionality +GCC ?= gcc + +INSTALL ?= install + +ifeq ($(V),0) + MAKE += --quiet --no-print-directory + ECHO_INFO ?= $(ECHO) ">> INFO:" +else + ECHO_INFO ?= /bin/true || $(ECHO) ">> INFO:" +endif + +# +# auto dependencies +# + +MAKEDEP = @$(GCC) $(CPPFLAGS) -MM -MF $(patsubst %.o,%.d,$@) $<; +MAKEDEP_EXEC = \ + @$(GCC) $(CPPFLAGS) -MM -MT $(patsubst %.d,%,$@) \ + -MF $@ $(patsubst %.d,%.c,$@); + +ADDDEP = \ + @adddep_func() { \ + $(MV) $$1 $$1.dtmp; \ + $(CAT) $$1.dtmp | $(SED) -e 's/\([^\]\)$$/\1 \\/' | \ + ( $(CAT) - && $(ECHO) " $$2" ) > $$1; \ + $(RM) -f $@.dtmp; \ + }; \ + adddep_func + +# +# build constants +# + +VERSION_HDR = version.h + +# +# build macros +# + +PY_DISTUTILS = \ + VERSION_RELEASE="$(VERSION_RELEASE)" \ + CFLAGS="$(CFLAGS) $(CPPFLAGS) $(PYCFLAGS)" LDFLAGS="$(LDFLAGS)" \ + $(PYTHON) ./setup.py + +ifeq ($(V),0) + PY_BUILD = @echo " PYTHON build"; +endif +PY_BUILD += $(PY_DISTUTILS) +ifeq ($(V),0) + PY_BUILD += -q +endif +PY_BUILD += build + +ifeq ($(V),0) + PY_INSTALL = @echo " PYTHON install"; +endif +PY_INSTALL += $(PY_DISTUTILS) +ifeq ($(V),0) + PY_INSTALL += -q +endif +PY_INSTALL += install + +ifeq ($(V),0) + COMPILE = @echo " CC $@"; +endif +COMPILE += $(GCC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<; + +ifeq ($(V),0) + COMPILE_EXEC = @echo " CC $@"; +endif +COMPILE_EXEC += $(GCC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(LDFLAGS); + +ifeq ($(V),0) + ARCHIVE = @echo " AR $@"; +endif +ARCHIVE += $(AR) -cru $@ $?; + +ifeq ($(V),0) + LINK_EXEC = @echo " LD $@"; +endif +LINK_EXEC += $(GCC) $(LDFLAGS) -o $@ $^ $(LIBFLAGS); + +ifeq ($(V),0) + LINK_LIB = @echo " LD $@" \ + "($(patsubst %.so.$(VERSION_RELEASE),%.so.$(VERSION_MAJOR),$@))"; +endif +LINK_LIB += $(GCC) $(LDFLAGS) -o $@ $^ -shared \ + -Wl,-soname=$(patsubst %.so.$(VERSION_RELEASE),%.so.$(VERSION_MAJOR),$@) + +# +# install macros +# + +ifeq ($(V),0) + INSTALL_LIB_MACRO = @echo " INSTALL $^ ($(INSTALL_LIB_DIR)/$^)"; +endif +INSTALL_LIB_MACRO += \ + basename=$$(echo $^ | sed -e 's/.so.*$$/.so/'); \ + soname=$$(objdump -p $^ | grep "SONAME" | awk '{print $$2}'); \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) \ + -d "$(INSTALL_LIB_DIR)"; \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) -m 0755 \ + $^ "$(INSTALL_LIB_DIR)"; \ + (cd "$(INSTALL_LIB_DIR)"; $(RM) $$soname); \ + (cd "$(INSTALL_LIB_DIR)"; $(LN) -s $^ $$soname); \ + (cd "$(INSTALL_LIB_DIR)"; $(RM) $$basname); \ + (cd "$(INSTALL_LIB_DIR)"; $(LN) -s $^ $$basename); + +ifeq ($(V),0) + INSTALL_BIN_MACRO = @echo " INSTALL $^ ($(INSTALL_BIN_DIR)/$^)"; +endif +INSTALL_BIN_MACRO += \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) \ + -d "$(INSTALL_BIN_DIR)"; \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) -m 0755 \ + $^ "$(INSTALL_BIN_DIR)"; + +ifeq ($(V),0) + INSTALL_PC_MACRO = \ + @echo " INSTALL $$(cat /proc/$$$$/cmdline | awk '{print $$(NF)}')" \ + " ($(INSTALL_LIB_DIR)/pkgconfig)"; +endif +INSTALL_PC_MACRO += \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) \ + -d "$(INSTALL_LIB_DIR)/pkgconfig"; \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) -m 0644 \ + "$$(cat /proc/$$$$/cmdline | awk '{print $$(NF)}')" \ + "$(INSTALL_LIB_DIR)/pkgconfig"; \# + +ifeq ($(V),0) + INSTALL_INC_MACRO = @echo " INSTALL $^ ($(INSTALL_INC_DIR))"; +endif +INSTALL_INC_MACRO += \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) \ + -d "$(INSTALL_INC_DIR)"; \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) -m 0644 \ + $^ "$(INSTALL_INC_DIR)"; + +ifeq ($(V),0) + INSTALL_MAN1_MACRO = \ + @echo " INSTALL manpages ($(INSTALL_MAN_DIR)/man1)"; +endif +INSTALL_MAN1_MACRO += \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) \ + -d "$(INSTALL_MAN_DIR)/man1"; \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) -m 0644 \ + $^ "$(INSTALL_MAN_DIR)/man1"; + +ifeq ($(V),0) + INSTALL_MAN3_MACRO = \ + @echo " INSTALL manpages ($(INSTALL_MAN_DIR)/man3)"; +endif +INSTALL_MAN3_MACRO += \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) \ + -d "$(INSTALL_MAN_DIR)/man3"; \ + $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) -m 0644 \ + $^ "$(INSTALL_MAN_DIR)/man3"; + +# +# default build targets +# + +%.o: %.c + $(MAKEDEP) + $(COMPILE) diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..7b980ab --- /dev/null +++ b/src/Makefile @@ -0,0 +1,92 @@ +# +# Enhanced Seccomp Library Makefile +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# +# macros +# + +include ../macros.mk + +# +# configuration +# + +include $(TOPDIR)/version_info.mk +include $(TOPDIR)/configure.mk +include $(TOPDIR)/install.mk + +LIB_STATIC = libseccomp.a +LIB_SHARED = libseccomp.so.$(VERSION_RELEASE) + +OBJS = \ + api.o db.o arch.o \ + arch-x86.o arch-x86-syscalls.o \ + arch-x86_64.o arch-x86_64-syscalls.o \ + arch-x32.o arch-x32-syscalls.o \ + arch-arm.o arch-arm-syscalls.o \ + hash.o \ + gen_pfc.o gen_bpf.o + +DEPS = $(OBJS:%.o=%.d) + +# +# bindings configuration +# + +BINDINGS = + +ifeq ($(CONF_BINDINGS_PYTHON), 1) + BINDINGS += python +endif + +# +# targets +# + +.PHONY: all install clean python + +all: $(LIB_STATIC) $(LIB_SHARED) $(BINDINGS) + +-include $(DEPS) + +$(LIB_STATIC): $(OBJS) + $(ARCHIVE) + +$(LIB_SHARED): $(OBJS) + $(LINK_LIB) + +python: $(LIB_STATIC) + @$(ECHO_INFO) "building in directory $@/ ..." + @$(MAKE) -C $@ + +install: $(LIB_SHARED) + $(INSTALL_LIB_MACRO) + @for dir in $(BINDINGS); do \ + $(ECHO) ">> INFO: installing from $$dir/"; \ + $(MAKE) -C $$dir install; \ + done + +clean: + $(RM) $(DEPS) $(OBJS) $(LIB_STATIC) libseccomp.so.* + @for dir in python; do \ + $(MAKE) -C $$dir clean; \ + done + diff --git a/src/api.c b/src/api.c new file mode 100644 index 0000000..86e5f9d --- /dev/null +++ b/src/api.c @@ -0,0 +1,589 @@ +/** + * Seccomp Library API + * + * Copyright (c) 2012,2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "arch.h" +#include "db.h" +#include "gen_pfc.h" +#include "gen_bpf.h" +#include "system.h" + +#define API __attribute__((visibility("default"))) + +/** + * Validate a filter context + * @param ctx the filter context + * + * Attempt to validate the provided filter context. Returns zero if the + * context is valid, negative values on failure. + * + */ +static int _ctx_valid(const scmp_filter_ctx *ctx) +{ + return db_col_valid((struct db_filter_col *)ctx); +} + +/** + * Validate a syscall number + * @param syscall the syscall number + * + * Attempt to perform basic syscall number validation. Returns zero of the + * syscall appears valid, negative values on failure. + * + */ +static int _syscall_valid(int syscall) +{ + if (syscall <= -1 && syscall >= -99) + return -EINVAL; + return 0; +} + +/* NOTE - function header comment in include/seccomp.h */ +API scmp_filter_ctx seccomp_init(uint32_t def_action) +{ + struct db_filter_col *col; + struct db_filter *db; + + if (db_action_valid(def_action) < 0) + return NULL; + + col = db_col_init(def_action); + if (col == NULL) + return NULL; + db = db_init(arch_def_native); + if (db == NULL) + goto init_failure_col; + + if (db_col_db_add(col, db) < 0) + goto init_failure_db; + + return col; + +init_failure_db: + db_release(db); +init_failure_col: + db_col_release(col); + return NULL; +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action) +{ + int rc; + struct db_filter_col *col = (struct db_filter_col *)ctx; + struct db_filter *db; + + if (db_col_valid(col) || db_action_valid(def_action) < 0) + return -EINVAL; + + db_col_reset(col, def_action); + + db = db_init(arch_def_native); + if (db == NULL) + return -ENOMEM; + rc = db_col_db_add(col, db); + if (rc < 0) + db_release(db); + + return rc; +} + +/* NOTE - function header comment in include/seccomp.h */ +API void seccomp_release(scmp_filter_ctx ctx) +{ + if (_ctx_valid(ctx)) + return; + + db_col_release((struct db_filter_col *)ctx); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_merge(scmp_filter_ctx ctx_dst, + scmp_filter_ctx ctx_src) +{ + struct db_filter_col *col_dst = (struct db_filter_col *)ctx_dst; + struct db_filter_col *col_src = (struct db_filter_col *)ctx_src; + + if (db_col_valid(col_dst) || db_col_valid(col_src)) + return -EINVAL; + + /* NOTE: only the default action and NNP settings must match */ + if ((col_dst->attr.act_default != col_src->attr.act_default) || + (col_dst->attr.nnp_enable != col_src->attr.nnp_enable)) + return -EINVAL; + + return db_col_merge(col_dst, col_src); +} + +/* NOTE - function header comment in include/seccomp.h */ +API uint32_t seccomp_arch_native(void) +{ + return arch_def_native->token; +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_arch_exist(const scmp_filter_ctx ctx, + uint32_t arch_token) +{ + struct db_filter_col *col = (struct db_filter_col *)ctx; + + if (arch_token == 0) + arch_token = arch_def_native->token; + + if (arch_valid(arch_token)) + return -EINVAL; + + return (db_col_arch_exist(col, arch_token) ? 0 : -EEXIST); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token) +{ + int rc; + const struct arch_def *arch; + struct db_filter *db; + struct db_filter_col *col = (struct db_filter_col *)ctx; + + if (arch_token == 0) + arch_token = arch_def_native->token; + + if (arch_valid(arch_token)) + return -EINVAL; + if (db_col_arch_exist(col, arch_token)) + return -EEXIST; + + arch = arch_def_lookup(arch_token); + if (arch == NULL) + return -EFAULT; + db = db_init(arch); + if (db == NULL) + return -ENOMEM; + rc = db_col_db_add(col, db); + if (rc < 0) + db_release(db); + + return rc; +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token) +{ + struct db_filter_col *col = (struct db_filter_col *)ctx; + + if (arch_token == 0) + arch_token = arch_def_native->token; + + if (arch_valid(arch_token)) + return -EINVAL; + if (db_col_arch_exist(col, arch_token) != -EEXIST) + return -EEXIST; + + return db_col_db_remove(col, arch_token); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_load(const scmp_filter_ctx ctx) +{ + int rc; + struct db_filter_col *col; + struct bpf_program *program; + + if (_ctx_valid(ctx)) + return -EINVAL; + col = (struct db_filter_col *)ctx; + + program = gen_bpf_generate((struct db_filter_col *)ctx); + if (program == NULL) + return -ENOMEM; + /* attempt to set NO_NEW_PRIVS */ + if (col->attr.nnp_enable) { + rc = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + if (rc < 0) + return -errno; + } + /* load the filter into the kernel */ + rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, program); + gen_bpf_release(program); + if (rc < 0) + return -errno; + + return 0; +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_attr_get(const scmp_filter_ctx ctx, + enum scmp_filter_attr attr, uint32_t *value) +{ + if (_ctx_valid(ctx)) + return -EINVAL; + + return db_col_attr_get((const struct db_filter_col *)ctx, attr, value); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_attr_set(scmp_filter_ctx ctx, + enum scmp_filter_attr attr, uint32_t value) +{ + if (_ctx_valid(ctx)) + return -EINVAL; + + return db_col_attr_set((struct db_filter_col *)ctx, attr, value); +} + +/* NOTE - function header comment in include/seccomp.h */ +API char *seccomp_syscall_resolve_num_arch(uint32_t arch_token, int num) +{ + const struct arch_def *arch; + const char *name; + + if (arch_token == 0) + arch_token = arch_def_native->token; + if (arch_valid(arch_token)) + return NULL; + arch = arch_def_lookup(arch_token); + if (arch == NULL) + return NULL; + + name = arch_syscall_resolve_num(arch, num); + if (name == NULL) + return NULL; + + return strdup(name); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_syscall_resolve_name_arch(uint32_t arch_token, const char *name) +{ + const struct arch_def *arch; + + if (name == NULL) + return -EINVAL; + + if (arch_token == 0) + arch_token = arch_def_native->token; + if (arch_valid(arch_token)) + return -EINVAL; + arch = arch_def_lookup(arch_token); + if (arch == NULL) + return -EFAULT; + + return arch_syscall_resolve_name(arch, name); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_syscall_resolve_name(const char *name) +{ + return seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, name); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_syscall_priority(scmp_filter_ctx ctx, + int syscall, uint8_t priority) +{ + int rc = 0, rc_tmp; + unsigned int iter; + int sc_tmp; + struct db_filter_col *col; + struct db_filter *filter; + + if (_ctx_valid(ctx) || _syscall_valid(syscall)) + return -EINVAL; + col = (struct db_filter_col *)ctx; + + for (iter = 0; iter < col->filter_cnt; iter++) { + filter = col->filters[iter]; + sc_tmp = syscall; + + rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp); + if (rc_tmp < 0) + goto syscall_priority_failure; + + /* if this is a pseudo syscall (syscall < 0) then we need to + * rewrite the syscall for some arch specific reason */ + if (sc_tmp < 0) { + /* we set this as a strict op - we don't really care + * since priorities are a "best effort" thing - as we + * want to catch the -EDOM error and bail on this + * architecture */ + rc_tmp = arch_syscall_rewrite(filter->arch, 1, &sc_tmp); + if (rc_tmp == -EDOM) + continue; + if (rc_tmp < 0) + goto syscall_priority_failure; + } + + rc_tmp = db_syscall_priority(filter, sc_tmp, priority); + +syscall_priority_failure: + if (rc == 0 && rc_tmp < 0) + rc = rc_tmp; + } + + return rc; +} + +/** + * Add a new rule to the current filter + * @param col the filter collection + * @param strict the strict flag + * @param action the filter action + * @param syscall the syscall number + * @param arg_cnt the number of argument filters in the argument filter chain + * @param arg_list the argument filter chain, (uint, enum scmp_compare, ulong) + * + * This function adds a new argument/comparison/value to the seccomp filter for + * a syscall; multiple arguments can be specified and they will be chained + * together (essentially AND'd together) in the filter. When the strict flag + * is true the function will fail if the exact rule can not be added to the + * filter, if the strict flag is false the function will not fail if the + * function needs to adjust the rule due to architecture specifics. Returns + * zero on success, negative values on failure. + * + */ +static int _seccomp_rule_add(struct db_filter_col *col, + bool strict, uint32_t action, int syscall, + unsigned int arg_cnt, + const struct scmp_arg_cmp *arg_array) +{ + int rc = 0, rc_tmp; + int sc_tmp; + unsigned int iter; + unsigned int chain_len; + unsigned int arg_num; + size_t chain_size; + struct db_filter *filter; + struct db_api_arg *chain = NULL, *chain_tmp; + struct scmp_arg_cmp arg_data; + + if (arg_cnt > 0 && arg_array == NULL) + return -EINVAL; + + if (db_col_valid(col) || _syscall_valid(syscall)) + return -EINVAL; + + rc = db_action_valid(action); + if (rc < 0) + return rc; + if (action == col->attr.act_default) + return -EPERM; + + if (strict && col->filter_cnt > 1) + return -EOPNOTSUPP; + + /* collect the arguments for the filter rule */ + chain_len = ARG_COUNT_MAX; + chain_size = sizeof(*chain) * chain_len; + chain = malloc(chain_size); + if (chain == NULL) + return -ENOMEM; + memset(chain, 0, chain_size); + for (iter = 0; iter < arg_cnt; iter++) { + arg_data = arg_array[iter]; + arg_num = arg_data.arg; + if (arg_num < chain_len && chain[arg_num].valid == 0) { + chain[arg_num].valid = 1; + chain[arg_num].arg = arg_num; + chain[arg_num].op = arg_data.op; + /* XXX - we should check datum/mask size against the + * arch definition, e.g. 64 bit datum on x86 */ + switch (chain[arg_num].op) { + case SCMP_CMP_NE: + case SCMP_CMP_LT: + case SCMP_CMP_LE: + case SCMP_CMP_EQ: + case SCMP_CMP_GE: + case SCMP_CMP_GT: + chain[arg_num].mask = DATUM_MAX; + chain[arg_num].datum = arg_data.datum_a; + break; + case SCMP_CMP_MASKED_EQ: + chain[arg_num].mask = arg_data.datum_a; + chain[arg_num].datum = arg_data.datum_b; + break; + default: + rc = -EINVAL; + goto rule_add_return; + } + } else { + rc = -EINVAL; + goto rule_add_return; + } + } + + for (iter = 0; iter < col->filter_cnt; iter++) { + filter = col->filters[iter]; + sc_tmp = syscall; + + rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp); + if (rc_tmp < 0) + goto rule_add_failure; + + /* if this is a pseudo syscall (syscall < 0) then we need to + * rewrite the rule for some arch specific reason */ + if (sc_tmp < 0) { + /* make a private copy of the chain */ + chain_tmp = malloc(chain_size); + if (chain_tmp == NULL) { + rc = -ENOMEM; + goto rule_add_failure; + } + memcpy(chain_tmp, chain, chain_size); + + /* mangle the private chain copy */ + rc_tmp = arch_filter_rewrite(filter->arch, strict, + &sc_tmp, chain_tmp); + if ((rc == -EDOM) && (!strict)) { + free(chain_tmp); + continue; + } + if (rc_tmp < 0) { + free(chain_tmp); + goto rule_add_failure; + } + + /* add the new rule to the existing filter */ + rc_tmp = db_rule_add(filter, action, sc_tmp, chain_tmp); + free(chain_tmp); + } else + /* add the new rule to the existing filter */ + rc_tmp = db_rule_add(filter, action, sc_tmp, chain); + +rule_add_failure: + if (rc == 0 && rc_tmp < 0) + rc = rc_tmp; + } + +rule_add_return: + if (chain != NULL) + free(chain); + return rc; +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_rule_add_array(scmp_filter_ctx ctx, + uint32_t action, int syscall, + unsigned int arg_cnt, + const struct scmp_arg_cmp *arg_array) +{ + if (arg_cnt < 0 || arg_cnt > ARG_COUNT_MAX) + return -EINVAL; + + return _seccomp_rule_add((struct db_filter_col *)ctx, + 0, action, syscall, arg_cnt, arg_array); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_rule_add(scmp_filter_ctx ctx, + uint32_t action, int syscall, + unsigned int arg_cnt, ...) +{ + int rc; + int iter; + struct scmp_arg_cmp arg_array[ARG_COUNT_MAX]; + va_list arg_list; + + if (arg_cnt < 0 || arg_cnt > ARG_COUNT_MAX) + return -EINVAL; + + va_start(arg_list, arg_cnt); + for (iter = 0; iter < arg_cnt; ++iter) + arg_array[iter] = va_arg(arg_list, struct scmp_arg_cmp); + rc = seccomp_rule_add_array(ctx, action, syscall, arg_cnt, arg_array); + va_end(arg_list); + + return rc; +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_rule_add_exact_array(scmp_filter_ctx ctx, + uint32_t action, int syscall, + unsigned int arg_cnt, + const struct scmp_arg_cmp *arg_array) +{ + if (arg_cnt < 0 || arg_cnt > ARG_COUNT_MAX) + return -EINVAL; + + return _seccomp_rule_add((struct db_filter_col *)ctx, + 1, action, syscall, arg_cnt, arg_array); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_rule_add_exact(scmp_filter_ctx ctx, + uint32_t action, int syscall, + unsigned int arg_cnt, ...) +{ + int rc; + int iter; + struct scmp_arg_cmp arg_array[ARG_COUNT_MAX]; + va_list arg_list; + + if (arg_cnt < 0 || arg_cnt > ARG_COUNT_MAX) + return -EINVAL; + + va_start(arg_list, arg_cnt); + for (iter = 0; iter < arg_cnt; ++iter) + arg_array[iter] = va_arg(arg_list, struct scmp_arg_cmp); + rc = seccomp_rule_add_exact_array(ctx, + action, syscall, arg_cnt, arg_array); + va_end(arg_list); + + return rc; +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd) +{ + if (_ctx_valid(ctx)) + return -EINVAL; + + return gen_pfc_generate((struct db_filter_col *)ctx, fd); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd) +{ + int rc; + struct bpf_program *program; + + if (_ctx_valid(ctx)) + return -EINVAL; + + program = gen_bpf_generate((struct db_filter_col *)ctx); + if (program == NULL) + return -ENOMEM; + rc = write(fd, program->blks, BPF_PGM_SIZE(program)); + gen_bpf_release(program); + if (rc < 0) + return -errno; + + return 0; +} diff --git a/src/arch-arm-syscalls.c b/src/arch-arm-syscalls.c new file mode 100644 index 0000000..66db33b --- /dev/null +++ b/src/arch-arm-syscalls.c @@ -0,0 +1,479 @@ +/** + * Enhanced Seccomp ARM Syscall Table + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "arch.h" +#include "arch-arm.h" + +#define __NR_OABI_SYSCALL_BASE 0x900000 + +/* NOTE: we currently only support the ARM EABI, more info at the URL below: + * -> http://wiki.embeddedarm.com/wiki/EABI_vs_OABI */ +#if 1 +#define __NR_SYSCALL_BASE 0 +#else +#define __NR_SYSCALL_BASE __NR_OABI_SYSCALL_BASE +#endif + +/* NOTE: based on Linux 3.8.0-rc5 */ +const struct arch_syscall_def arm_syscall_table[] = { \ + /* NOTE: arm_sync_file_range() and sync_file_range2() share values */ + { "accept", (__NR_SYSCALL_BASE + 285) }, + { "accept4", (__NR_SYSCALL_BASE + 366) }, + { "access", (__NR_SYSCALL_BASE + 33) }, + { "acct", (__NR_SYSCALL_BASE + 51) }, + { "add_key", (__NR_SYSCALL_BASE + 309) }, + { "adjtimex", (__NR_SYSCALL_BASE + 124) }, + { "afs_syscall", __PNR_afs_syscall }, + { "alarm", (__NR_SYSCALL_BASE + 27) }, + { "arm_fadvise64_64", (__NR_SYSCALL_BASE + 270) }, + { "arm_sync_file_range", (__NR_SYSCALL_BASE + 341) }, + { "arch_prctl", __PNR_arch_prctl }, + { "bdflush", (__NR_SYSCALL_BASE + 134) }, + { "bind", (__NR_SYSCALL_BASE + 282) }, + { "break", __PNR_break }, + { "brk", (__NR_SYSCALL_BASE + 45) }, + { "capget", (__NR_SYSCALL_BASE + 184) }, + { "capset", (__NR_SYSCALL_BASE + 185) }, + { "chdir", (__NR_SYSCALL_BASE + 12) }, + { "chmod", (__NR_SYSCALL_BASE + 15) }, + { "chown", (__NR_SYSCALL_BASE + 182) }, + { "chown32", (__NR_SYSCALL_BASE + 212) }, + { "chroot", (__NR_SYSCALL_BASE + 61) }, + { "clock_adjtime", (__NR_SYSCALL_BASE + 372) }, + { "clock_getres", (__NR_SYSCALL_BASE + 264) }, + { "clock_gettime", (__NR_SYSCALL_BASE + 263) }, + { "clock_nanosleep", (__NR_SYSCALL_BASE + 265) }, + { "clock_settime", (__NR_SYSCALL_BASE + 262) }, + { "clone", (__NR_SYSCALL_BASE + 120) }, + { "close", (__NR_SYSCALL_BASE + 6) }, + { "connect", (__NR_SYSCALL_BASE + 283) }, + { "creat", (__NR_SYSCALL_BASE + 8) }, + { "create_module", __PNR_create_module }, + { "delete_module", (__NR_SYSCALL_BASE + 129) }, + { "dup", (__NR_SYSCALL_BASE + 41) }, + { "dup2", (__NR_SYSCALL_BASE + 63) }, + { "dup3", (__NR_SYSCALL_BASE + 358) }, + { "epoll_create", (__NR_SYSCALL_BASE + 250) }, + { "epoll_create1", (__NR_SYSCALL_BASE + 357) }, + { "epoll_ctl", (__NR_SYSCALL_BASE + 251) }, + { "epoll_ctl_old", __PNR_epoll_ctl_old }, + { "epoll_pwait", (__NR_SYSCALL_BASE + 346) }, + { "epoll_wait", (__NR_SYSCALL_BASE + 252) }, + { "epoll_wait_old", __PNR_epoll_wait_old }, + { "eventfd", (__NR_SYSCALL_BASE + 351) }, + { "eventfd2", (__NR_SYSCALL_BASE + 356) }, + { "execve", (__NR_SYSCALL_BASE + 11) }, + { "exit", (__NR_SYSCALL_BASE + 1) }, + { "exit_group", (__NR_SYSCALL_BASE + 248) }, + { "faccessat", (__NR_SYSCALL_BASE + 334) }, + { "fadvise64", __PNR_fadvise64 }, + { "fadvise64_64", __PNR_fadvise64_64 }, + { "fallocate", (__NR_SYSCALL_BASE + 352) }, + { "fanotify_init", (__NR_SYSCALL_BASE + 367) }, + { "fanotify_mark", (__NR_SYSCALL_BASE + 368) }, + { "fchdir", (__NR_SYSCALL_BASE + 133) }, + { "fchmod", (__NR_SYSCALL_BASE + 94) }, + { "fchmodat", (__NR_SYSCALL_BASE + 333) }, + { "fchown", (__NR_SYSCALL_BASE + 95) }, + { "fchown32", (__NR_SYSCALL_BASE + 207) }, + { "fchownat", (__NR_SYSCALL_BASE + 325) }, + { "fcntl", (__NR_SYSCALL_BASE + 55) }, + { "fcntl64", (__NR_SYSCALL_BASE + 221) }, + { "fdatasync", (__NR_SYSCALL_BASE + 148) }, + { "fgetxattr", (__NR_SYSCALL_BASE + 231) }, + { "finit_module", (__NR_SYSCALL_BASE + 379) }, + { "flistxattr", (__NR_SYSCALL_BASE + 234) }, + { "flock", (__NR_SYSCALL_BASE + 143) }, + { "fork", (__NR_SYSCALL_BASE + 2) }, + { "fremovexattr", (__NR_SYSCALL_BASE + 237) }, + { "fsetxattr", (__NR_SYSCALL_BASE + 228) }, + { "fstat", (__NR_SYSCALL_BASE + 108) }, + { "fstat64", (__NR_SYSCALL_BASE + 197) }, + { "fstatat64", (__NR_SYSCALL_BASE + 327) }, + { "fstatfs", (__NR_SYSCALL_BASE + 100) }, + { "fstatfs64", (__NR_SYSCALL_BASE + 267) }, + { "fsync", (__NR_SYSCALL_BASE + 118) }, + { "ftime", __PNR_ftime }, + { "ftruncate", (__NR_SYSCALL_BASE + 93) }, + { "ftruncate64", (__NR_SYSCALL_BASE + 194) }, + { "futex", (__NR_SYSCALL_BASE + 240) }, + { "futimesat", (__NR_SYSCALL_BASE + 326) }, + { "get_kernel_syms", __PNR_get_kernel_syms }, + { "get_mempolicy", (__NR_SYSCALL_BASE + 320) }, + { "get_robust_list", (__NR_SYSCALL_BASE + 339) }, + { "get_thread_area", __PNR_get_thread_area }, + { "getcpu", (__NR_SYSCALL_BASE + 345) }, + { "getcwd", (__NR_SYSCALL_BASE + 183) }, + { "getdents", (__NR_SYSCALL_BASE + 141) }, + { "getdents64", (__NR_SYSCALL_BASE + 217) }, + { "getegid", (__NR_SYSCALL_BASE + 50) }, + { "getegid32", (__NR_SYSCALL_BASE + 202) }, + { "geteuid", (__NR_SYSCALL_BASE + 49) }, + { "geteuid32", (__NR_SYSCALL_BASE + 201) }, + { "getgid", (__NR_SYSCALL_BASE + 47) }, + { "getgid32", (__NR_SYSCALL_BASE + 200) }, + { "getgroups", (__NR_SYSCALL_BASE + 80) }, + { "getgroups32", (__NR_SYSCALL_BASE + 205) }, + { "getitimer", (__NR_SYSCALL_BASE + 105) }, + { "getpeername", (__NR_SYSCALL_BASE + 287) }, + { "getpgid", (__NR_SYSCALL_BASE + 132) }, + { "getpgrp", (__NR_SYSCALL_BASE + 65) }, + { "getpid", (__NR_SYSCALL_BASE + 20) }, + { "getpmsg", __PNR_getpmsg }, + { "getppid", (__NR_SYSCALL_BASE + 64) }, + { "getpriority", (__NR_SYSCALL_BASE + 96) }, + { "getresgid", (__NR_SYSCALL_BASE + 171) }, + { "getresgid32", (__NR_SYSCALL_BASE + 211) }, + { "getresuid", (__NR_SYSCALL_BASE + 165) }, + { "getresuid32", (__NR_SYSCALL_BASE + 209) }, + { "getrlimit", (__NR_SYSCALL_BASE + 76) }, + { "getrusage", (__NR_SYSCALL_BASE + 77) }, + { "getsid", (__NR_SYSCALL_BASE + 147) }, + { "getsockname", (__NR_SYSCALL_BASE + 286) }, + { "getsockopt", (__NR_SYSCALL_BASE + 295) }, + { "gettid", (__NR_SYSCALL_BASE + 224) }, + { "gettimeofday", (__NR_SYSCALL_BASE + 78) }, + { "getuid", (__NR_SYSCALL_BASE + 24) }, + { "getuid32", (__NR_SYSCALL_BASE + 199) }, + { "getxattr", (__NR_SYSCALL_BASE + 229) }, + { "gtty", __PNR_gtty }, + { "idle", __PNR_idle }, + { "init_module", (__NR_SYSCALL_BASE + 128) }, + { "inotify_add_watch", (__NR_SYSCALL_BASE + 317) }, + { "inotify_init", (__NR_SYSCALL_BASE + 316) }, + { "inotify_init1", (__NR_SYSCALL_BASE + 360) }, + { "inotify_rm_watch", (__NR_SYSCALL_BASE + 318) }, + { "io_cancel", (__NR_SYSCALL_BASE + 247) }, + { "io_destroy", (__NR_SYSCALL_BASE + 244) }, + { "io_getevents", (__NR_SYSCALL_BASE + 245) }, + { "io_setup", (__NR_SYSCALL_BASE + 243) }, + { "io_submit", (__NR_SYSCALL_BASE + 246) }, + { "ioctl", (__NR_SYSCALL_BASE + 54) }, + { "ioperm", __PNR_ioperm }, + { "iopl", __PNR_iopl }, + { "ioprio_get", (__NR_SYSCALL_BASE + 315) }, + { "ioprio_set", (__NR_SYSCALL_BASE + 314) }, + { "ipc", (__NR_SYSCALL_BASE + 117) }, + { "kcmp", __PNR_kcmp }, + { "kexec_load", (__NR_SYSCALL_BASE + 347) }, + { "keyctl", (__NR_SYSCALL_BASE + 311) }, + { "kill", (__NR_SYSCALL_BASE + 37) }, + { "lchown", (__NR_SYSCALL_BASE + 16) }, + { "lchown32", (__NR_SYSCALL_BASE + 198) }, + { "lgetxattr", (__NR_SYSCALL_BASE + 230) }, + { "link", (__NR_SYSCALL_BASE + 9) }, + { "linkat", (__NR_SYSCALL_BASE + 330) }, + { "listen", (__NR_SYSCALL_BASE + 284) }, + { "listxattr", (__NR_SYSCALL_BASE + 232) }, + { "llistxattr", (__NR_SYSCALL_BASE + 233) }, + { "_llseek", (__NR_SYSCALL_BASE + 140) }, + { "lock", __PNR_lock }, + { "lookup_dcookie", (__NR_SYSCALL_BASE + 249) }, + { "lremovexattr", (__NR_SYSCALL_BASE + 236) }, + { "lseek", (__NR_SYSCALL_BASE + 19) }, + { "lsetxattr", (__NR_SYSCALL_BASE + 227) }, + { "lstat", (__NR_SYSCALL_BASE + 107) }, + { "lstat64", (__NR_SYSCALL_BASE + 196) }, + { "madvise", (__NR_SYSCALL_BASE + 220) }, + { "mbind", (__NR_SYSCALL_BASE + 319) }, + { "migrate_pages", __PNR_migrate_pages }, + { "mincore", (__NR_SYSCALL_BASE + 219) }, + { "mkdir", (__NR_SYSCALL_BASE + 39) }, + { "mkdirat", (__NR_SYSCALL_BASE + 323) }, + { "mknod", (__NR_SYSCALL_BASE + 14) }, + { "mknodat", (__NR_SYSCALL_BASE + 324) }, + { "mlock", (__NR_SYSCALL_BASE + 150) }, + { "mlockall", (__NR_SYSCALL_BASE + 152) }, + { "mmap", (__NR_SYSCALL_BASE + 90) }, + { "mmap2", (__NR_SYSCALL_BASE + 192) }, + { "modify_ldt", __PNR_modify_ldt }, + { "mount", (__NR_SYSCALL_BASE + 21) }, + { "move_pages", (__NR_SYSCALL_BASE + 344) }, + { "mprotect", (__NR_SYSCALL_BASE + 125) }, + { "mpx", __PNR_mpx }, + { "mq_getsetattr", (__NR_SYSCALL_BASE + 279) }, + { "mq_notify", (__NR_SYSCALL_BASE + 278) }, + { "mq_open", (__NR_SYSCALL_BASE + 274) }, + { "mq_timedreceive", (__NR_SYSCALL_BASE + 277) }, + { "mq_timedsend", (__NR_SYSCALL_BASE + 276) }, + { "mq_unlink", (__NR_SYSCALL_BASE + 275) }, + { "mremap", (__NR_SYSCALL_BASE + 163) }, + { "msgctl", (__NR_SYSCALL_BASE + 304) }, + { "msgget", (__NR_SYSCALL_BASE + 303) }, + { "msgrcv", (__NR_SYSCALL_BASE + 302) }, + { "msgsnd", (__NR_SYSCALL_BASE + 301) }, + { "msync", (__NR_SYSCALL_BASE + 144) }, + { "munlock", (__NR_SYSCALL_BASE + 151) }, + { "munlockall", (__NR_SYSCALL_BASE + 153) }, + { "munmap", (__NR_SYSCALL_BASE + 91) }, + { "name_to_handle_at", (__NR_SYSCALL_BASE + 370) }, + { "nanosleep", (__NR_SYSCALL_BASE + 162) }, + { "_newselect", (__NR_SYSCALL_BASE + 142) }, + { "newfstatat", __PNR_newfstatat }, + { "nfsservctl", (__NR_SYSCALL_BASE + 169) }, + { "nice", (__NR_SYSCALL_BASE + 34) }, + { "oldfstat", __PNR_oldfstat }, + { "oldlstat", __PNR_oldlstat }, + { "oldolduname", __PNR_oldolduname }, + { "oldstat", __PNR_oldstat }, + { "olduname", __PNR_olduname }, + { "open", (__NR_SYSCALL_BASE + 5) }, + { "open_by_handle_at", (__NR_SYSCALL_BASE + 371) }, + { "openat", (__NR_SYSCALL_BASE + 322) }, + { "pause", (__NR_SYSCALL_BASE + 29) }, + { "pciconfig_iobase", (__NR_SYSCALL_BASE + 271) }, + { "pciconfig_read", (__NR_SYSCALL_BASE + 272) }, + { "pciconfig_write", (__NR_SYSCALL_BASE + 273) }, + { "perf_event_open", (__NR_SYSCALL_BASE + 364) }, + { "personality", (__NR_SYSCALL_BASE + 136) }, + { "pipe", (__NR_SYSCALL_BASE + 42) }, + { "pipe2", (__NR_SYSCALL_BASE + 359) }, + { "pivot_root", (__NR_SYSCALL_BASE + 218) }, + { "poll", (__NR_SYSCALL_BASE + 168) }, + { "ppoll", (__NR_SYSCALL_BASE + 336) }, + { "prctl", (__NR_SYSCALL_BASE + 172) }, + { "pread64", (__NR_SYSCALL_BASE + 180) }, + { "preadv", (__NR_SYSCALL_BASE + 361) }, + { "prlimit64", (__NR_SYSCALL_BASE + 369) }, + { "process_vm_readv", (__NR_SYSCALL_BASE + 376) }, + { "process_vm_writev", (__NR_SYSCALL_BASE + 377) }, + { "prof", __PNR_prof }, + { "profil", __PNR_profil }, + { "pselect6", (__NR_SYSCALL_BASE + 335) }, + { "ptrace", (__NR_SYSCALL_BASE + 26) }, + { "putpmsg", __PNR_putpmsg }, + { "pwrite64", (__NR_SYSCALL_BASE + 181) }, + { "pwritev", (__NR_SYSCALL_BASE + 362) }, + { "query_module", __PNR_query_module }, + { "quotactl", (__NR_SYSCALL_BASE + 131) }, + { "read", (__NR_SYSCALL_BASE + 3) }, + { "readahead", (__NR_SYSCALL_BASE + 225) }, + { "readdir", (__NR_SYSCALL_BASE + 89) }, + { "readlink", (__NR_SYSCALL_BASE + 85) }, + { "readlinkat", (__NR_SYSCALL_BASE + 332) }, + { "readv", (__NR_SYSCALL_BASE + 145) }, + { "reboot", (__NR_SYSCALL_BASE + 88) }, + { "recv", (__NR_SYSCALL_BASE + 291) }, + { "recvfrom", (__NR_SYSCALL_BASE + 292) }, + { "recvmmsg", (__NR_SYSCALL_BASE + 365) }, + { "recvmsg", (__NR_SYSCALL_BASE + 297) }, + { "remap_file_pages", (__NR_SYSCALL_BASE + 253) }, + { "removexattr", (__NR_SYSCALL_BASE + 235) }, + { "rename", (__NR_SYSCALL_BASE + 38) }, + { "renameat", (__NR_SYSCALL_BASE + 329) }, + { "request_key", (__NR_SYSCALL_BASE + 310) }, + { "restart_syscall", (__NR_SYSCALL_BASE + 0) }, + { "rmdir", (__NR_SYSCALL_BASE + 40) }, + { "rt_sigaction", (__NR_SYSCALL_BASE + 174) }, + { "rt_sigpending", (__NR_SYSCALL_BASE + 176) }, + { "rt_sigprocmask", (__NR_SYSCALL_BASE + 175) }, + { "rt_sigqueueinfo", (__NR_SYSCALL_BASE + 178) }, + { "rt_sigreturn", (__NR_SYSCALL_BASE + 173) }, + { "rt_sigsuspend", (__NR_SYSCALL_BASE + 179) }, + { "rt_sigtimedwait", (__NR_SYSCALL_BASE + 177) }, + { "rt_tgsigqueueinfo", (__NR_SYSCALL_BASE + 363) }, + { "sched_get_priority_max", (__NR_SYSCALL_BASE + 159) }, + { "sched_get_priority_min", (__NR_SYSCALL_BASE + 160) }, + { "sched_getaffinity", (__NR_SYSCALL_BASE + 242) }, + { "sched_getparam", (__NR_SYSCALL_BASE + 155) }, + { "sched_getscheduler", (__NR_SYSCALL_BASE + 157) }, + { "sched_rr_get_interval", (__NR_SYSCALL_BASE + 161) }, + { "sched_setaffinity", (__NR_SYSCALL_BASE + 241) }, + { "sched_setparam", (__NR_SYSCALL_BASE + 154) }, + { "sched_setscheduler", (__NR_SYSCALL_BASE + 156) }, + { "sched_yield", (__NR_SYSCALL_BASE + 158) }, + { "security", __PNR_security }, + { "select", (__NR_SYSCALL_BASE + 82) }, + { "semctl", (__NR_SYSCALL_BASE + 300) }, + { "semget", (__NR_SYSCALL_BASE + 299) }, + { "semop", (__NR_SYSCALL_BASE + 298) }, + { "semtimedop", (__NR_SYSCALL_BASE + 312) }, + { "send", (__NR_SYSCALL_BASE + 289) }, + { "sendfile", (__NR_SYSCALL_BASE + 187) }, + { "sendfile64", (__NR_SYSCALL_BASE + 239) }, + { "sendmmsg", (__NR_SYSCALL_BASE + 374) }, + { "sendmsg", (__NR_SYSCALL_BASE + 296) }, + { "sendto", (__NR_SYSCALL_BASE + 290) }, + { "set_mempolicy", (__NR_SYSCALL_BASE + 321) }, + { "set_robust_list", (__NR_SYSCALL_BASE + 338) }, + { "set_thread_area", __PNR_set_thread_area }, + { "set_tid_address", (__NR_SYSCALL_BASE + 256) }, + { "setdomainname", (__NR_SYSCALL_BASE + 121) }, + { "setfsgid", (__NR_SYSCALL_BASE + 139) }, + { "setfsgid32", (__NR_SYSCALL_BASE + 216) }, + { "setfsuid", (__NR_SYSCALL_BASE + 138) }, + { "setfsuid32", (__NR_SYSCALL_BASE + 215) }, + { "setgid", (__NR_SYSCALL_BASE + 46) }, + { "setgid32", (__NR_SYSCALL_BASE + 214) }, + { "setgroups", (__NR_SYSCALL_BASE + 81) }, + { "setgroups32", (__NR_SYSCALL_BASE + 206) }, + { "sethostname", (__NR_SYSCALL_BASE + 74) }, + { "setitimer", (__NR_SYSCALL_BASE + 104) }, + { "setns", (__NR_SYSCALL_BASE + 375) }, + { "setpgid", (__NR_SYSCALL_BASE + 57) }, + { "setpriority", (__NR_SYSCALL_BASE + 97) }, + { "setregid", (__NR_SYSCALL_BASE + 71) }, + { "setregid32", (__NR_SYSCALL_BASE + 204) }, + { "setresgid", (__NR_SYSCALL_BASE + 170) }, + { "setresgid32", (__NR_SYSCALL_BASE + 210) }, + { "setresuid", (__NR_SYSCALL_BASE + 164) }, + { "setresuid32", (__NR_SYSCALL_BASE + 208) }, + { "setreuid", (__NR_SYSCALL_BASE + 70) }, + { "setreuid32", (__NR_SYSCALL_BASE + 203) }, + { "setrlimit", (__NR_SYSCALL_BASE + 75) }, + { "setsid", (__NR_SYSCALL_BASE + 66) }, + { "setsockopt", (__NR_SYSCALL_BASE + 294) }, + { "settimeofday", (__NR_SYSCALL_BASE + 79) }, + { "setuid", (__NR_SYSCALL_BASE + 23) }, + { "setuid32", (__NR_SYSCALL_BASE + 213) }, + { "setxattr", (__NR_SYSCALL_BASE + 226) }, + { "sgetmask", __PNR_sgetmask }, + { "shmat", (__NR_SYSCALL_BASE + 305) }, + { "shmctl", (__NR_SYSCALL_BASE + 308) }, + { "shmdt", (__NR_SYSCALL_BASE + 306) }, + { "shmget", (__NR_SYSCALL_BASE + 307) }, + { "shutdown", (__NR_SYSCALL_BASE + 293) }, + { "sigaction", (__NR_SYSCALL_BASE + 67) }, + { "sigaltstack", (__NR_SYSCALL_BASE + 186) }, + { "signal", __PNR_signal }, + { "signalfd", (__NR_SYSCALL_BASE + 349) }, + { "signalfd4", (__NR_SYSCALL_BASE + 355) }, + { "sigpending", (__NR_SYSCALL_BASE + 73) }, + { "sigprocmask", (__NR_SYSCALL_BASE + 126) }, + { "sigreturn", (__NR_SYSCALL_BASE + 119) }, + { "sigsuspend", (__NR_SYSCALL_BASE + 72) }, + { "socket", (__NR_SYSCALL_BASE + 281) }, + { "socketcall", (__NR_SYSCALL_BASE + 102) }, + { "socketpair", (__NR_SYSCALL_BASE + 288) }, + { "splice", (__NR_SYSCALL_BASE + 340) }, + { "ssetmask", __PNR_ssetmask }, + { "stat", (__NR_SYSCALL_BASE + 106) }, + { "stat64", (__NR_SYSCALL_BASE + 195) }, + { "statfs", (__NR_SYSCALL_BASE + 99) }, + { "statfs64", (__NR_SYSCALL_BASE + 266) }, + { "stime", (__NR_SYSCALL_BASE + 25) }, + { "stty", __PNR_stty }, + { "swapoff", (__NR_SYSCALL_BASE + 115) }, + { "swapon", (__NR_SYSCALL_BASE + 87) }, + { "symlink", (__NR_SYSCALL_BASE + 83) }, + { "symlinkat", (__NR_SYSCALL_BASE + 331) }, + { "sync", (__NR_SYSCALL_BASE + 36) }, + { "sync_file_range", __PNR_sync_file_range }, + { "sync_file_range2", (__NR_SYSCALL_BASE + 341) }, + { "syncfs", (__NR_SYSCALL_BASE + 373) }, + { "syscall", (__NR_SYSCALL_BASE + 113) }, + { "_sysctl", (__NR_SYSCALL_BASE + 149) }, + { "sysfs", (__NR_SYSCALL_BASE + 135) }, + { "sysinfo", (__NR_SYSCALL_BASE + 116) }, + { "syslog", (__NR_SYSCALL_BASE + 103) }, + { "tee", (__NR_SYSCALL_BASE + 342) }, + { "tgkill", (__NR_SYSCALL_BASE + 268) }, + { "time", (__NR_SYSCALL_BASE + 13) }, + { "timer_create", (__NR_SYSCALL_BASE + 257) }, + { "timer_delete", (__NR_SYSCALL_BASE + 261) }, + { "timer_getoverrun", (__NR_SYSCALL_BASE + 260) }, + { "timer_gettime", (__NR_SYSCALL_BASE + 259) }, + { "timer_settime", (__NR_SYSCALL_BASE + 258) }, + { "timerfd_create", (__NR_SYSCALL_BASE + 350) }, + { "timerfd_gettime", (__NR_SYSCALL_BASE + 354) }, + { "timerfd_settime", (__NR_SYSCALL_BASE + 353) }, + { "times", (__NR_SYSCALL_BASE + 43) }, + { "tkill", (__NR_SYSCALL_BASE + 238) }, + { "truncate", (__NR_SYSCALL_BASE + 92) }, + { "truncate64", (__NR_SYSCALL_BASE + 193) }, + { "tuxcall", __PNR_tuxcall }, + { "ugetrlimit", (__NR_SYSCALL_BASE + 191) }, + { "ulimit", __PNR_ulimit }, + { "umask", (__NR_SYSCALL_BASE + 60) }, + { "umount", (__NR_SYSCALL_BASE + 22) }, + { "umount2", (__NR_SYSCALL_BASE + 52) }, + { "uname", (__NR_SYSCALL_BASE + 122) }, + { "unlink", (__NR_SYSCALL_BASE + 10) }, + { "unlinkat", (__NR_SYSCALL_BASE + 328) }, + { "unshare", (__NR_SYSCALL_BASE + 337) }, + { "uselib", (__NR_SYSCALL_BASE + 86) }, + { "ustat", (__NR_SYSCALL_BASE + 62) }, + { "utime", (__NR_SYSCALL_BASE + 30) }, + { "utimensat", (__NR_SYSCALL_BASE + 348) }, + { "utimes", (__NR_SYSCALL_BASE + 269) }, + { "vfork", (__NR_SYSCALL_BASE + 190) }, + { "vhangup", (__NR_SYSCALL_BASE + 111) }, + { "vm86", __PNR_vm86 }, + { "vm86old", __PNR_vm86old }, + { "vmsplice", (__NR_SYSCALL_BASE + 343) }, + { "vserver", (__NR_SYSCALL_BASE + 313) }, + { "wait4", (__NR_SYSCALL_BASE + 114) }, + { "waitid", (__NR_SYSCALL_BASE + 280) }, + { "waitpid", __PNR_waitpid }, + { "write", (__NR_SYSCALL_BASE + 4) }, + { "writev", (__NR_SYSCALL_BASE + 146) }, + { NULL, __NR_SCMP_ERROR }, +}; + +/** + * Resolve a syscall name to a number + * @param name the syscall name + * + * Resolve the given syscall name to the syscall number using the syscall table. + * Returns the syscall number on success, including negative pseudo syscall + * numbers; returns __NR_SCMP_ERROR on failure. + * + */ +int arm_syscall_resolve_name(const char *name) +{ + unsigned int iter; + const struct arch_syscall_def *table = arm_syscall_table; + + /* XXX - plenty of room for future improvement here */ + for (iter = 0; table[iter].name != NULL; iter++) { + if (strcmp(name, table[iter].name) == 0) + return table[iter].num; + } + + return __NR_SCMP_ERROR; +} + +/** + * Resolve a syscall number to a name + * @param num the syscall number + * + * Resolve the given syscall number to the syscall name using the syscall table. + * Returns a pointer to the syscall name string on success, including pseudo + * syscall names; returns NULL on failure. + * + */ +const char *arm_syscall_resolve_num(int num) +{ + unsigned int iter; + const struct arch_syscall_def *table = arm_syscall_table; + + /* XXX - plenty of room for future improvement here */ + for (iter = 0; table[iter].num != __NR_SCMP_ERROR; iter++) { + if (num == table[iter].num) + return table[iter].name; + } + + return NULL; +} diff --git a/src/arch-arm.c b/src/arch-arm.c new file mode 100644 index 0000000..d2f0834 --- /dev/null +++ b/src/arch-arm.c @@ -0,0 +1,34 @@ +/** + * Enhanced Seccomp ARM Specific Code + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include + +#include "arch.h" +#include "arch-arm.h" + +const struct arch_def arch_def_arm = { + .token = SCMP_ARCH_ARM, + .token_bpf = AUDIT_ARCH_ARM, + .size = ARCH_SIZE_32, + .endian = ARCH_ENDIAN_LITTLE, +}; diff --git a/src/arch-arm.h b/src/arch-arm.h new file mode 100644 index 0000000..a6f0b00 --- /dev/null +++ b/src/arch-arm.h @@ -0,0 +1,37 @@ +/** + * Enhanced Seccomp ARM Specific Code + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _ARCH_ARM_H +#define _ARCH_ARM_H + +#include + +#include "arch.h" +#include "system.h" + +#define arm_arg_count_max 6 + +extern const struct arch_def arch_def_arm; + +int arm_syscall_resolve_name(const char *name); +const char *arm_syscall_resolve_num(int num); + +#endif diff --git a/src/arch-x32-syscalls.c b/src/arch-x32-syscalls.c new file mode 100644 index 0000000..00c5bc2 --- /dev/null +++ b/src/arch-x32-syscalls.c @@ -0,0 +1,67 @@ +/** + * Enhanced Seccomp x32 Syscall Table + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "arch.h" +#include "arch-x86_64.h" +#include "arch-x32.h" + +/** + * Resolve a syscall name to a number + * @param name the syscall name + * + * Resolve the given syscall name to the syscall number using the syscall table. + * Returns the syscall number on success, including negative pseudo syscall + * numbers; returns __NR_SCMP_ERROR on failure. + * + */ +int x32_syscall_resolve_name(const char *name) +{ + int syscall; + + syscall = x86_64_syscall_resolve_name(name); + if (syscall >= 0) + syscall |= X32_SYSCALL_BIT; + + return syscall; +} + +/** + * Resolve a syscall number to a name + * @param num the syscall number + * + * Resolve the given syscall number to the syscall name using the syscall table. + * Returns a pointer to the syscall name string on success, including pseudo + * syscall names; returns NULL on failure. + * + */ +const char *x32_syscall_resolve_num(int num) +{ + int syscall = num; + + if (syscall >= 0) + syscall &= (~X32_SYSCALL_BIT); + + return x86_64_syscall_resolve_num(syscall); +} diff --git a/src/arch-x32.c b/src/arch-x32.c new file mode 100644 index 0000000..8b5dd97 --- /dev/null +++ b/src/arch-x32.c @@ -0,0 +1,35 @@ +/** + * Enhanced Seccomp x32 Specific Code + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include + +#include "arch.h" +#include "arch-x32.h" + +const struct arch_def arch_def_x32 = { + .token = SCMP_ARCH_X32, + /* NOTE: this seems odd but the kernel treats x32 like x86_64 here */ + .token_bpf = AUDIT_ARCH_X86_64, + .size = ARCH_SIZE_32, + .endian = ARCH_ENDIAN_LITTLE, +}; diff --git a/src/arch-x32.h b/src/arch-x32.h new file mode 100644 index 0000000..891a6f1 --- /dev/null +++ b/src/arch-x32.h @@ -0,0 +1,39 @@ +/** + * Enhanced Seccomp x32 Specific Code + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _ARCH_X32_H +#define _ARCH_X32_H + +#include + +#include "arch.h" +#include "system.h" + +#define X32_SYSCALL_BIT 0x40000000 + +#define x32_arg_count_max 6 + +extern const struct arch_def arch_def_x32; + +int x32_syscall_resolve_name(const char *name); +const char *x32_syscall_resolve_num(int num); + +#endif diff --git a/src/arch-x86-syscalls.c b/src/arch-x86-syscalls.c new file mode 100644 index 0000000..79f1b91 --- /dev/null +++ b/src/arch-x86-syscalls.c @@ -0,0 +1,468 @@ +/** + * Enhanced Seccomp x86 Syscall Table + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "arch.h" +#include "arch-x86.h" + +/* NOTE: based on Linux 3.4.7 */ +static const struct arch_syscall_def x86_syscall_table[] = { \ + { "accept", __PNR_accept }, + { "accept4", __PNR_accept4 }, + { "access", 33 }, + { "acct", 51 }, + { "add_key", 286 }, + { "adjtimex", 124 }, + { "afs_syscall", 137 }, + { "alarm", 27 }, + { "arm_fadvise64_64", __PNR_arm_fadvise64_64 }, + { "arm_sync_file_range", __PNR_arm_sync_file_range }, + { "arch_prctl", __PNR_arch_prctl }, + { "bdflush", 134 }, + { "bind", __PNR_bind }, + { "break", 17 }, + { "brk", 45 }, + { "capget", 184 }, + { "capset", 185 }, + { "chdir", 12 }, + { "chmod", 15 }, + { "chown", 182 }, + { "chown32", 212 }, + { "chroot", 61 }, + { "clock_adjtime", 343 }, + { "clock_getres", 266 }, + { "clock_gettime", 265 }, + { "clock_nanosleep", 267 }, + { "clock_settime", 264 }, + { "clone", 120 }, + { "close", 6 }, + { "connect", __PNR_connect }, + { "creat", 8 }, + { "create_module", 127 }, + { "delete_module", 129 }, + { "dup", 41 }, + { "dup2", 63 }, + { "dup3", 330 }, + { "epoll_create", 254 }, + { "epoll_create1", 329 }, + { "epoll_ctl", 255 }, + { "epoll_ctl_old", __PNR_epoll_ctl_old }, + { "epoll_pwait", 319 }, + { "epoll_wait", 256 }, + { "epoll_wait_old", __PNR_epoll_wait_old }, + { "eventfd", 323 }, + { "eventfd2", 328 }, + { "execve", 11 }, + { "exit", 1 }, + { "exit_group", 252 }, + { "faccessat", 307 }, + { "fadvise64", 250 }, + { "fadvise64_64", 272 }, + { "fallocate", 324 }, + { "fanotify_init", 338 }, + { "fanotify_mark", 339 }, + { "fchdir", 133 }, + { "fchmod", 94 }, + { "fchmodat", 306 }, + { "fchown", 95 }, + { "fchown32", 207 }, + { "fchownat", 298 }, + { "fcntl", 55 }, + { "fcntl64", 221 }, + { "fdatasync", 148 }, + { "fgetxattr", 231 }, + { "finit_module", __PNR_finit_module }, + { "flistxattr", 234 }, + { "flock", 143 }, + { "fork", 2 }, + { "fremovexattr", 237 }, + { "fsetxattr", 228 }, + { "fstat", 108 }, + { "fstat64", 197 }, + { "fstatat64", 300 }, + { "fstatfs", 100 }, + { "fstatfs64", 269 }, + { "fsync", 118 }, + { "ftime", 35 }, + { "ftruncate", 93 }, + { "ftruncate64", 194 }, + { "futex", 240 }, + { "futimesat", 299 }, + { "get_kernel_syms", 130 }, + { "get_mempolicy", 275 }, + { "get_robust_list", 312 }, + { "get_thread_area", 244 }, + { "getcpu", 318 }, + { "getcwd", 183 }, + { "getdents", 141 }, + { "getdents64", 220 }, + { "getegid", 50 }, + { "getegid32", 202 }, + { "geteuid", 49 }, + { "geteuid32", 201 }, + { "getgid", 47 }, + { "getgid32", 200 }, + { "getgroups", 80 }, + { "getgroups32", 205 }, + { "getitimer", 105 }, + { "getpeername", __PNR_getpeername }, + { "getpgid", 132 }, + { "getpgrp", 65 }, + { "getpid", 20 }, + { "getpmsg", 188 }, + { "getppid", 64 }, + { "getpriority", 96 }, + { "getresgid", 171 }, + { "getresgid32", 211 }, + { "getresuid", 165 }, + { "getresuid32", 209 }, + { "getrlimit", 76 }, + { "getrusage", 77 }, + { "getsid", 147 }, + { "getsockname", __PNR_getsockname }, + { "getsockopt", __PNR_getsockopt }, + { "gettid", 224 }, + { "gettimeofday", 78 }, + { "getuid", 24 }, + { "getuid32", 199 }, + { "getxattr", 229 }, + { "gtty", 32 }, + { "idle", 112 }, + { "init_module", 128 }, + { "inotify_add_watch", 292 }, + { "inotify_init", 291 }, + { "inotify_init1", 332 }, + { "inotify_rm_watch", 293 }, + { "io_cancel", 249 }, + { "io_destroy", 246 }, + { "io_getevents", 247 }, + { "io_setup", 245 }, + { "io_submit", 248 }, + { "ioctl", 54 }, + { "ioperm", 101 }, + { "iopl", 110 }, + { "ioprio_get", 290 }, + { "ioprio_set", 289 }, + { "ipc", 117 }, + { "kcmp", 349 }, + { "kexec_load", 283 }, + { "keyctl", 288 }, + { "kill", 37 }, + { "lchown", 16 }, + { "lchown32", 198 }, + { "lgetxattr", 230 }, + { "link", 9 }, + { "linkat", 303 }, + { "listen", __PNR_listen }, + { "listxattr", 232 }, + { "llistxattr", 233 }, + { "_llseek", 140 }, + { "lock", 53 }, + { "lookup_dcookie", 253 }, + { "lremovexattr", 236 }, + { "lseek", 19 }, + { "lsetxattr", 227 }, + { "lstat", 107 }, + { "lstat64", 196 }, + { "madvise", 219 }, + { "mbind", 274 }, + { "migrate_pages", 294 }, + { "mincore", 218 }, + { "mkdir", 39 }, + { "mkdirat", 296 }, + { "mknod", 14 }, + { "mknodat", 297 }, + { "mlock", 150 }, + { "mlockall", 152 }, + { "mmap", 90 }, + { "mmap2", 192 }, + { "modify_ldt", 123 }, + { "mount", 21 }, + { "move_pages", 317 }, + { "mprotect", 125 }, + { "mpx", 56 }, + { "mq_getsetattr", 282 }, + { "mq_notify", 281 }, + { "mq_open", 277 }, + { "mq_timedreceive", 280 }, + { "mq_timedsend", 279 }, + { "mq_unlink", 278 }, + { "mremap", 163 }, + { "msgctl", __PNR_msgctl }, + { "msgget", __PNR_msgget }, + { "msgrcv", __PNR_msgrcv }, + { "msgsnd", __PNR_msgsnd }, + { "msync", 144 }, + { "munlock", 151 }, + { "munlockall", 153 }, + { "munmap", 91 }, + { "name_to_handle_at", 341 }, + { "nanosleep", 162 }, + { "_newselect", 142 }, + { "newfstatat", __PNR_newfstatat }, + { "nfsservctl", 169 }, + { "nice", 34 }, + { "oldfstat", 28 }, + { "oldlstat", 84 }, + { "oldolduname", 59 }, + { "oldstat", 18 }, + { "olduname", 109 }, + { "open", 5 }, + { "open_by_handle_at", 342 }, + { "openat", 295 }, + { "pause", 29 }, + { "pciconfig_iobase", __PNR_pciconfig_iobase }, + { "pciconfig_read", __PNR_pciconfig_read }, + { "pciconfig_write", __PNR_pciconfig_write }, + { "perf_event_open", 336 }, + { "personality", 136 }, + { "pipe", 42 }, + { "pipe2", 331 }, + { "pivot_root", 217 }, + { "poll", 168 }, + { "ppoll", 309 }, + { "prctl", 172 }, + { "pread64", 180 }, + { "preadv", 333 }, + { "prlimit64", 340 }, + { "process_vm_readv", 347 }, + { "process_vm_writev", 348 }, + { "prof", 44 }, + { "profil", 98 }, + { "pselect6", 308 }, + { "ptrace", 26 }, + { "putpmsg", 189 }, + { "pwrite64", 181 }, + { "pwritev", 334 }, + { "query_module", 167 }, + { "quotactl", 131 }, + { "read", 3 }, + { "readahead", 225 }, + { "readdir", 89 }, + { "readlink", 85 }, + { "readlinkat", 305 }, + { "readv", 145 }, + { "reboot", 88 }, + { "recv", __PNR_recv }, + { "recvfrom", __PNR_recvfrom }, + { "recvmmsg", 337 }, + { "recvmsg", __PNR_recvmsg }, + { "remap_file_pages", 257 }, + { "removexattr", 235 }, + { "rename", 38 }, + { "renameat", 302 }, + { "request_key", 287 }, + { "restart_syscall", 0 }, + { "rmdir", 40 }, + { "rt_sigaction", 174 }, + { "rt_sigpending", 176 }, + { "rt_sigprocmask", 175 }, + { "rt_sigqueueinfo", 178 }, + { "rt_sigreturn", 173 }, + { "rt_sigsuspend", 179 }, + { "rt_sigtimedwait", 177 }, + { "rt_tgsigqueueinfo", 335 }, + { "sched_get_priority_max", 159 }, + { "sched_get_priority_min", 160 }, + { "sched_getaffinity", 242 }, + { "sched_getparam", 155 }, + { "sched_getscheduler", 157 }, + { "sched_rr_get_interval", 161 }, + { "sched_setaffinity", 241 }, + { "sched_setparam", 154 }, + { "sched_setscheduler", 156 }, + { "sched_yield", 158 }, + { "security", __PNR_security }, + { "select", 82 }, + { "semctl", __PNR_semctl }, + { "semget", __PNR_semget }, + { "semop", __PNR_semop }, + { "semtimedop", __PNR_semtimedop }, + { "send", __PNR_send }, + { "sendfile", 187 }, + { "sendfile64", 239 }, + { "sendmmsg", 345 }, + { "sendmsg", __PNR_sendmsg }, + { "sendto", __PNR_sendto }, + { "set_mempolicy", 276 }, + { "set_robust_list", 311 }, + { "set_thread_area", 243 }, + { "set_tid_address", 258 }, + { "setdomainname", 121 }, + { "setfsgid", 139 }, + { "setfsgid32", 216 }, + { "setfsuid", 138 }, + { "setfsuid32", 215 }, + { "setgid", 46 }, + { "setgid32", 214 }, + { "setgroups", 81 }, + { "setgroups32", 206 }, + { "sethostname", 74 }, + { "setitimer", 104 }, + { "setns", 346 }, + { "setpgid", 57 }, + { "setpriority", 97 }, + { "setregid", 71 }, + { "setregid32", 204 }, + { "setresgid", 170 }, + { "setresgid32", 210 }, + { "setresuid", 164 }, + { "setresuid32", 208 }, + { "setreuid", 70 }, + { "setreuid32", 203 }, + { "setrlimit", 75 }, + { "setsid", 66 }, + { "setsockopt", __PNR_setsockopt }, + { "settimeofday", 79 }, + { "setuid", 23 }, + { "setuid32", 213 }, + { "setxattr", 226 }, + { "sgetmask", 68 }, + { "shmat", __PNR_shmat }, + { "shmctl", __PNR_shmctl }, + { "shmdt", __PNR_shmdt }, + { "shmget", __PNR_shmget }, + { "shutdown", __PNR_shutdown }, + { "sigaction", 67 }, + { "sigaltstack", 186 }, + { "signal", 48 }, + { "signalfd", 321 }, + { "signalfd4", 327 }, + { "sigpending", 73 }, + { "sigprocmask", 126 }, + { "sigreturn", 119 }, + { "sigsuspend", 72 }, + { "socket", __PNR_socket }, + { "socketcall", 102 }, + { "socketpair", __PNR_socketpair }, + { "splice", 313 }, + { "ssetmask", 69 }, + { "stat", 106 }, + { "stat64", 195 }, + { "statfs", 99 }, + { "statfs64", 268 }, + { "stime", 25 }, + { "stty", 31 }, + { "swapoff", 115 }, + { "swapon", 87 }, + { "symlink", 83 }, + { "symlinkat", 304 }, + { "sync", 36 }, + { "sync_file_range", 314 }, + { "sync_file_range2", __PNR_sync_file_range2 }, + { "syncfs", 344 }, + { "syscall", __PNR_syscall }, + { "_sysctl", 149 }, + { "sysfs", 135 }, + { "sysinfo", 116 }, + { "syslog", 103 }, + { "tee", 315 }, + { "tgkill", 270 }, + { "time", 13 }, + { "timer_create", 259 }, + { "timer_delete", 263 }, + { "timer_getoverrun", 262 }, + { "timer_gettime", 261 }, + { "timer_settime", 260 }, + { "timerfd_create", 322 }, + { "timerfd_gettime", 326 }, + { "timerfd_settime", 325 }, + { "times", 43 }, + { "tkill", 238 }, + { "truncate", 92 }, + { "truncate64", 193 }, + { "tuxcall", __PNR_tuxcall }, + { "ugetrlimit", 191 }, + { "ulimit", 58 }, + { "umask", 60 }, + { "umount", 22 }, + { "umount2", 52 }, + { "uname", 122 }, + { "unlink", 10 }, + { "unlinkat", 301 }, + { "unshare", 310 }, + { "uselib", 86 }, + { "ustat", 62 }, + { "utime", 30 }, + { "utimensat", 320 }, + { "utimes", 271 }, + { "vfork", 190 }, + { "vhangup", 111 }, + { "vm86", 166 }, + { "vm86old", 113 }, + { "vmsplice", 316 }, + { "vserver", 273 }, + { "wait4", 114 }, + { "waitid", 284 }, + { "waitpid", 7 }, + { "write", 4 }, + { "writev", 146 }, + { NULL, __NR_SCMP_ERROR }, +}; + +/** + * Resolve a syscall name to a number + * @param name the syscall name + * + * Resolve the given syscall name to the syscall number using the syscall table. + * Returns the syscall number on success, including negative pseudo syscall + * numbers; returns __NR_SCMP_ERROR on failure. + * + */ +int x86_syscall_resolve_name(const char *name) +{ + unsigned int iter; + const struct arch_syscall_def *table = x86_syscall_table; + + /* XXX - plenty of room for future improvement here */ + for (iter = 0; table[iter].name != NULL; iter++) { + if (strcmp(name, table[iter].name) == 0) + return table[iter].num; + } + + return __NR_SCMP_ERROR; +} + +/** + * Resolve a syscall number to a name + * @param num the syscall number + * + * Resolve the given syscall number to the syscall name using the syscall table. + * Returns a pointer to the syscall name string on success, including pseudo + * syscall names; returns NULL on failure. + * + */ +const char *x86_syscall_resolve_num(int num) +{ + unsigned int iter; + const struct arch_syscall_def *table = x86_syscall_table; + + /* XXX - plenty of room for future improvement here */ + for (iter = 0; table[iter].num != __NR_SCMP_ERROR; iter++) { + if (num == table[iter].num) + return table[iter].name; + } + + return NULL; +} diff --git a/src/arch-x86.c b/src/arch-x86.c new file mode 100644 index 0000000..66e72dc --- /dev/null +++ b/src/arch-x86.c @@ -0,0 +1,112 @@ +/** + * Enhanced Seccomp x86 Specific Code + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include + +#include "arch.h" +#include "arch-x86.h" + +/* x86 syscall numbers */ +#define __x86_NR_socketcall 102 +#define __x86_NR_ipc 117 + +const struct arch_def arch_def_x86 = { + .token = SCMP_ARCH_X86, + .token_bpf = AUDIT_ARCH_I386, + .size = ARCH_SIZE_32, + .endian = ARCH_ENDIAN_LITTLE, +}; + +/** + * Rewrite a syscall value to match the architecture + * @param arch the architecture definition + * @param strict strict flag + * @param syscall the syscall number + * + * Syscalls can vary across different architectures so this function rewrites + * the syscall into the correct value for the specified architecture. If + * @strict is true then the function will fail if the syscall can not be + * preservered, however, if @strict is false the function will do a "best + * effort" rewrite and not fail. Returns zero on success, negative values on + * failure. + * + */ +int x86_syscall_rewrite(const struct arch_def *arch, bool strict, int *syscall) +{ + if ((*syscall) <= -100 && (*syscall) >= -117) + *syscall = __x86_NR_socketcall; + else if ((*syscall) <= -200 && (*syscall) >= -211) + *syscall = __x86_NR_ipc; + else if (((*syscall) < 0) && (strict)) + return -EDOM; + + return 0; +} + +/** + * Rewrite a filter rule to match the architecture specifics + * @param arch the architecture definition + * @param strict strict flag + * @param syscall the syscall number + * @param chain the argument filter chain + * + * Syscalls can vary across different architectures so this function handles + * the necessary seccomp rule rewrites to ensure the right thing is done + * regardless of the rule or architecture. If @strict is true then the + * function will fail if the entire filter can not be preservered, however, + * if @strict is false the function will do a "best effort" rewrite and not + * fail. Returns zero on success, negative values on failure. + * + */ +int x86_filter_rewrite(const struct arch_def *arch, bool strict, + int *syscall, struct db_api_arg *chain) +{ + unsigned int iter; + + if ((*syscall) <= -100 && (*syscall) >= -117) { + for (iter = 0; iter < x86_arg_count_max; iter++) { + if ((chain[iter].valid != 0) && (strict)) + return -EINVAL; + } + chain[0].arg = 0; + chain[0].op = SCMP_CMP_EQ; + chain[0].mask = DATUM_MAX; + chain[0].datum = abs(*syscall) % 100; + chain[0].valid = 1; + *syscall = __x86_NR_socketcall; + } else if ((*syscall) <= -200 && (*syscall) >= -211) { + for (iter = 0; iter < x86_arg_count_max; iter++) { + if ((chain[iter].valid != 0) && (strict)) + return -EINVAL; + } + chain[0].arg = 0; + chain[0].op = SCMP_CMP_EQ; + chain[0].mask = DATUM_MAX; + chain[0].datum = abs(*syscall) % 200; + chain[0].valid = 1; + *syscall = __x86_NR_ipc; + } else if (((*syscall) < 0) && (strict)) + return -EDOM; + + return 0; +} diff --git a/src/arch-x86.h b/src/arch-x86.h new file mode 100644 index 0000000..a399559 --- /dev/null +++ b/src/arch-x86.h @@ -0,0 +1,43 @@ +/** + * Enhanced Seccomp x86 Specific Code + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _ARCH_X86_H +#define _ARCH_X86_H + +#include + +#include "arch.h" +#include "db.h" +#include "system.h" + +#define x86_arg_count_max 6 + +extern const struct arch_def arch_def_x86; + +int x86_syscall_resolve_name(const char *name); +const char *x86_syscall_resolve_num(int num); + +int x86_syscall_rewrite(const struct arch_def *arch, bool strict, int *syscall); + +int x86_filter_rewrite(const struct arch_def *arch, bool strict, + int *syscall, struct db_api_arg *chain); + +#endif diff --git a/src/arch-x86_64-syscalls.c b/src/arch-x86_64-syscalls.c new file mode 100644 index 0000000..af095b8 --- /dev/null +++ b/src/arch-x86_64-syscalls.c @@ -0,0 +1,468 @@ +/** + * Enhanced Seccomp x86_64 Syscall Table + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "arch.h" +#include "arch-x86_64.h" + +/* NOTE: based on Linux 3.4.7 */ +const struct arch_syscall_def x86_64_syscall_table[] = { \ + { "accept", 43 }, + { "accept4", 288 }, + { "access", 21 }, + { "acct", 163 }, + { "add_key", 248 }, + { "adjtimex", 159 }, + { "afs_syscall", 183 }, + { "alarm", 37 }, + { "arm_fadvise64_64", __PNR_arm_fadvise64_64 }, + { "arm_sync_file_range", __PNR_arm_sync_file_range }, + { "arch_prctl", 158 }, + { "bdflush", __PNR_bdflush }, + { "bind", 49 }, + { "break", __PNR_break }, + { "brk", 12 }, + { "capget", 125 }, + { "capset", 126 }, + { "chdir", 80 }, + { "chmod", 90 }, + { "chown", 92 }, + { "chown32", __PNR_chown32 }, + { "chroot", 161 }, + { "clock_adjtime", 305 }, + { "clock_getres", 229 }, + { "clock_gettime", 228 }, + { "clock_nanosleep", 230 }, + { "clock_settime", 227 }, + { "clone", 56 }, + { "close", 3 }, + { "connect", 42 }, + { "creat", 85 }, + { "create_module", 174 }, + { "delete_module", 176 }, + { "dup", 32 }, + { "dup2", 33 }, + { "dup3", 292 }, + { "epoll_create", 213 }, + { "epoll_create1", 291 }, + { "epoll_ctl", 233 }, + { "epoll_ctl_old", 214 }, + { "epoll_pwait", 281 }, + { "epoll_wait", 232 }, + { "epoll_wait_old", 215 }, + { "eventfd", 284 }, + { "eventfd2", 290 }, + { "execve", 59 }, + { "exit", 60 }, + { "exit_group", 231 }, + { "faccessat", 269 }, + { "fadvise64", 221 }, + { "fadvise64_64", __PNR_fadvise64_64 }, + { "fallocate", 285 }, + { "fanotify_init", 300 }, + { "fanotify_mark", 301 }, + { "fchdir", 81 }, + { "fchmod", 91 }, + { "fchmodat", 268 }, + { "fchown", 93 }, + { "fchown32", __PNR_fchown32 }, + { "fchownat", 260 }, + { "fcntl", 72 }, + { "fcntl64", __PNR_fcntl64 }, + { "fdatasync", 75 }, + { "fgetxattr", 193 }, + { "finit_module", __PNR_finit_module }, + { "flistxattr", 196 }, + { "flock", 73 }, + { "fork", 57 }, + { "fremovexattr", 199 }, + { "fsetxattr", 190 }, + { "fstat", 5 }, + { "fstat64", __PNR_fstat64 }, + { "fstatat64", __PNR_fstatat64 }, + { "fstatfs", 138 }, + { "fstatfs64", __PNR_fstatfs64 }, + { "fsync", 74 }, + { "ftime", __PNR_ftime }, + { "ftruncate", 77 }, + { "ftruncate64", __PNR_ftruncate64 }, + { "futex", 202 }, + { "futimesat", 261 }, + { "get_kernel_syms", 177 }, + { "get_mempolicy", 239 }, + { "get_robust_list", 274 }, + { "get_thread_area", 211 }, + { "getcpu", 309 }, + { "getcwd", 79 }, + { "getdents", 78 }, + { "getdents64", 217 }, + { "getegid", 108 }, + { "getegid32", __PNR_getegid32 }, + { "geteuid", 107 }, + { "geteuid32", __PNR_geteuid32 }, + { "getgid", 104 }, + { "getgid32", __PNR_getgid32 }, + { "getgroups", 115 }, + { "getgroups32", __PNR_getgroups32 }, + { "getitimer", 36 }, + { "getpeername", 52 }, + { "getpgid", 121 }, + { "getpgrp", 111 }, + { "getpid", 39 }, + { "getpmsg", 181 }, + { "getppid", 110 }, + { "getpriority", 140 }, + { "getresgid", 120 }, + { "getresgid32", __PNR_getresgid32 }, + { "getresuid", 118 }, + { "getresuid32", __PNR_getresuid32 }, + { "getrlimit", 97 }, + { "getrusage", 98 }, + { "getsid", 124 }, + { "getsockname", 51 }, + { "getsockopt", 55 }, + { "gettid", 186 }, + { "gettimeofday", 96 }, + { "getuid", 102 }, + { "getuid32", __PNR_getuid32 }, + { "getxattr", 191 }, + { "gtty", __PNR_gtty }, + { "idle", __PNR_idle }, + { "init_module", 175 }, + { "inotify_add_watch", 254 }, + { "inotify_init", 253 }, + { "inotify_init1", 294 }, + { "inotify_rm_watch", 255 }, + { "io_cancel", 210 }, + { "io_destroy", 207 }, + { "io_getevents", 208 }, + { "io_setup", 206 }, + { "io_submit", 209 }, + { "ioctl", 16 }, + { "ioperm", 173 }, + { "iopl", 172 }, + { "ioprio_get", 252 }, + { "ioprio_set", 251 }, + { "ipc", __PNR_ipc }, + { "kcmp", 312 }, + { "kexec_load", 246 }, + { "keyctl", 250 }, + { "kill", 62 }, + { "lchown", 94 }, + { "lchown32", __PNR_lchown32 }, + { "lgetxattr", 192 }, + { "link", 86 }, + { "linkat", 265 }, + { "listen", 50 }, + { "listxattr", 194 }, + { "llistxattr", 195 }, + { "_llseek", __PNR__llseek }, + { "lock", __PNR_lock }, + { "lookup_dcookie", 212 }, + { "lremovexattr", 198 }, + { "lseek", 8 }, + { "lsetxattr", 189 }, + { "lstat", 6 }, + { "lstat64", __PNR_lstat64 }, + { "madvise", 28 }, + { "mbind", 237 }, + { "migrate_pages", 256 }, + { "mincore", 27 }, + { "mkdir", 83 }, + { "mkdirat", 258 }, + { "mknod", 133 }, + { "mknodat", 259 }, + { "mlock", 149 }, + { "mlockall", 151 }, + { "mmap", 9 }, + { "mmap2", __PNR_mmap2 }, + { "modify_ldt", 154 }, + { "mount", 165 }, + { "move_pages", 279 }, + { "mprotect", 10 }, + { "mpx", __PNR_mpx }, + { "mq_getsetattr", 245 }, + { "mq_notify", 244 }, + { "mq_open", 240 }, + { "mq_timedreceive", 243 }, + { "mq_timedsend", 242 }, + { "mq_unlink", 241 }, + { "mremap", 25 }, + { "msgctl", 71 }, + { "msgget", 68 }, + { "msgrcv", 70 }, + { "msgsnd", 69 }, + { "msync", 26 }, + { "munlock", 150 }, + { "munlockall", 152 }, + { "munmap", 11 }, + { "name_to_handle_at", 303 }, + { "nanosleep", 35 }, + { "_newselect", __PNR__newselect }, + { "newfstatat", 262 }, + { "nfsservctl", 180 }, + { "nice", __PNR_nice }, + { "oldfstat", __PNR_oldfstat }, + { "oldlstat", __PNR_oldlstat }, + { "oldolduname", __PNR_oldolduname }, + { "oldstat", __PNR_oldstat }, + { "olduname", __PNR_olduname }, + { "open", 2 }, + { "open_by_handle_at", 304 }, + { "openat", 257 }, + { "pause", 34 }, + { "pciconfig_iobase", __PNR_pciconfig_iobase }, + { "pciconfig_read", __PNR_pciconfig_read }, + { "pciconfig_write", __PNR_pciconfig_write }, + { "perf_event_open", 298 }, + { "personality", 135 }, + { "pipe", 22 }, + { "pipe2", 293 }, + { "pivot_root", 155 }, + { "poll", 7 }, + { "ppoll", 271 }, + { "prctl", 157 }, + { "pread64", 17 }, + { "preadv", 295 }, + { "prlimit64", 302 }, + { "process_vm_readv", 310 }, + { "process_vm_writev", 311 }, + { "prof", __PNR_prof }, + { "profil", __PNR_profil }, + { "pselect6", 270 }, + { "ptrace", 101 }, + { "putpmsg", 182 }, + { "pwrite64", 18 }, + { "pwritev", 296 }, + { "query_module", 178 }, + { "quotactl", 179 }, + { "read", 0 }, + { "readahead", 187 }, + { "readdir", __PNR_readdir }, + { "readlink", 89 }, + { "readlinkat", 267 }, + { "readv", 19 }, + { "reboot", 169 }, + { "recv", __PNR_recv }, + { "recvfrom", 45 }, + { "recvmmsg", 299 }, + { "recvmsg", 47 }, + { "remap_file_pages", 216 }, + { "removexattr", 197 }, + { "rename", 82 }, + { "renameat", 264 }, + { "request_key", 249 }, + { "restart_syscall", 219 }, + { "rmdir", 84 }, + { "rt_sigaction", 13 }, + { "rt_sigpending", 127 }, + { "rt_sigprocmask", 14 }, + { "rt_sigqueueinfo", 129 }, + { "rt_sigreturn", 15 }, + { "rt_sigsuspend", 130 }, + { "rt_sigtimedwait", 128 }, + { "rt_tgsigqueueinfo", 297 }, + { "sched_get_priority_max", 146 }, + { "sched_get_priority_min", 147 }, + { "sched_getaffinity", 204 }, + { "sched_getparam", 143 }, + { "sched_getscheduler", 145 }, + { "sched_rr_get_interval", 148 }, + { "sched_setaffinity", 203 }, + { "sched_setparam", 142 }, + { "sched_setscheduler", 144 }, + { "sched_yield", 24 }, + { "security", 185 }, + { "select", 23 }, + { "semctl", 66 }, + { "semget", 64 }, + { "semop", 65 }, + { "semtimedop", 220 }, + { "send", __PNR_send }, + { "sendfile", 40 }, + { "sendfile64", __PNR_sendfile64 }, + { "sendmmsg", 307 }, + { "sendmsg", 46 }, + { "sendto", 44 }, + { "set_mempolicy", 238 }, + { "set_robust_list", 273 }, + { "set_thread_area", 205 }, + { "set_tid_address", 218 }, + { "setdomainname", 171 }, + { "setfsgid", 123 }, + { "setfsgid32", __PNR_setfsgid32 }, + { "setfsuid", 122 }, + { "setfsuid32", __PNR_setfsuid32 }, + { "setgid", 106 }, + { "setgid32", __PNR_setgid32 }, + { "setgroups", 116 }, + { "setgroups32", __PNR_setgroups32 }, + { "sethostname", 170 }, + { "setitimer", 38 }, + { "setns", 308 }, + { "setpgid", 109 }, + { "setpriority", 141 }, + { "setregid", 114 }, + { "setregid32", __PNR_setregid32 }, + { "setresgid", 119 }, + { "setresgid32", __PNR_setresgid32 }, + { "setresuid", 117 }, + { "setresuid32", __PNR_setresuid32 }, + { "setreuid", 113 }, + { "setreuid32", __PNR_setreuid32 }, + { "setrlimit", 160 }, + { "setsid", 112 }, + { "setsockopt", 54 }, + { "settimeofday", 164 }, + { "setuid", 105 }, + { "setuid32", __PNR_setuid32 }, + { "setxattr", 188 }, + { "sgetmask", __PNR_sgetmask }, + { "shmat", 30 }, + { "shmctl", 31 }, + { "shmdt", 67 }, + { "shmget", 29 }, + { "shutdown", 48 }, + { "sigaction", __PNR_sigaction }, + { "sigaltstack", 131 }, + { "signal", __PNR_signal }, + { "signalfd", 282 }, + { "signalfd4", 289 }, + { "sigpending", __PNR_sigpending }, + { "sigprocmask", __PNR_sigprocmask }, + { "sigreturn", __PNR_sigreturn }, + { "sigsuspend", __PNR_sigsuspend }, + { "socket", 41 }, + { "socketcall", __PNR_socketcall }, + { "socketpair", 53 }, + { "splice", 275 }, + { "ssetmask", __PNR_ssetmask }, + { "stat", 4 }, + { "stat64", __PNR_stat64 }, + { "statfs", 137 }, + { "statfs64", __PNR_statfs64 }, + { "stime", __PNR_stime }, + { "stty", __PNR_stty }, + { "swapoff", 168 }, + { "swapon", 167 }, + { "symlink", 88 }, + { "symlinkat", 266 }, + { "sync", 162 }, + { "sync_file_range", 277 }, + { "sync_file_range2", __PNR_sync_file_range2 }, + { "syncfs", 306 }, + { "syscall", __PNR_syscall }, + { "_sysctl", 156 }, + { "sysfs", 139 }, + { "sysinfo", 99 }, + { "syslog", 103 }, + { "tee", 276 }, + { "tgkill", 234 }, + { "time", 201 }, + { "timer_create", 222 }, + { "timer_delete", 226 }, + { "timer_getoverrun", 225 }, + { "timer_gettime", 224 }, + { "timer_settime", 223 }, + { "timerfd_create", 283 }, + { "timerfd_gettime", 287 }, + { "timerfd_settime", 286 }, + { "times", 100 }, + { "tkill", 200 }, + { "truncate", 76 }, + { "truncate64", __PNR_truncate64 }, + { "tuxcall", 184 }, + { "ugetrlimit", __PNR_ugetrlimit }, + { "ulimit", __PNR_ulimit }, + { "umask", 95 }, + { "umount", __PNR_umount }, + { "umount2", 166 }, + { "uname", 63 }, + { "unlink", 87 }, + { "unlinkat", 263 }, + { "unshare", 272 }, + { "uselib", 134 }, + { "ustat", 136 }, + { "utime", 132 }, + { "utimensat", 280 }, + { "utimes", 235 }, + { "vfork", 58 }, + { "vhangup", 153 }, + { "vm86", __PNR_vm86 }, + { "vm86old", __PNR_vm86old }, + { "vmsplice", 278 }, + { "vserver", 236 }, + { "wait4", 61 }, + { "waitid", 247 }, + { "waitpid", __PNR_waitpid }, + { "write", 1 }, + { "writev", 20 }, + { NULL, __NR_SCMP_ERROR }, +}; + +/** + * Resolve a syscall name to a number + * @param name the syscall name + * + * Resolve the given syscall name to the syscall number using the syscall table. + * Returns the syscall number on success, including negative pseudo syscall + * numbers; returns __NR_SCMP_ERROR on failure. + * + */ +int x86_64_syscall_resolve_name(const char *name) +{ + unsigned int iter; + const struct arch_syscall_def *table = x86_64_syscall_table; + + /* XXX - plenty of room for future improvement here */ + for (iter = 0; table[iter].name != NULL; iter++) { + if (strcmp(name, table[iter].name) == 0) + return table[iter].num; + } + + return __NR_SCMP_ERROR; +} + +/** + * Resolve a syscall number to a name + * @param num the syscall number + * + * Resolve the given syscall number to the syscall name using the syscall table. + * Returns a pointer to the syscall name string on success, including pseudo + * syscall names; returns NULL on failure. + * + */ +const char *x86_64_syscall_resolve_num(int num) +{ + unsigned int iter; + const struct arch_syscall_def *table = x86_64_syscall_table; + + /* XXX - plenty of room for future improvement here */ + for (iter = 0; table[iter].num != __NR_SCMP_ERROR; iter++) { + if (num == table[iter].num) + return table[iter].name; + } + + return NULL; +} diff --git a/src/arch-x86_64.c b/src/arch-x86_64.c new file mode 100644 index 0000000..55656c2 --- /dev/null +++ b/src/arch-x86_64.c @@ -0,0 +1,34 @@ +/** + * Enhanced Seccomp x86_64 Specific Code + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include + +#include "arch.h" +#include "arch-x86_64.h" + +const struct arch_def arch_def_x86_64 = { + .token = SCMP_ARCH_X86_64, + .token_bpf = AUDIT_ARCH_X86_64, + .size = ARCH_SIZE_64, + .endian = ARCH_ENDIAN_LITTLE, +}; diff --git a/src/arch-x86_64.h b/src/arch-x86_64.h new file mode 100644 index 0000000..cc1c6bf --- /dev/null +++ b/src/arch-x86_64.h @@ -0,0 +1,40 @@ +/** + * Enhanced Seccomp x86_64 Specific Code + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _ARCH_x86_64_H +#define _ARCH_x86_64_H + +#include + +#include "arch.h" +#include "system.h" + +#define x86_64_arg_count_max 6 + +extern const struct arch_def arch_def_x86_64; + +#define x86_64_arg_offset_lo(x) (arch_arg_offset(x)) +#define x86_64_arg_offset_hi(x) (arch_arg_offset(x) + 4) + +int x86_64_syscall_resolve_name(const char *name); +const char *x86_64_syscall_resolve_num(int num); + +#endif diff --git a/src/arch.c b/src/arch.c new file mode 100644 index 0000000..47a539d --- /dev/null +++ b/src/arch.c @@ -0,0 +1,322 @@ +/** + * Enhanced Seccomp Architecture/Machine Specific Code + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "arch.h" +#include "arch-x86.h" +#include "arch-x86_64.h" +#include "arch-x32.h" +#include "arch-arm.h" +#include "system.h" + +#if __i386__ +const struct arch_def *arch_def_native = &arch_def_x86; +#elif __x86_64__ +#ifdef __ILP32__ +const struct arch_def *arch_def_native = &arch_def_x32; +#else +const struct arch_def *arch_def_native = &arch_def_x86_64; +#endif /* __ILP32__ */ +#elif __arm__ +const struct arch_def *arch_def_native = &arch_def_arm; +#else +#error the arch code needs to know about your machine type +#endif /* machine type guess */ + +/** + * Validate the architecture token + * @param arch the architecture token + * + * Verify the given architecture token; return zero if valid, -EINVAL if not. + * + */ +int arch_valid(uint32_t arch) +{ + switch (arch) { + case SCMP_ARCH_X86: + case SCMP_ARCH_X86_64: + case SCMP_ARCH_X32: + case SCMP_ARCH_ARM: + return 0; + } + + return -EINVAL; +} + +/** + * Lookup the architecture definition + * @param token the architecure token + * + * Return the matching architecture definition, returns NULL on failure. + * + */ +const struct arch_def *arch_def_lookup(uint32_t token) +{ + switch (token) { + case SCMP_ARCH_X86: + return &arch_def_x86; + case SCMP_ARCH_X86_64: + return &arch_def_x86_64; + case SCMP_ARCH_X32: + return &arch_def_x32; + case SCMP_ARCH_ARM: + return &arch_def_arm; + } + + return NULL; +} + +/** + * Determine the maximum number of syscall arguments + * @param arch the architecture definition + * + * Determine the maximum number of syscall arguments for the given architecture. + * Returns the number of arguments on success, negative values on failure. + * + */ +int arch_arg_count_max(const struct arch_def *arch) +{ + switch (arch->token) { + case SCMP_ARCH_X86: + return x86_arg_count_max; + case SCMP_ARCH_X86_64: + return x86_64_arg_count_max; + case SCMP_ARCH_X32: + return x32_arg_count_max; + case SCMP_ARCH_ARM: + return arm_arg_count_max; + } + + return -EDOM; +} + +/** + * Determine the argument offset for the lower 32 bits + * @param arch the architecture definition + * @param arg the argument number + * + * Determine the correct offset for the low 32 bits of the given argument based + * on the architecture definition. Returns the offset on success, negative + * values on failure. + * + */ +int arch_arg_offset_lo(const struct arch_def *arch, unsigned int arg) +{ + switch (arch->token) { + case SCMP_ARCH_X86_64: + return x86_64_arg_offset_lo(arg); + default: + return -EDOM; + } +} + +/** + * Determine the argument offset for the high 32 bits + * @param arch the architecture definition + * @param arg the argument number + * + * Determine the correct offset for the high 32 bits of the given argument + * based on the architecture definition. Returns the offset on success, + * negative values on failure. + * + */ +int arch_arg_offset_hi(const struct arch_def *arch, unsigned int arg) +{ + switch (arch->token) { + case SCMP_ARCH_X86_64: + return x86_64_arg_offset_hi(arg); + default: + return -EDOM; + } +} + +/** + * Resolve a syscall name to a number + * @param arch the architecture definition + * @param name the syscall name + * + * Resolve the given syscall name to the syscall number based on the given + * architecture. Returns the syscall number on success, including negative + * pseudo syscall numbers; returns __NR_SCMP_ERROR on failure. + * + */ +int arch_syscall_resolve_name(const struct arch_def *arch, const char *name) +{ + switch (arch->token) { + case SCMP_ARCH_X86: + return x86_syscall_resolve_name(name); + case SCMP_ARCH_X86_64: + return x86_64_syscall_resolve_name(name); + case SCMP_ARCH_X32: + return x32_syscall_resolve_name(name); + case SCMP_ARCH_ARM: + return arm_syscall_resolve_name(name); + } + + return __NR_SCMP_ERROR; +} + +/** + * Resolve a syscall number to a name + * @param arch the architecture definition + * @param num the syscall number + * + * Resolve the given syscall number to the syscall name based on the given + * architecture. Returns a pointer to the syscall name string on success, + * including pseudo syscall names; returns NULL on failure. + * + */ +const char *arch_syscall_resolve_num(const struct arch_def *arch, int num) +{ + switch (arch->token) { + case SCMP_ARCH_X86: + return x86_syscall_resolve_num(num); + case SCMP_ARCH_X86_64: + return x86_64_syscall_resolve_num(num); + case SCMP_ARCH_X32: + return x32_syscall_resolve_num(num); + case SCMP_ARCH_ARM: + return arm_syscall_resolve_num(num); + } + + return NULL; +} + +/** + * Translate the syscall number + * @param arch the architecture definition + * @param syscall the syscall number + * + * Translate the syscall number, in the context of the native architecure, to + * the provided architecure. Returns zero on success, negative values on + * failure. + * + */ +int arch_syscall_translate(const struct arch_def *arch, int *syscall) +{ + int sc_num; + const char *sc_name; + + if (arch->token != arch_def_native->token) { + sc_name = arch_syscall_resolve_num(arch_def_native, *syscall); + if (sc_name == NULL) + return -EFAULT; + + sc_num = arch_syscall_resolve_name(arch, sc_name); + if (sc_num == __NR_SCMP_ERROR) + return -EFAULT; + + *syscall = sc_num; + } + + return 0; +} + +/** + * Rewrite a syscall value to match the architecture + * @param arch the architecture definition + * @param strict strict flag + * @param syscall the syscall number + * + * Syscalls can vary across different architectures so this function rewrites + * the syscall into the correct value for the specified architecture. If + * @strict is true then the function will fail if the syscall can not be + * preservered, however, if @strict is false the function will do a "best + * effort" rewrite and not fail. Returns zero on success, negative values on + * failure. + * + */ +int arch_syscall_rewrite(const struct arch_def *arch, bool strict, int *syscall) +{ + int sys = *syscall; + + if (sys >= 0) { + /* we shouldn't be here - no rewrite needed */ + return 0; + } else if (sys < 0 && sys > -100) { + /* reserved values */ + return -EINVAL; + } else if (sys <= -100 && sys > -10000) { + /* rewritable syscalls */ + switch (arch->token) { + case SCMP_ARCH_X86: + return x86_syscall_rewrite(arch, strict, syscall); + } + /* NOTE: we fall through to the default handling (strict?) if + * we don't support any rewriting for the architecture */ + } + + /* syscalls not defined on this architecture */ + if (strict) + return -EDOM; + return 0; +} + +/** + * Rewrite a filter rule to match the architecture specifics + * @param arch the architecture definition + * @param strict strict flag + * @param syscall the syscall number + * @param chain the argument filter chain + * + * Syscalls can vary across different architectures so this function handles + * the necessary seccomp rule rewrites to ensure the right thing is done + * regardless of the rule or architecture. If @strict is true then the + * function will fail if the entire filter can not be preservered, however, + * if @strict is false the function will do a "best effort" rewrite and not + * fail. Returns zero on success, negative values on failure. + * + */ +int arch_filter_rewrite(const struct arch_def *arch, + bool strict, int *syscall, struct db_api_arg *chain) +{ + int sys = *syscall; + + if (sys >= 0) { + /* we shouldn't be here - no rewrite needed */ + return 0; + } else if (sys < 0 && sys > -100) { + /* reserved values */ + return -EINVAL; + } else if (sys <= -100 && sys > -10000) { + /* rewritable syscalls */ + switch (arch->token) { + case SCMP_ARCH_X86: + return x86_filter_rewrite(arch, strict, syscall, chain); + } + /* NOTE: we fall through to the default handling (strict?) if + * we don't support any rewriting for the architecture */ + } + + /* syscalls not defined on this architecture */ + if (strict) + return -EDOM; + return 0; +} diff --git a/src/arch.h b/src/arch.h new file mode 100644 index 0000000..5c4249f --- /dev/null +++ b/src/arch.h @@ -0,0 +1,106 @@ +/** + * Enhanced Seccomp Architecture/Machine Specific Code + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _ARCH_H +#define _ARCH_H + +#include +#include +#include + +#include + +#include "system.h" + +struct db_api_arg; + +struct arch_def { + uint32_t token; + uint32_t token_bpf; + enum { + ARCH_SIZE_UNSPEC = 0, + ARCH_SIZE_32 = 32, + ARCH_SIZE_64 = 64, + } size; + enum { + ARCH_ENDIAN_UNSPEC = 0, + ARCH_ENDIAN_LITTLE, + ARCH_ENDIAN_BIG, + } endian; +}; + +/* arch_def for the current architecture */ +extern const struct arch_def *arch_def_native; + +/* NOTE: Syscall mappings can be found by running the following commands + * on the specific architecture's include file: + * # gcc -E -dM | grep '__NR_' + * where in many cases is /usr/include/asm/unistd.h, however, + * depending on the architecture you may need to use a different header. + * Further, you can automatically format this list for use as a struct + * initializer with the following command: + * # gcc -E -dM | grep '__NR_' | \ + * sed -e 's/#define[ \t]\+__NR_//' | sort | \ + * sed -e 's/\([^ \t]\+\)\([ \t]\+\)\([0-9]\+\)/\t{ \"\1\", \3 },/' + * Finally, when creating a table/array of this structure, the final + * sentinel entry should be "{ NULL, __NR_SCMP_ERROR }"; see the existing + * tables as an example. + */ +struct arch_syscall_def { + const char *name; + unsigned int num; +}; + +#define DATUM_MAX ((scmp_datum_t)-1) +#define D64_LO(x) ((uint32_t)((uint64_t)(x) & 0x00000000ffffffff)) +#define D64_HI(x) ((uint32_t)((uint64_t)(x) >> 32)) + +#define ARG_COUNT_MAX 6 + +int arch_valid(uint32_t arch); + +const struct arch_def *arch_def_lookup(uint32_t token); + +int arch_arg_count_max(const struct arch_def *arch); + +/** + * Determine the argument offset + * @param _arg the argument number + * + * Return the correct offset of the given argument. + * + */ +#define arch_arg_offset(_arg) (offsetof(struct seccomp_data, args[_arg])) + +int arch_arg_offset_lo(const struct arch_def *arch, unsigned int arg); +int arch_arg_offset_hi(const struct arch_def *arch, unsigned int arg); + +int arch_syscall_resolve_name(const struct arch_def *arch, const char *name); +const char *arch_syscall_resolve_num(const struct arch_def *arch, int num); + +int arch_syscall_translate(const struct arch_def *arch, int *syscall); +int arch_syscall_rewrite(const struct arch_def *arch, bool strict, + int *syscall); + +int arch_filter_rewrite(const struct arch_def *arch, + bool strict, int *syscall, struct db_api_arg *chain); + +#endif diff --git a/src/db.c b/src/db.c new file mode 100644 index 0000000..345a654 --- /dev/null +++ b/src/db.c @@ -0,0 +1,1314 @@ +/** + * Enhanced Seccomp Filter DB + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "arch.h" +#include "db.h" + +/* state values */ +#define _DB_STA_VALID 0xA1B2C3D4 +#define _DB_STA_FREED 0x1A2B3C4D + +/* the priority field is fairly simple - without any user hints, or in the case + * of a hint "tie", we give higher priority to syscalls with less chain nodes + * (filter is easier to evaluate) */ +#define _DB_PRI_MASK_CHAIN 0x0000FFFF +#define _DB_PRI_MASK_USER 0x00FF0000 +#define _DB_PRI_USER(x) (((x) << 16) & _DB_PRI_MASK_USER) + +/* private structure for tracking the state of the sub-tree "pruning" */ +struct db_prune_state { + bool prefix_exist; + bool prefix_new; + bool matched; +}; + +static unsigned int _db_tree_free(struct db_arg_chain_tree *tree); + +/** + * Do not call this function directly, use _db_tree_free() instead + */ +static unsigned int __db_tree_free(struct db_arg_chain_tree *tree) +{ + int cnt; + + if (tree == NULL || --(tree->refcnt) > 0) + return 0; + + /* we assume the caller has ensured that 'tree->lvl_prv == NULL' */ + cnt = __db_tree_free(tree->lvl_nxt); + cnt += _db_tree_free(tree->nxt_t); + cnt += _db_tree_free(tree->nxt_f); + + free(tree); + return cnt + 1; +} + +/** + * Free a syscall filter argument chain tree + * @param list the argument chain list + * + * This function frees a syscall argument chain list and returns the number of + * nodes freed. + * + */ +static unsigned int _db_tree_free(struct db_arg_chain_tree *tree) +{ + struct db_arg_chain_tree *iter; + + if (tree == NULL) + return 0; + + iter = tree; + while (iter->lvl_prv != NULL) + iter = iter->lvl_prv; + + return __db_tree_free(iter); +} + +/** + * Remove a node from an argument chain tree + * @param tree the pointer to the tree + * @param node the node to remove + * + * This function searches the tree looking for the node and removes it once + * found. Returns the number of nodes freed. + * + */ +static unsigned int _db_tree_remove(struct db_arg_chain_tree **tree, + struct db_arg_chain_tree *node) +{ + int cnt = 0; + struct db_arg_chain_tree *c_iter; + + if (tree == NULL || *tree == NULL || node == NULL) + return 0; + + c_iter = *tree; + while (c_iter->lvl_prv != NULL) + c_iter = c_iter->lvl_prv; + + do { + if (c_iter == node || db_chain_zombie(c_iter)) { + /* remove from the tree */ + if (c_iter == *tree) { + if (c_iter->lvl_prv != NULL) + *tree = c_iter->lvl_prv; + else + *tree = c_iter->lvl_nxt; + } + if (c_iter->lvl_prv != NULL) + c_iter->lvl_prv->lvl_nxt = c_iter->lvl_nxt; + if (c_iter->lvl_nxt != NULL) + c_iter->lvl_nxt->lvl_prv = c_iter->lvl_prv; + + /* free and return */ + c_iter->lvl_prv = NULL; + c_iter->lvl_nxt = NULL; + cnt += _db_tree_free(c_iter); + return cnt; + } + + /* check the true/false sub-trees */ + cnt += _db_tree_remove(&(c_iter->nxt_t), node); + cnt += _db_tree_remove(&(c_iter->nxt_f), node); + + c_iter = c_iter->lvl_nxt; + } while (c_iter != NULL); + + return cnt; +} + +/** + * Traverse a tree checking the action values + * @param tree the pointer to the tree + * @param action the action + * + * Traverse the tree inspecting each action to see if it matches the given + * action. Returns zero if all actions match the given action, negative values + * on failure. + * + */ +static int _db_tree_act_check(struct db_arg_chain_tree *tree, uint32_t action) +{ + int rc; + struct db_arg_chain_tree *c_iter; + + if (tree == NULL) + return 0; + + c_iter = tree; + while (c_iter->lvl_prv != NULL) + c_iter = c_iter->lvl_prv; + + do { + if (c_iter->act_t_flg && c_iter->act_t != action) + return -EEXIST; + if (c_iter->act_f_flg && c_iter->act_f != action) + return -EEXIST; + + rc = _db_tree_act_check(c_iter->nxt_t, action); + if (rc < 0) + return rc; + rc = _db_tree_act_check(c_iter->nxt_f, action); + if (rc < 0) + return rc; + + c_iter = c_iter->lvl_nxt; + } while (c_iter != NULL); + + return 0; +} + +/** + * Checks for a sub-tree match in an existing tree and prunes the tree + * @param prev the head of the existing tree or sub-tree + * @param existing the starting point into the existing tree + * @param new pointer to the new tree + * @param state pointer to the pruning state + * + * This function searches the existing and new trees trying to prune each to + * eliminate redundancy. Returns the number of nodes removed from the tree on + * success, zero if no changes were made, and negative values if the new tree + * should be discarded. + * + */ +static int _db_tree_sub_prune(struct db_arg_chain_tree **prev, + struct db_arg_chain_tree *existing, + struct db_arg_chain_tree *new, + struct db_prune_state *state) +{ + int rc = 0; + int rc_tmp; + struct db_arg_chain_tree *ec_iter; + struct db_arg_chain_tree *ec_iter_tmp; + struct db_arg_chain_tree *c_iter; + struct db_prune_state state_new; + + if (!state || !existing || !new) + return 0; + + ec_iter = existing; + c_iter = new; + do { + if (db_chain_eq(ec_iter, c_iter)) { + /* equal */ + + if (db_chain_leaf(c_iter)) { + /* leaf */ + if (db_chain_eq_result(ec_iter, c_iter)) { + /* identical results */ + if (prev != NULL) + return _db_tree_remove(prev, + ec_iter); + else + return -1; + } + if (c_iter->act_t_flg && ec_iter->nxt_t) { + /* new is shorter (true) */ + if (prev == NULL) + return -1; + rc += _db_tree_remove(&(ec_iter->nxt_t), + ec_iter->nxt_t); + ec_iter->act_t = c_iter->act_t; + ec_iter->act_t_flg = true; + } + if (c_iter->act_f_flg && ec_iter->nxt_f) { + /* new is shorter (false) */ + if (prev == NULL) + return -1; + rc += _db_tree_remove(&(ec_iter->nxt_f), + ec_iter->nxt_f); + ec_iter->act_f = c_iter->act_f; + ec_iter->act_f_flg = true; + } + + return rc; + } + + if (c_iter->nxt_t && ec_iter->act_t_flg) + /* existing is shorter (true) */ + return -1; + if (c_iter->nxt_f && ec_iter->act_f_flg) + /* existing is shorter (false) */ + return -1; + + if (c_iter->nxt_t) { + state_new = *state; + state_new.matched = true; + rc_tmp = _db_tree_sub_prune((prev ? + &ec_iter : NULL), + ec_iter->nxt_t, + c_iter->nxt_t, + &state_new); + rc += (rc_tmp > 0 ? rc_tmp : 0); + if (state->prefix_new && rc_tmp < 0) + return (rc > 0 ? rc : rc_tmp); + } + if (c_iter->nxt_f) { + state_new = *state; + state_new.matched = true; + rc_tmp = _db_tree_sub_prune((prev ? + &ec_iter : NULL), + ec_iter->nxt_f, + c_iter->nxt_f, + &state_new); + rc += (rc_tmp > 0 ? rc_tmp : 0); + if (state->prefix_new && rc_tmp < 0) + return (rc > 0 ? rc : rc_tmp); + } + } else if (db_chain_lt(ec_iter, c_iter)) { + /* less than */ + if (state->matched || state->prefix_new) + goto next; + state_new = *state; + state_new.prefix_exist = true; + + if (ec_iter->nxt_t) { + rc_tmp = _db_tree_sub_prune((prev ? + &ec_iter : NULL), + ec_iter->nxt_t, + c_iter, + &state_new); + rc += (rc_tmp > 0 ? rc_tmp : 0); + } + if (ec_iter->nxt_f) { + rc_tmp = _db_tree_sub_prune((prev ? + &ec_iter : NULL), + ec_iter->nxt_f, + c_iter, + &state_new); + rc += (rc_tmp > 0 ? rc_tmp : 0); + } + } else if (db_chain_gt(ec_iter, c_iter)) { + /* greater than */ + if (state->matched || state->prefix_exist) + goto next; + state_new = *state; + state_new.prefix_new = true; + + if (c_iter->nxt_t) { + rc_tmp = _db_tree_sub_prune(NULL, + ec_iter, + c_iter->nxt_t, + &state_new); + rc += (rc_tmp > 0 ? rc_tmp : 0); + if (rc_tmp < 0) + return (rc > 0 ? rc : rc_tmp); + } + if (c_iter->nxt_f) { + rc_tmp = _db_tree_sub_prune(NULL, + ec_iter, + c_iter->nxt_f, + &state_new); + rc += (rc_tmp > 0 ? rc_tmp : 0); + if (rc_tmp < 0) + return (rc > 0 ? rc : rc_tmp); + } + } + +next: + /* re-check current node and advance to the next node */ + if (db_chain_zombie(ec_iter)) { + ec_iter_tmp = ec_iter->lvl_nxt; + rc += _db_tree_remove(prev, ec_iter); + ec_iter = ec_iter_tmp; + } else + ec_iter = ec_iter->lvl_nxt; + } while (ec_iter); + + return rc; +} + +/** + * Validate the seccomp action + * @param action the seccomp action + * + * Verify that the given action is a valid seccomp action; return zero if + * valid, -EINVAL if invalid. + */ +int db_action_valid(uint32_t action) +{ + if (action == SCMP_ACT_KILL) + return 0; + else if (action == SCMP_ACT_TRAP) + return 0; + else if (action == SCMP_ACT_ERRNO(action & 0x0000ffff)) + return 0; + else if (action == SCMP_ACT_TRACE(action & 0x0000ffff)) + return 0; + else if (action == SCMP_ACT_ALLOW) + return 0; + + return -EINVAL; +} + +/** + * Free and reset the seccomp filter collection + * @param col the seccomp filter collection + * @param def_action the default filter action + * + * This function frees any existing filter DBs and resets the collection to a + * default state. + * + */ +void db_col_reset(struct db_filter_col *col, uint32_t def_action) +{ + unsigned int iter; + + if (col == NULL) + return; + + /* free any filters */ + for (iter = 0; iter < col->filter_cnt; iter++) + db_release(col->filters[iter]); + col->filter_cnt = 0; + free(col->filters); + col->filters = NULL; + + /* set the default attribute values */ + col->attr.act_default = def_action; + col->attr.act_badarch = SCMP_ACT_KILL; + col->attr.nnp_enable = 1; + + /* set the state */ + col->state = _DB_STA_VALID; +} + +/** + * Intitalize a seccomp filter collection + * @param def_action the default filter action + * + * This function initializes a seccomp filter collection and readies it for + * use. Returns a pointer to the collection on success, NULL on failure. + * + */ +struct db_filter_col *db_col_init(uint32_t def_action) +{ + struct db_filter_col *col; + + col = malloc(sizeof(*col)); + if (col == NULL) + return NULL; + + /* clear the buffer for the first time */ + memset(col, 0, sizeof(*col)); + + /* reset the DB to a known state */ + db_col_reset(col, def_action); + + return col; +} + +/** + * Destroy a seccomp filter collection + * @param col the seccomp filter collection + * + * This function destroys a seccomp filter collection. After calling this + * function, the filter should no longer be referenced. + * + */ +void db_col_release(struct db_filter_col *col) +{ + if (col == NULL) + return; + + /* set the state, just in case */ + col->state = _DB_STA_FREED; + + /* free and reset the DB */ + db_col_reset(col, 0); + free(col); +} + +/** + * Validate a filter collection + * @param col the seccomp filter collection + * + * This function validates a seccomp filter collection. Returns zero if the + * collection is valid, negative values on failure. + * + */ +int db_col_valid(struct db_filter_col *col) +{ + if (col != NULL && col->state == _DB_STA_VALID) + return 0; + return -EINVAL; +} + +/** + * Merge two filter collections + * @param col_dst the destination filter collection + * @param col_src the source filter collection + * + * This function merges two filter collections into the given destination + * collection. The source filter collection is no longer valid if the function + * returns successfully. Returns zero on success, negative values on failure. + * + */ +int db_col_merge(struct db_filter_col *col_dst, struct db_filter_col *col_src) +{ + unsigned int iter_a, iter_b; + struct db_filter **dbs; + + /* make sure we don't have any arch/filter collisions */ + for (iter_a = 0; iter_a < col_dst->filter_cnt; iter_a++) { + for (iter_b = 0; iter_b < col_src->filter_cnt; iter_b++) { + if (col_dst->filters[iter_a]->arch->token == + col_src->filters[iter_b]->arch->token) + return -EEXIST; + } + } + + /* expand the destination */ + dbs = realloc(col_dst->filters, + sizeof(struct db_filter *) * + (col_dst->filter_cnt + col_src->filter_cnt)); + if (dbs == NULL) + return -ENOMEM; + col_dst->filters = dbs; + + /* transfer the architecture filters */ + for (iter_a = col_dst->filter_cnt, iter_b = 0; + iter_b < col_src->filter_cnt; iter_a++, iter_b++) { + col_dst->filters[iter_a] = col_src->filters[iter_b]; + col_dst->filter_cnt++; + } + + /* free the source */ + col_src->filter_cnt = 0; + db_col_release(col_src); + + return 0; +} + +/** + * Check to see if an architecture filter exists in the filter collection + * @param col the seccomp filter collection + * @param arch_token the architecture token + * + * Iterate through the given filter collection checking to see if a filter + * exists for the specified architecture. Returns -EEXIST if a filter is found, + * zero if a matching filter does not exist. + * + */ +int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token) +{ + unsigned int iter; + + for (iter = 0; iter < col->filter_cnt; iter++) + if (col->filters[iter]->arch->token == arch_token) + return -EEXIST; + + return 0; +} + +/** + * Get a filter attribute + * @param col the seccomp filter collection + * @param attr the filter attribute + * @param value the filter attribute value + * + * Get the requested filter attribute and provide it via @value. Returns zero + * on success, negative values on failure. + * + */ +int db_col_attr_get(const struct db_filter_col *col, + enum scmp_filter_attr attr, uint32_t *value) +{ + int rc = 0; + + switch (attr) { + case SCMP_FLTATR_ACT_DEFAULT: + *value = col->attr.act_default; + break; + case SCMP_FLTATR_ACT_BADARCH: + *value = col->attr.act_badarch; + break; + case SCMP_FLTATR_CTL_NNP: + *value = col->attr.nnp_enable; + break; + default: + rc = -EEXIST; + break; + } + + return rc; +} + +/** + * Set a filter attribute + * @param db the seccomp filter collection + * @param attr the filter attribute + * @param value the filter attribute value + * + * Set the requested filter attribute with the given value. Returns zero on + * success, negative values on failure. + * + */ +int db_col_attr_set(struct db_filter_col *col, + enum scmp_filter_attr attr, uint32_t value) +{ + int rc = 0; + + switch (attr) { + case SCMP_FLTATR_ACT_DEFAULT: + /* read only */ + return -EACCES; + break; + case SCMP_FLTATR_ACT_BADARCH: + if (db_action_valid(value) == 0) + col->attr.act_badarch = value; + else + return -EINVAL; + break; + case SCMP_FLTATR_CTL_NNP: + col->attr.nnp_enable = (value ? 1 : 0); + break; + default: + rc = -EEXIST; + break; + } + + return rc; +} + +/** + * Add a new filter DB to a filter collection + * @param col the seccomp filter collection + * @param db the seccomp filter DB + * + * This function adds an existing seccomp filter DB to an existing seccomp + * filter collection assuming there isn't a filter DB already present with the + * same architecture. Returns zero on success, negative values on failure. + * + */ +int db_col_db_add(struct db_filter_col *col, struct db_filter *db) +{ + struct db_filter **dbs; + + if (db_col_arch_exist(col, db->arch->token)) + return -EEXIST; + + dbs = realloc(col->filters, + sizeof(struct db_filter *) * (col->filter_cnt + 1)); + if (dbs == NULL) + return -ENOMEM; + col->filters = dbs; + col->filter_cnt++; + col->filters[col->filter_cnt - 1] = db; + + return 0; +} + +/** + * Remove a filter DB from a filter collection + * @param col the seccomp filter collection + * @param arch_token the architecture token + * + * This function removes an existing seccomp filter DB from an existing seccomp + * filter collection. Returns zero on success, negative values on failure. + * + */ +int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token) +{ + unsigned int iter; + unsigned int found; + struct db_filter **dbs; + + if ((col->filter_cnt <= 1) || (db_col_arch_exist(col, arch_token) == 0)) + return -EINVAL; + + for (found = 0, iter = 0; iter < col->filter_cnt; iter++) { + if (found) + col->filters[iter - 1] = col->filters[iter]; + else if (col->filters[iter]->arch->token == arch_token) { + db_release(col->filters[iter]); + found = 1; + } + } + col->filters[--col->filter_cnt] = NULL; + + /* NOTE: if we can't do the realloc it isn't fatal, we just have some + * extra space that will get cleaned up later */ + dbs = realloc(col->filters, + sizeof(struct db_filter *) * col->filter_cnt); + if (dbs != NULL) + col->filters = dbs; + + return 0; +} + +/** + * Free and reset the seccomp filter DB + * @param db the seccomp filter DB + * @param def_action the default filter action + * + * This function frees any existing filters and resets the filter DB to a + * default state; only the DB architecture is preserved. + * + */ +void db_reset(struct db_filter *db) +{ + struct db_sys_list *s_iter; + + if (db == NULL) + return; + + /* free any filters */ + if (db->syscalls != NULL) { + s_iter = db->syscalls; + while (s_iter != NULL) { + db->syscalls = s_iter->next; + _db_tree_free(s_iter->chains); + free(s_iter); + s_iter = db->syscalls; + } + db->syscalls = NULL; + } +} + +/** + * Intitalize a seccomp filter DB + * @param arch the architecture definition + * + * This function initializes a seccomp filter DB and readies it for use. + * Returns a pointer to the DB on success, NULL on failure. + * + */ +struct db_filter *db_init(const struct arch_def *arch) +{ + struct db_filter *db; + + db = malloc(sizeof(*db)); + if (db == NULL) + return NULL; + + /* clear the buffer for the first time and set the arch */ + memset(db, 0, sizeof(*db)); + db->arch = arch; + + /* reset the DB to a known state */ + db_reset(db); + + return db; +} + +/** + * Destroy a seccomp filter DB + * @param db the seccomp filter DB + * + * This function destroys a seccomp filter DB. After calling this function, + * the filter should no longer be referenced. + * + */ +void db_release(struct db_filter *db) +{ + if (db == NULL) + return; + + /* free and reset the DB */ + db_reset(db); + free(db); +} + +/** + * Update the user specified portion of the syscall priority + * @param db the seccomp filter db + * @param syscall the syscall number + * @param priority the syscall priority + * + * This function sets, or updates, the syscall priority; the highest priority + * value between the existing and specified value becomes the new syscall + * priority. If the syscall entry does not already exist, a new phantom + * syscall entry is created as a placeholder. Returns zero on success, + * negative values on failure. + * + */ +int db_syscall_priority(struct db_filter *db, + unsigned int syscall, uint8_t priority) +{ + unsigned int sys_pri = _DB_PRI_USER(priority); + struct db_sys_list *s_new, *s_iter, *s_prev = NULL; + + assert(db != NULL); + + s_iter = db->syscalls; + while (s_iter != NULL && s_iter->num < syscall) { + s_prev = s_iter; + s_iter = s_iter->next; + } + + /* matched an existing syscall entry */ + if (s_iter != NULL && s_iter->num == syscall) { + if (sys_pri > (s_iter->priority & _DB_PRI_MASK_USER)) { + s_iter->priority &= (~_DB_PRI_MASK_USER); + s_iter->priority |= sys_pri; + } + return 0; + } + + /* no existing syscall entry - create a phantom entry */ + s_new = malloc(sizeof(*s_new)); + if (s_new == NULL) + return -ENOMEM; + memset(s_new, 0, sizeof(*s_new)); + s_new->num = syscall; + s_new->priority = sys_pri; + s_new->valid = false; + + /* add it before s_iter */ + if (s_prev != NULL) { + s_new->next = s_prev->next; + s_prev->next = s_new; + } else { + s_new->next = db->syscalls; + db->syscalls = s_new; + } + + return 0; +} + +/** + * Fixup the node based on the op/mask + * @param node the chain node + * + * Apply some simplifications based on the comparison op and mask value. + * + */ +static void _db_node_mask_fixup(struct db_arg_chain_tree *node) +{ + if (node->op == SCMP_CMP_MASKED_EQ && node->mask == 0) { + node->op = SCMP_CMP_EQ; + node->mask = ARG_MASK_MAX; + node->datum = 0; + } else + node->datum &= node->mask; +} + +/** + * Generate a new filter rule for a 64 bit system + * @param arch the architecture definition + * @param action the filter action + * @param syscall the syscall number + * @param chain argument filter chain + * + * This function generates a new syscall filter for a 64 bit system. Returns + * zero on success, negative values on failure. + * + */ +static struct db_sys_list *_db_rule_gen_64(const struct arch_def *arch, + uint32_t action, + unsigned int syscall, + struct db_api_arg *chain) +{ + unsigned int iter; + int chain_len_max; + struct db_sys_list *s_new; + struct db_arg_chain_tree *c_iter_hi = NULL, *c_iter_lo = NULL; + struct db_arg_chain_tree *c_prev_hi = NULL, *c_prev_lo = NULL; + bool tf_flag; + + s_new = malloc(sizeof(*s_new)); + if (s_new == NULL) + return NULL; + memset(s_new, 0, sizeof(*s_new)); + s_new->num = syscall; + s_new->valid = true; + /* run through the argument chain */ + chain_len_max = arch_arg_count_max(arch); + for (iter = 0; iter < chain_len_max; iter++) { + if (chain[iter].valid == 0) + continue; + + c_iter_hi = malloc(sizeof(*c_iter_hi)); + if (c_iter_hi == NULL) + goto gen_64_failure; + memset(c_iter_hi, 0, sizeof(*c_iter_hi)); + c_iter_hi->refcnt = 1; + c_iter_lo = malloc(sizeof(*c_iter_lo)); + if (c_iter_lo == NULL) { + free(c_iter_hi); + goto gen_64_failure; + } + memset(c_iter_lo, 0, sizeof(*c_iter_lo)); + c_iter_lo->refcnt = 1; + + /* link this level to the previous level */ + if (c_prev_lo != NULL) { + if (!tf_flag) { + c_prev_lo->nxt_f = c_iter_hi; + c_prev_hi->nxt_f = c_iter_hi; + c_iter_hi->refcnt++; + } else + c_prev_lo->nxt_t = c_iter_hi; + } else + s_new->chains = c_iter_hi; + s_new->node_cnt += 2; + + /* set the arg, op, and datum fields */ + c_iter_hi->arg = chain[iter].arg; + c_iter_lo->arg = chain[iter].arg; + c_iter_hi->arg_offset = arch_arg_offset_hi(arch, + c_iter_hi->arg); + c_iter_lo->arg_offset = arch_arg_offset_lo(arch, + c_iter_lo->arg); + switch (chain[iter].op) { + case SCMP_CMP_GT: + c_iter_hi->op = SCMP_CMP_GE; + c_iter_lo->op = SCMP_CMP_GT; + tf_flag = true; + break; + case SCMP_CMP_NE: + c_iter_hi->op = SCMP_CMP_EQ; + c_iter_lo->op = SCMP_CMP_EQ; + tf_flag = false; + break; + case SCMP_CMP_LT: + c_iter_hi->op = SCMP_CMP_GE; + c_iter_lo->op = SCMP_CMP_GE; + tf_flag = false; + break; + case SCMP_CMP_LE: + c_iter_hi->op = SCMP_CMP_GE; + c_iter_lo->op = SCMP_CMP_GT; + tf_flag = false; + break; + default: + c_iter_hi->op = chain[iter].op; + c_iter_lo->op = chain[iter].op; + tf_flag = true; + } + c_iter_hi->mask = D64_HI(chain[iter].mask); + c_iter_lo->mask = D64_LO(chain[iter].mask); + c_iter_hi->datum = D64_HI(chain[iter].datum); + c_iter_lo->datum = D64_LO(chain[iter].datum); + + /* fixup the mask/datum */ + _db_node_mask_fixup(c_iter_hi); + _db_node_mask_fixup(c_iter_lo); + + /* link the hi and lo chain nodes */ + c_iter_hi->nxt_t = c_iter_lo; + + c_prev_hi = c_iter_hi; + c_prev_lo = c_iter_lo; + } + if (c_iter_lo != NULL) { + /* set the leaf node */ + if (!tf_flag) { + c_iter_lo->act_f_flg = true; + c_iter_lo->act_f = action; + c_iter_hi->act_f_flg = true; + c_iter_hi->act_f = action; + } else { + c_iter_lo->act_t_flg = true; + c_iter_lo->act_t = action; + } + } else + s_new->action = action; + + return s_new; + +gen_64_failure: + /* free the new chain and its syscall struct */ + _db_tree_free(s_new->chains); + free(s_new); + return NULL; +} + +/** + * Generate a new filter rule for a 32 bit system + * @param arch the architecture definition + * @param action the filter action + * @param syscall the syscall number + * @param chain argument filter chain + * + * This function generates a new syscall filter for a 32 bit system. Returns + * zero on success, negative values on failure. + * + */ +static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch, + uint32_t action, + unsigned int syscall, + struct db_api_arg *chain) +{ + unsigned int iter; + int chain_len_max; + struct db_sys_list *s_new; + struct db_arg_chain_tree *c_iter = NULL, *c_prev = NULL; + bool tf_flag; + + s_new = malloc(sizeof(*s_new)); + if (s_new == NULL) + return NULL; + memset(s_new, 0, sizeof(*s_new)); + s_new->num = syscall; + s_new->valid = true; + /* run through the argument chain */ + chain_len_max = arch_arg_count_max(arch); + for (iter = 0; iter < chain_len_max; iter++) { + if (chain[iter].valid == 0) + continue; + + c_iter = malloc(sizeof(*c_iter)); + if (c_iter == NULL) + goto gen_32_failure; + memset(c_iter, 0, sizeof(*c_iter)); + c_iter->refcnt = 1; + c_iter->arg = chain[iter].arg; + c_iter->arg_offset = arch_arg_offset(c_iter->arg); + c_iter->op = chain[iter].op; + c_iter->mask = chain[iter].mask; + c_iter->datum = chain[iter].datum; + + /* link in the new node and update the chain */ + if (c_prev != NULL) { + if (tf_flag) + c_prev->nxt_t = c_iter; + else + c_prev->nxt_f = c_iter; + } else + s_new->chains = c_iter; + s_new->node_cnt++; + + /* rewrite the op to reduce the op/datum combos */ + switch (c_iter->op) { + case SCMP_CMP_NE: + c_iter->op = SCMP_CMP_EQ; + tf_flag = false; + break; + case SCMP_CMP_LT: + c_iter->op = SCMP_CMP_GE; + tf_flag = false; + break; + case SCMP_CMP_LE: + c_iter->op = SCMP_CMP_GT; + tf_flag = false; + break; + default: + tf_flag = true; + } + + /* fixup the mask/datum */ + _db_node_mask_fixup(c_iter); + + c_prev = c_iter; + } + if (c_iter != NULL) { + /* set the leaf node */ + if (tf_flag) { + c_iter->act_t_flg = true; + c_iter->act_t = action; + } else { + c_iter->act_f_flg = true; + c_iter->act_f = action; + } + } else + s_new->action = action; + + return s_new; + +gen_32_failure: + /* free the new chain and its syscall struct */ + _db_tree_free(s_new->chains); + free(s_new); + return NULL; +} + +/** + * Add a new rule to the seccomp filter DB + * @param db the seccomp filter db + * @param action the filter action + * @param syscall the syscall number + * @param chain argument filter chain + * + * This function adds a new syscall filter to the seccomp filter DB, adding to + * the existing filters for the syscall, unless no argument specific filters + * are present (filtering only on the syscall). When adding new chains, the + * shortest chain, or most inclusive filter match, will be entered into the + * filter DB. Returns zero on success, negative values on failure. + * + */ +int db_rule_add(struct db_filter *db, uint32_t action, unsigned int syscall, + struct db_api_arg *chain) +{ + int rc = -ENOMEM; + struct db_sys_list *s_new, *s_iter, *s_prev = NULL; + struct db_arg_chain_tree *c_iter = NULL, *c_prev = NULL; + struct db_arg_chain_tree *ec_iter; + struct db_prune_state state; + bool rm_flag = false; + unsigned int new_chain_cnt = 0; + unsigned int n_cnt; + + assert(db != NULL); + + /* do all our possible memory allocation up front so we don't have to + * worry about failure once we get to the point where we start updating + * the filter db */ + if (db->arch->size == ARCH_SIZE_64) + s_new = _db_rule_gen_64(db->arch, action, syscall, chain); + else if (db->arch->size == ARCH_SIZE_32) + s_new = _db_rule_gen_32(db->arch, action, syscall, chain); + else + return -EFAULT; + if (s_new == NULL) + return -ENOMEM; + new_chain_cnt = s_new->node_cnt; + + /* no more failures allowed after this point that would result in the + * stored filter being in an inconsistent state */ + + /* find a matching syscall/chain or insert a new one */ + s_iter = db->syscalls; + while (s_iter != NULL && s_iter->num < syscall) { + s_prev = s_iter; + s_iter = s_iter->next; + } +add_reset: + s_new->node_cnt = new_chain_cnt; + s_new->priority = _DB_PRI_MASK_CHAIN - s_new->node_cnt; + c_prev = NULL; + c_iter = s_new->chains; + if (s_iter != NULL) + ec_iter = s_iter->chains; + else + ec_iter = NULL; + if (s_iter == NULL || s_iter->num != syscall) { + /* new syscall, add before s_iter */ + if (s_prev != NULL) { + s_new->next = s_prev->next; + s_prev->next = s_new; + } else { + s_new->next = db->syscalls; + db->syscalls = s_new; + } + return 0; + } else if (s_iter->chains == NULL) { + if (rm_flag || !s_iter->valid) { + /* we are here because our previous pass cleared the + * entire syscall chain when searching for a subtree + * match or the existing syscall entry is a phantom, + * so either way add the new chain */ + s_iter->chains = s_new->chains; + s_iter->action = s_new->action; + s_iter->node_cnt = s_new->node_cnt; + if (s_iter->valid) + s_iter->priority = s_new->priority; + s_iter->valid = true; + free(s_new); + rc = 0; + goto add_priority_update; + } else + /* syscall exists without any chains - existing filter + * is at least as large as the new entry so cleanup and + * exit */ + goto add_free_ok; + } else if (s_iter->chains != NULL && s_new->chains == NULL) { + /* syscall exists with chains but the new filter has no chains + * so we need to clear the existing chains and exit */ + _db_tree_free(s_iter->chains); + s_iter->chains = NULL; + s_iter->node_cnt = 0; + s_iter->action = action; + goto add_free_ok; + } + + /* check for sub-tree matches */ + memset(&state, 0, sizeof(state)); + rc = _db_tree_sub_prune(&(s_iter->chains), ec_iter, c_iter, &state); + if (rc > 0) { + rm_flag = true; + s_iter->node_cnt -= rc; + goto add_reset; + } else if (rc < 0) + goto add_free_ok; + + /* syscall exists and has at least one existing chain - start at the + * top and walk the two chains */ + do { + /* insert the new rule into the existing tree */ + if (db_chain_eq(c_iter, ec_iter)) { + /* found a matching node on this chain level */ + if (db_chain_action(c_iter) && + db_chain_action(ec_iter)) { + /* both are "action" nodes */ + if (c_iter->act_t_flg && ec_iter->act_t_flg) { + if (ec_iter->act_t != action) + goto add_free_exist; + } else if (c_iter->act_t_flg) { + ec_iter->act_t_flg = true; + ec_iter->act_t = action; + } + if (c_iter->act_f_flg && ec_iter->act_f_flg) { + if (ec_iter->act_f != action) + goto add_free_exist; + } else if (c_iter->act_f_flg) { + ec_iter->act_f_flg = true; + ec_iter->act_f = action; + } + if (ec_iter->act_t_flg == ec_iter->act_f_flg && + ec_iter->act_t == ec_iter->act_f) { + n_cnt = _db_tree_remove( + &(s_iter->chains), + ec_iter); + s_iter->node_cnt -= n_cnt; + goto add_free_ok; + } + } else if (db_chain_action(c_iter)) { + /* new is shorter */ + if (c_iter->act_t_flg) { + rc = _db_tree_act_check(ec_iter->nxt_t, + action); + if (rc < 0) + goto add_free; + n_cnt = _db_tree_free(ec_iter->nxt_t); + ec_iter->nxt_t = NULL; + ec_iter->act_t_flg = true; + ec_iter->act_t = action; + } else { + rc = _db_tree_act_check(ec_iter->nxt_f, + action); + if (rc < 0) + goto add_free; + n_cnt = _db_tree_free(ec_iter->nxt_f); + ec_iter->nxt_f = NULL; + ec_iter->act_f_flg = true; + ec_iter->act_f = action; + } + s_iter->node_cnt -= n_cnt; + } + if (c_iter->nxt_t != NULL) { + if (ec_iter->nxt_t != NULL) { + /* jump to the next level */ + c_prev = c_iter; + c_iter = c_iter->nxt_t; + ec_iter = ec_iter->nxt_t; + s_new->node_cnt--; + } else if (ec_iter->act_t_flg) { + /* existing is shorter */ + if (ec_iter->act_t == action) + goto add_free_ok; + goto add_free_exist; + } else { + /* add a new branch */ + c_prev = c_iter; + ec_iter->nxt_t = c_iter->nxt_t; + s_iter->node_cnt += + (s_new->node_cnt - 1); + goto add_free_match; + } + } else if (c_iter->nxt_f != NULL) { + if (ec_iter->nxt_f != NULL) { + /* jump to the next level */ + c_prev = c_iter; + c_iter = c_iter->nxt_f; + ec_iter = ec_iter->nxt_f; + s_new->node_cnt--; + } else if (ec_iter->act_f_flg) { + /* existing is shorter */ + if (ec_iter->act_f == action) + goto add_free_ok; + goto add_free_exist; + } else { + /* add a new branch */ + c_prev = c_iter; + ec_iter->nxt_f = c_iter->nxt_f; + s_iter->node_cnt += + (s_new->node_cnt - 1); + goto add_free_match; + } + } else + goto add_free_ok; + } else { + /* need to check other nodes on this level */ + if (db_chain_lt(c_iter, ec_iter)) { + if (ec_iter->lvl_prv == NULL) { + /* add to the start of the level */ + ec_iter->lvl_prv = c_iter; + c_iter->lvl_nxt = ec_iter; + if (ec_iter == s_iter->chains) + s_iter->chains = c_iter; + s_iter->node_cnt += s_new->node_cnt; + goto add_free_match; + } else + ec_iter = ec_iter->lvl_prv; + } else { + if (ec_iter->lvl_nxt == NULL) { + /* add to the end of the level */ + ec_iter->lvl_nxt = c_iter; + c_iter->lvl_prv = ec_iter; + s_iter->node_cnt += s_new->node_cnt; + goto add_free_match; + } else if (db_chain_lt(c_iter, + ec_iter->lvl_nxt)) { + /* add new chain in between */ + c_iter->lvl_nxt = ec_iter->lvl_nxt; + ec_iter->lvl_nxt->lvl_prv = c_iter; + ec_iter->lvl_nxt = c_iter; + c_iter->lvl_prv = ec_iter; + s_iter->node_cnt += s_new->node_cnt; + goto add_free_match; + } else + ec_iter = ec_iter->lvl_nxt; + } + } + } while ((c_iter != NULL) && (ec_iter != NULL)); + + /* we should never be here! */ + return -EFAULT; + +add_free_exist: + rc = -EEXIST; + goto add_free; +add_free_ok: + rc = 0; +add_free: + /* free the new chain and its syscall struct */ + _db_tree_free(s_new->chains); + free(s_new); + goto add_priority_update; +add_free_match: + /* free the matching portion of new chain */ + if (c_prev != NULL) { + c_prev->nxt_t = NULL; + c_prev->nxt_f = NULL; + _db_tree_free(s_new->chains); + } + free(s_new); + rc = 0; +add_priority_update: + /* update the priority */ + if (s_iter != NULL) { + s_iter->priority &= (~_DB_PRI_MASK_CHAIN); + s_iter->priority |= (_DB_PRI_MASK_CHAIN - s_iter->node_cnt); + } + return rc; +} diff --git a/src/db.h b/src/db.h new file mode 100644 index 0000000..c0472a5 --- /dev/null +++ b/src/db.h @@ -0,0 +1,194 @@ +/** + * Enhanced Seccomp Filter DB + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _FILTER_DB_H +#define _FILTER_DB_H + +#include +#include + +#include + +#include "arch.h" + +/* XXX - need to provide doxygen comments for the types here */ + +struct db_api_arg { + unsigned int arg; + unsigned int op; + scmp_datum_t mask; + scmp_datum_t datum; + + bool valid; +}; + +struct db_arg_chain_tree { + /* argument number (a0 = 0, a1 = 1, etc.) */ + unsigned int arg; + /* argument bpf offset */ + unsigned int arg_offset; + + /* comparison operator */ + enum scmp_compare op; + /* syscall argument value */ + uint32_t mask; + uint32_t datum; + + /* actions */ + bool act_t_flg; + bool act_f_flg; + uint32_t act_t; + uint32_t act_f; + + /* list of nodes on this level */ + struct db_arg_chain_tree *lvl_prv, *lvl_nxt; + + /* next node in the chain */ + struct db_arg_chain_tree *nxt_t; + struct db_arg_chain_tree *nxt_f; + + unsigned int refcnt; +}; +#define ARG_MASK_MAX ((uint32_t)-1) +#define db_chain_lt(x,y) \ + (((x)->arg < (y)->arg) || \ + (((x)->arg == (y)->arg) && \ + (((x)->op < (y)->op) || (((x)->mask & (y)->mask) == (y)->mask)))) +#define db_chain_eq(x,y) \ + (((x)->arg == (y)->arg) && \ + ((x)->op == (y)->op) && ((x)->datum == (y)->datum) && \ + ((x)->mask == (y)->mask)) +#define db_chain_gt(x,y) \ + (((x)->arg > (y)->arg) || \ + (((x)->arg == (y)->arg) && \ + (((x)->op > (y)->op) || (((x)->mask & (y)->mask) != (y)->mask)))) +#define db_chain_action(x) \ + (((x)->act_t_flg) || ((x)->act_f_flg)) +#define db_chain_zombie(x) \ + ((x)->nxt_t == NULL && !((x)->act_t_flg) && \ + (x)->nxt_f == NULL && !((x)->act_f_flg)) +#define db_chain_leaf(x) \ + ((x)->nxt_t == NULL && (x)->nxt_f == NULL) +#define db_chain_eq_result(x,y) \ + ((((x)->nxt_t != NULL && (y)->nxt_t != NULL) || \ + ((x)->nxt_t == NULL && (y)->nxt_t == NULL)) && \ + (((x)->nxt_f != NULL && (y)->nxt_f != NULL) || \ + ((x)->nxt_f == NULL && (y)->nxt_f == NULL)) && \ + ((x)->act_t_flg == (y)->act_t_flg) && \ + ((x)->act_f_flg == (y)->act_f_flg) && \ + (((x)->act_t_flg && (x)->act_t == (y)->act_t) || \ + (!((x)->act_t_flg))) && \ + (((x)->act_f_flg && (x)->act_f == (y)->act_f) || \ + (!((x)->act_f_flg)))) + +struct db_sys_list { + /* native syscall number */ + unsigned int num; + + /* priority - higher is better */ + unsigned int priority; + + /* the argument chain heads */ + struct db_arg_chain_tree *chains; + unsigned int node_cnt; + + /* action in the case of no argument chains */ + uint32_t action; + + struct db_sys_list *next; + /* temporary use only by the BPF generator */ + struct db_sys_list *pri_prv, *pri_nxt; + + bool valid; +}; + +struct db_filter_attr { + /* action to take if we don't match an explicit allow/deny */ + uint32_t act_default; + /* action to take if we don't match the architecture */ + uint32_t act_badarch; + /* NO_NEW_PRIVS related attributes */ + uint32_t nnp_enable; +}; + +struct db_filter { + /* target architecture */ + const struct arch_def *arch; + + /* syscall filters, kept as a sorted single-linked list */ + struct db_sys_list *syscalls; +}; + +struct db_filter_col { + /* verification / state */ + int state; + + /* attributes */ + struct db_filter_attr attr; + + /* individual filters */ + struct db_filter **filters; + unsigned int filter_cnt; +}; + +/** + * Iterate over each item in the DB list + * @param iter the iterator + * @param list the list + * + * This macro acts as for()/while() conditional and iterates the following + * statement for each item in the given list. + * + */ +#define db_list_foreach(iter,list) \ + for (iter = (list); iter != NULL; iter = iter->next) + +int db_action_valid(uint32_t action); + +struct db_filter_col *db_col_init(uint32_t def_action); +void db_col_reset(struct db_filter_col *col, uint32_t def_action); +void db_col_release(struct db_filter_col *col); + +int db_col_valid(struct db_filter_col *col); + +int db_col_merge(struct db_filter_col *col_dst, struct db_filter_col *col_src); + +int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token); + +int db_col_attr_get(const struct db_filter_col *col, + enum scmp_filter_attr attr, uint32_t *value); +int db_col_attr_set(struct db_filter_col *col, + enum scmp_filter_attr attr, uint32_t value); + +int db_col_db_add(struct db_filter_col *col, struct db_filter *db); +int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token); + +struct db_filter *db_init(const struct arch_def *arch); +void db_reset(struct db_filter *db); +void db_release(struct db_filter *db); + +int db_syscall_priority(struct db_filter *db, + unsigned int syscall, uint8_t priority); + +int db_rule_add(struct db_filter *db, uint32_t action, unsigned int syscall, + struct db_api_arg *chain); + +#endif diff --git a/src/gen_bpf.c b/src/gen_bpf.c new file mode 100644 index 0000000..8c96f87 --- /dev/null +++ b/src/gen_bpf.c @@ -0,0 +1,1755 @@ +/** + * Seccomp BPF Translator + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "arch.h" +#include "arch-x32.h" +#include "gen_bpf.h" +#include "db.h" +#include "hash.h" +#include "system.h" + +/* allocation increments */ +#define AINC_BLK 2 +#define AINC_PROG 64 + +struct acc_state { + int32_t offset; + uint32_t mask; +}; + +enum bpf_jump_type { + TGT_NONE = 0, + TGT_K, /* immediate "k" value */ + TGT_NXT, /* fall through to the next block */ + TGT_IMM, /* resolved immediate value */ + TGT_PTR_DB, /* pointer to part of the filter db */ + TGT_PTR_BLK, /* pointer to an instruction block */ + TGT_PTR_HSH, /* pointer to a block hash table */ +}; + +struct bpf_jump { + union { + uint8_t imm_j; + uint32_t imm_k; + uint64_t hash; + struct db_arg_chain_tree *db; + struct bpf_blk *blk; + unsigned int nxt; + } tgt; + enum bpf_jump_type type; +}; +#define _BPF_JMP_NO \ + ((struct bpf_jump) { .type = TGT_NONE }) +#define _BPF_JMP_NXT(x) \ + ((struct bpf_jump) { .type = TGT_NXT, .tgt = { .nxt = (x) } }) +#define _BPF_JMP_IMM(x) \ + ((struct bpf_jump) { .type = TGT_IMM, .tgt = { .imm_j = (x) } }) +#define _BPF_JMP_DB(x) \ + ((struct bpf_jump) { .type = TGT_PTR_DB, .tgt = { .db = (x) } }) +#define _BPF_JMP_BLK(x) \ + ((struct bpf_jump) { .type = TGT_PTR_BLK, .tgt = { .blk = (x) } }) +#define _BPF_JMP_HSH(x) \ + ((struct bpf_jump) { .type = TGT_PTR_HSH, .tgt = { .hash = (x) } }) +#define _BPF_K(x) \ + ((struct bpf_jump) { .type = TGT_K, .tgt = { .imm_k = (x) } }) +#define _BPF_JMP_MAX 255 +#define _BPF_JMP_MAX_RET 255 + +struct bpf_instr { + uint16_t op; + struct bpf_jump jt; + struct bpf_jump jf; + struct bpf_jump k; +}; +#define _BPF_OFFSET_SYSCALL (offsetof(struct seccomp_data, nr)) +#define _BPF_SYSCALL _BPF_K(_BPF_OFFSET_SYSCALL) + +struct bpf_blk { + struct bpf_instr *blks; + unsigned int blk_cnt; + unsigned int blk_alloc; + + /* priority - higher is better */ + unsigned int priority; + + /* status flags */ + bool flag_hash; /* added to the hash table */ + bool flag_dup; /* duplicate block and in use */ + bool flag_unique; /* ->blks is unique to this block */ + + /* original db_arg_chain_tree node */ + const struct db_arg_chain_tree *node; + + /* used during block assembly */ + uint64_t hash; + struct bpf_blk *hash_nxt; + struct bpf_blk *prev, *next; + struct bpf_blk *lvl_prv, *lvl_nxt; + struct acc_state acc_state; +}; +#define _BLK_MSZE(x) \ + ((x)->blk_cnt * sizeof(*((x)->blks))) + +struct bpf_hash_bkt { + struct bpf_blk *blk; + struct bpf_hash_bkt *next; + unsigned int found; +}; + +#define _BPF_HASH_BITS 8 +#define _BPF_HASH_SIZE (1 << _BPF_HASH_BITS) +#define _BPF_HASH_MASK (_BPF_HASH_BITS - 1) +struct bpf_state { + /* block hash table */ + struct bpf_hash_bkt *htbl[_BPF_HASH_SIZE]; + + /* filter attributes */ + const struct db_filter_attr *attr; + /* default action */ + uint64_t def_hsh; + + /* target arch - NOTE: be careful, temporary use only! */ + const struct arch_def *arch; + + /* bpf program */ + struct bpf_program *bpf; +}; + +/** + * Populate a BPF instruction + * @param _ins the BPF instruction + * @param _op the BPF operand + * @param _jt the BPF jt value + * @param _jf the BPF jf value + * @param _k the BPF k value + * + * Set the given values on the provided bpf_instr struct. + * + */ +#define _BPF_INSTR(_ins,_op,_jt,_jf,_k) \ + do { \ + memset(&(_ins), 0, sizeof(_ins)); \ + (_ins).op = (_op); \ + (_ins).jt = _jt; \ + (_ins).jf = _jf; \ + (_ins).k = _k; \ + } while (0) + +static struct bpf_blk *_gen_bpf_chain(struct bpf_state *state, + const struct db_sys_list *sys, + const struct db_arg_chain_tree *chain, + const struct bpf_jump *nxt_jump, + struct acc_state *a_state); + +static struct bpf_blk *_hsh_remove(struct bpf_state *state, uint64_t h_val); +static struct bpf_blk *_hsh_find(const struct bpf_state *state, uint64_t h_val); + +/** + * Free the BPF instruction block + * @param state the BPF state + * @param blk the BPF instruction block + * + * Free the BPF instruction block, any linked blocks are preserved and the hash + * table is not modified. In general, you probably want to use _blk_free() + * instead. + * + */ +static void __blk_free(struct bpf_state *state, struct bpf_blk *blk) +{ + struct bpf_blk *b_tmp; + + while (blk->hash_nxt != NULL) { + b_tmp = blk->hash_nxt; + blk->hash_nxt = b_tmp->hash_nxt; + if (!b_tmp->flag_dup) + free(b_tmp); + } + if (blk->blks != NULL && blk->flag_unique) + free(blk->blks); + free(blk); +} + +/** +* Free the BPF instruction block + * @param state the BPF state + * @param blk the BPF instruction block + * + * Free the BPF instruction block including any linked blocks. The hash table + * is updated to reflect the newly removed block(s). + * + */ +static void _blk_free(struct bpf_state *state, struct bpf_blk *blk) +{ + int iter; + struct bpf_blk *b_iter; + struct bpf_instr *i_iter; + + if (blk == NULL) + return; + + /* remove this block from the hash table */ + _hsh_remove(state, blk->hash); + + /* run through the block freeing TGT_PTR_{BLK,HSH} jump targets */ + for (iter = 0; iter < blk->blk_cnt; iter++) { + i_iter = &blk->blks[iter]; + switch (i_iter->jt.type) { + case TGT_PTR_BLK: + _blk_free(state, i_iter->jt.tgt.blk); + break; + case TGT_PTR_HSH: + b_iter = _hsh_find(state, i_iter->jt.tgt.hash); + _blk_free(state, b_iter); + break; + default: + /* do nothing */ + break; + } + switch (i_iter->jf.type) { + case TGT_PTR_BLK: + _blk_free(state, i_iter->jf.tgt.blk); + break; + case TGT_PTR_HSH: + b_iter = _hsh_find(state, i_iter->jf.tgt.hash); + _blk_free(state, b_iter); + break; + default: + /* do nothing */ + break; + } + } + __blk_free(state, blk); +} + +/** + * Append a new BPF instruction to an instruction block + * @param state the BPF state + * @param blk the existing instruction block, or NULL + * @param instr the new instruction + * + * Add the new BPF instruction to the end of the give instruction block. If + * the given instruction block is NULL, a new block will be allocated. Returns + * a pointer to the block on success, NULL on failure, and in the case of + * failure the instruction block is free'd. + * + */ +static struct bpf_blk *_blk_append(struct bpf_state *state, + struct bpf_blk *blk, + const struct bpf_instr *instr) +{ + struct bpf_instr *new; + + if (blk == NULL) { + blk = malloc(sizeof(*blk)); + if (blk == NULL) + return NULL; + memset(blk, 0, sizeof(*blk)); + blk->flag_unique = true; + } + if ((blk->blk_cnt + 1) > blk->blk_alloc) { + blk->blk_alloc += AINC_BLK; + new = realloc(blk->blks, blk->blk_alloc * sizeof(*(blk->blks))); + if (new == NULL) { + _blk_free(state, blk); + return NULL; + } + blk->blks = new; + } + memcpy(&blk->blks[blk->blk_cnt++], instr, sizeof(*instr)); + + return blk; +} + +/** + * Append a block of BPF instructions to the final BPF program + * @param prg the BPF program + * @param blk the BPF instruction block + * + * Add the BPF instruction block to the end of the BPF program and perform the + * necssary translation. Returns zero on success, negative values on failure + * and in the case of failure the BPF program is free'd. + * + */ +static int _bpf_append_blk(struct bpf_program *prg, const struct bpf_blk *blk) +{ + int rc; + bpf_instr_raw *i_new; + bpf_instr_raw *i_iter; + unsigned int old_cnt = prg->blk_cnt; + unsigned int iter; + + /* (re)allocate the program memory */ + prg->blk_cnt += blk->blk_cnt; + i_new = realloc(prg->blks, BPF_PGM_SIZE(prg)); + if (i_new == NULL) { + rc = -ENOMEM; + goto bpf_append_blk_failure; + } + prg->blks = i_new; + + /* transfer and translate the blocks to raw instructions */ + for (iter = 0; iter < blk->blk_cnt; iter++) { + i_iter = &(prg->blks[old_cnt + iter]); + + i_iter->code = blk->blks[iter].op; + switch (blk->blks[iter].jt.type) { + case TGT_NONE: + i_iter->jt = 0; + break; + case TGT_IMM: + /* jump to the value specified */ + i_iter->jt = blk->blks[iter].jt.tgt.imm_j; + break; + default: + /* fatal error - we should never get here */ + rc = -EFAULT; + goto bpf_append_blk_failure; + } + switch (blk->blks[iter].jf.type) { + case TGT_NONE: + i_iter->jf = 0; + break; + case TGT_IMM: + /* jump to the value specified */ + i_iter->jf = blk->blks[iter].jf.tgt.imm_j; + break; + default: + /* fatal error - we should never get here */ + rc = -EFAULT; + goto bpf_append_blk_failure; + } + switch (blk->blks[iter].k.type) { + case TGT_NONE: + i_iter->k = 0; + break; + case TGT_K: + i_iter->k = blk->blks[iter].k.tgt.imm_k; + break; + default: + /* fatal error - we should never get here */ + rc = -EFAULT; + goto bpf_append_blk_failure; + } + } + + return prg->blk_cnt; + +bpf_append_blk_failure: + prg->blk_cnt = 0; + free(prg->blks); + return rc; +} + +/** + * Free the BPF program + * @param prg the BPF program + * + * Free the BPF program. None of the associated BPF state used to generate the + * BPF program is released in this function. + * + */ +static void _program_free(struct bpf_program *prg) +{ + if (prg == NULL) + return; + + if (prg->blks != NULL) + free(prg->blks); + free(prg); +} + +/** + * Free the BPF state + * @param the BPF state + * + * Free all of the BPF state, including the BPF program if present. + * + */ +static void _state_release(struct bpf_state *state) +{ + unsigned int bkt; + struct bpf_hash_bkt *iter; + + if (state == NULL) + return; + + /* release all of the hash table entries */ + for (bkt = 0; bkt < _BPF_HASH_SIZE; bkt++) { + while (state->htbl[bkt]) { + iter = state->htbl[bkt]; + state->htbl[bkt] = iter->next; + __blk_free(state, iter->blk); + free(iter); + } + } + _program_free(state->bpf); + + memset(state, 0, sizeof(*state)); +} + +/** + * Add an instruction block to the BPF state hash table + * @param state the BPF state + * @param blk_p pointer to the BPF instruction block + * @param found initial found value (see _hsh_find_once() for description) + * + * This function adds an instruction block to the hash table, and frees the + * block if an identical instruction block already exists, returning a pointer + * to the original block in place of the given block. Returns zero on success + * and negative values on failure. + * + */ +static int _hsh_add(struct bpf_state *state, struct bpf_blk **blk_p, + unsigned int found) +{ + uint64_t h_val; + struct bpf_hash_bkt *h_new, *h_iter, *h_prev = NULL; + struct bpf_blk *blk = *blk_p; + struct bpf_blk *b_iter; + + if (blk->flag_hash) + return 0; + + h_new = malloc(sizeof(*h_new)); + if (h_new == NULL) + return -ENOMEM; + memset(h_new, 0, sizeof(*h_new)); + + /* generate the hash */ + h_val = jhash(blk->blks, _BLK_MSZE(blk), 0); + blk->hash = h_val; + blk->flag_hash = true; + blk->node = NULL; + h_new->blk = blk; + h_new->found = (found ? 1 : 0); + + /* insert the block into the hash table */ + h_iter = state->htbl[h_val & _BPF_HASH_MASK]; + if (h_iter != NULL) { + do { + if ((h_iter->blk->hash == h_val) && + (_BLK_MSZE(h_iter->blk) == _BLK_MSZE(blk)) && + (memcmp(h_iter->blk->blks, blk->blks, + _BLK_MSZE(blk)) == 0)) { + /* duplicate block */ + free(h_new); + + /* store the duplicate block */ + b_iter = h_iter->blk; + while (b_iter->hash_nxt != NULL) + b_iter = b_iter->hash_nxt; + b_iter->hash_nxt = blk; + + /* in some cases we want to return the + * duplicate block */ + if (found) { + blk->flag_dup = true; + return 0; + } + + /* update the priority if needed */ + if (h_iter->blk->priority < blk->priority) + h_iter->blk->priority = blk->priority; + + /* try to save some memory */ + free(blk->blks); + blk->blks = h_iter->blk->blks; + blk->flag_unique = false; + + *blk_p = h_iter->blk; + return 0; + } else if (h_iter->blk->hash == h_val) { + /* hash collision */ + if ((h_val >> 32) == 0xffffffff) { + /* overflow */ + blk->flag_hash = false; + blk->hash = 0; + return -EFAULT; + } + h_val += ((uint64_t)1 << 32); + h_new->blk->hash = h_val; + + /* restart at the beginning of the bucket */ + h_iter = state->htbl[h_val & _BPF_HASH_MASK]; + } else { + /* no match, move along */ + h_prev = h_iter; + h_iter = h_iter->next; + } + } while (h_iter != NULL); + h_prev->next = h_new; + } else + state->htbl[h_val & _BPF_HASH_MASK] = h_new; + + return 0; +} + +/** + * Remove an entry from the hash table + * @param state the BPF state + * @param h_val the hash value + * + * Remove an entry from the hash table and return it to the caller, NULL is + * returned if the entry can not be found. + * + */ +static struct bpf_blk *_hsh_remove(struct bpf_state *state, uint64_t h_val) +{ + unsigned int bkt = h_val & _BPF_HASH_MASK; + struct bpf_blk *blk; + struct bpf_hash_bkt *h_iter, *h_prev = NULL; + + h_iter = state->htbl[bkt]; + while (h_iter != NULL) { + if (h_iter->blk->hash == h_val) { + if (h_prev != NULL) + h_prev->next = h_iter->next; + else + state->htbl[bkt] = h_iter->next; + blk = h_iter->blk; + free(h_iter); + return blk; + } + h_prev = h_iter; + h_iter = h_iter->next; + } + + return NULL; +} + +/** + * Find and return a hash bucket + * @param state the BPF state + * @param h_val the hash value + * + * Find the entry associated with the given hash value and return it to the + * caller, NULL is returned if the entry can not be found. This function + * should not be called directly; use _hsh_find() and _hsh_find_once() instead. + * + */ +static struct bpf_hash_bkt *_hsh_find_bkt(const struct bpf_state *state, + uint64_t h_val) +{ + struct bpf_hash_bkt *h_iter; + + h_iter = state->htbl[h_val & _BPF_HASH_MASK]; + while (h_iter != NULL) { + if (h_iter->blk->hash == h_val) + return h_iter; + h_iter = h_iter->next; + } + + return NULL; +} + +/** + * Find and only return an entry in the hash table once + * @param state the BPF state + * @param h_val the hash value + * + * Find the entry associated with the given hash value and return it to the + * caller if it has not be returned previously by this function; returns NULL + * if the entry can not be found or has already been returned in a previous + * call. + * + */ +static struct bpf_blk *_hsh_find_once(const struct bpf_state *state, + uint64_t h_val) +{ + struct bpf_hash_bkt *h_iter; + + h_iter = _hsh_find_bkt(state, h_val); + if (h_iter == NULL || h_iter->found != 0) + return NULL; + h_iter->found = 1; + return h_iter->blk; +} + +/** + * Finds an entry in the hash table + * @param state the BPF state + * @param h_val the hash value + * + * Find the entry associated with the given hash value and return it to the + * caller, NULL is returned if the entry can not be found. + * + */ +static struct bpf_blk *_hsh_find(const struct bpf_state *state, uint64_t h_val) +{ + struct bpf_hash_bkt *h_iter; + + h_iter = _hsh_find_bkt(state, h_val); + if (h_iter == NULL) + return NULL; + return h_iter->blk; +} + +/** + * Generate a BPF action instruction + * @param state the BPF state + * @param blk the BPF instruction block, or NULL + * @param action the desired action + * + * Generate a BPF action instruction and append it to the given instruction + * block. Returns a pointer to the instruction block on success, NULL on + * failure. + * + */ +static struct bpf_blk *_gen_bpf_action(struct bpf_state *state, + struct bpf_blk *blk, uint32_t action) +{ + struct bpf_instr instr; + + _BPF_INSTR(instr, BPF_RET, _BPF_JMP_NO, _BPF_JMP_NO, _BPF_K(action)); + return _blk_append(state, blk, &instr); +} + +/** + * Generate a BPF action instruction and insert it into the hash table + * @param state the BPF state + * @param action the desired action + * + * Generate a BPF action instruction and insert it into the hash table. + * Returns a pointer to the instruction block on success, NULL on failure. + * + */ +static struct bpf_blk *_gen_bpf_action_hsh(struct bpf_state *state, + uint32_t action) +{ + struct bpf_blk *blk; + + blk = _gen_bpf_action(state, NULL, action); + if (blk == NULL) + return NULL; + if (_hsh_add(state, &blk, 0) < 0) { + _blk_free(state, blk); + return NULL; + } + + return blk; +} + +/** + * Generate a BPF instruction block for a given chain node + * @param state the BPF state + * @param node the filter chain node + * @param a_state the accumulator state + * + * Generate BPF instructions to execute the filter for the given chain node. + * Returns a pointer to the instruction block on success, NULL on failure. + * + */ +static struct bpf_blk *_gen_bpf_node(struct bpf_state *state, + const struct db_arg_chain_tree *node, + struct acc_state *a_state) +{ + int32_t acc_offset; + uint32_t acc_mask; + uint64_t act_t_hash = 0, act_f_hash = 0; + struct bpf_blk *blk = NULL, *b_act; + struct bpf_instr instr; + struct acc_state a_state_orig = *a_state; + + /* generate the action blocks */ + if (node->act_t_flg) { + b_act = _gen_bpf_action_hsh(state, node->act_t); + if (b_act == NULL) + goto node_failure; + act_t_hash = b_act->hash; + } + if (node->act_f_flg) { + b_act = _gen_bpf_action_hsh(state, node->act_f); + if (b_act == NULL) + goto node_failure; + act_f_hash = b_act->hash; + } + + /* check the accumulator state */ + acc_offset = node->arg_offset; + acc_mask = node->mask; + if (acc_offset < 0) + goto node_failure; + if ((acc_offset != a_state->offset) || + ((acc_mask & a_state->mask) != acc_mask)) { + /* reload the accumulator */ + a_state->offset = acc_offset; + a_state->mask = ARG_MASK_MAX; + _BPF_INSTR(instr, BPF_LD + BPF_ABS, + _BPF_JMP_NO, _BPF_JMP_NO, _BPF_K(acc_offset)); + blk = _blk_append(state, blk, &instr); + if (blk == NULL) + goto node_failure; + } + if (acc_mask != a_state->mask) { + /* apply the bitmask */ + a_state->mask = acc_mask; + _BPF_INSTR(instr, BPF_ALU + BPF_AND, + _BPF_JMP_NO, _BPF_JMP_NO, _BPF_K(acc_mask)); + blk = _blk_append(state, blk, &instr); + if (blk == NULL) + goto node_failure; + } + + /* check the accumulator against the datum */ + switch (node->op) { + case SCMP_CMP_MASKED_EQ: + case SCMP_CMP_EQ: + _BPF_INSTR(instr, BPF_JMP + BPF_JEQ, + _BPF_JMP_NO, _BPF_JMP_NO, _BPF_K(node->datum)); + break; + case SCMP_CMP_GT: + _BPF_INSTR(instr, BPF_JMP + BPF_JGT, + _BPF_JMP_NO, _BPF_JMP_NO, _BPF_K(node->datum)); + break; + case SCMP_CMP_GE: + _BPF_INSTR(instr, BPF_JMP + BPF_JGE, + _BPF_JMP_NO, _BPF_JMP_NO, _BPF_K(node->datum)); + break; + case SCMP_CMP_NE: + case SCMP_CMP_LT: + case SCMP_CMP_LE: + /* if we hit here it means the filter db isn't correct */ + default: + /* fatal error, we should never get here */ + goto node_failure; + } + + /* fixup the jump targets */ + if (node->nxt_t != NULL) + instr.jt = _BPF_JMP_DB(node->nxt_t); + else if (node->act_t_flg) + instr.jt = _BPF_JMP_HSH(act_t_hash); + else + instr.jt = _BPF_JMP_NXT(0); + if (node->nxt_f != NULL) + instr.jf = _BPF_JMP_DB(node->nxt_f); + else if (node->act_f_flg) + instr.jf = _BPF_JMP_HSH(act_f_hash); + else + instr.jf = _BPF_JMP_NXT(0); + blk = _blk_append(state, blk, &instr); + if (blk == NULL) + goto node_failure; + + blk->node = node; + blk->acc_state = a_state_orig; + return blk; + +node_failure: + _blk_free(state, blk); + return NULL; +} + +/** + * Resolve the jump targets in a BPF instruction block + * @param state the BPF state + * @param sys the syscall filter + * @param blk the BPF instruction block + * @param nxt_jump the jump to fallthrough to at the end of the level + * + * Resolve the jump targets in a BPF instruction block generated by the + * _gen_bpf_chain_lvl() function and adds the resulting block to the hash + * table. Returns a pointer to the new instruction block on success, NULL on + * failure. + * + */ +static struct bpf_blk *_gen_bpf_chain_lvl_res(struct bpf_state *state, + const struct db_sys_list *sys, + struct bpf_blk *blk, + const struct bpf_jump *nxt_jump) +{ + int rc; + unsigned int iter; + struct bpf_blk *b_new; + struct bpf_instr *i_iter; + struct db_arg_chain_tree *node; + + if (blk->flag_hash) + return blk; + + /* convert TGT_PTR_DB to TGT_PTR_HSH references */ + for (iter = 0; iter < blk->blk_cnt; iter++) { + i_iter = &blk->blks[iter]; + switch (i_iter->jt.type) { + case TGT_NONE: + case TGT_IMM: + case TGT_PTR_HSH: + /* ignore these jump types */ + break; + case TGT_PTR_BLK: + b_new = _gen_bpf_chain_lvl_res(state, sys, + i_iter->jt.tgt.blk, + nxt_jump); + if (b_new == NULL) + return NULL; + i_iter->jt = _BPF_JMP_HSH(b_new->hash); + break; + case TGT_PTR_DB: + node = (struct db_arg_chain_tree *)i_iter->jt.tgt.db; + b_new = _gen_bpf_chain(state, sys, node, + nxt_jump, &blk->acc_state); + if (b_new == NULL) + return NULL; + i_iter->jt = _BPF_JMP_HSH(b_new->hash); + break; + default: + /* we should not be here */ + return NULL; + } + switch (i_iter->jf.type) { + case TGT_NONE: + case TGT_IMM: + case TGT_PTR_HSH: + /* ignore these jump types */ + break; + case TGT_PTR_BLK: + b_new = _gen_bpf_chain_lvl_res(state, sys, + i_iter->jf.tgt.blk, + nxt_jump); + if (b_new == NULL) + return NULL; + i_iter->jf = _BPF_JMP_HSH(b_new->hash); + break; + case TGT_PTR_DB: + node = (struct db_arg_chain_tree *)i_iter->jf.tgt.db; + b_new = _gen_bpf_chain(state, sys, node, + nxt_jump, &blk->acc_state); + if (b_new == NULL) + return NULL; + i_iter->jf = _BPF_JMP_HSH(b_new->hash); + break; + default: + /* we should not be here */ + return NULL; + } + switch (i_iter->k.type) { + case TGT_NONE: + case TGT_K: + case TGT_PTR_HSH: + /* ignore these jump types */ + break; + default: + /* we should not be here */ + return NULL; + } + } + + /* insert the block into the hash table */ + rc = _hsh_add(state, &blk, 0); + if (rc < 0) + return NULL; + + return blk; +} + +/** + * Generates the BPF instruction blocks for a given filter chain + * @param state the BPF state + * @param sys the syscall filter + * @param chain the filter chain + * @param nxt_jump the jump to fallthrough to at the end of the level + * @param a_state the accumulator state + * + * Generate the BPF instruction blocks for the given filter chain and return + * a pointer to the first block on success; returns NULL on failure. + * + */ +static struct bpf_blk *_gen_bpf_chain(struct bpf_state *state, + const struct db_sys_list *sys, + const struct db_arg_chain_tree *chain, + const struct bpf_jump *nxt_jump, + struct acc_state *a_state) +{ + struct bpf_blk *b_head = NULL, *b_tail = NULL; + struct bpf_blk *b_prev, *b_next, *b_iter; + struct bpf_instr *i_iter; + const struct db_arg_chain_tree *c_iter; + unsigned int iter; + struct bpf_jump nxt_jump_tmp; + + if (chain == NULL) { + b_head = _gen_bpf_action(state, NULL, sys->action); + if (b_head == NULL) + goto chain_failure; + b_tail = b_head; + } else { + /* find the starting node of the level */ + c_iter = chain; + while (c_iter->lvl_prv != NULL) + c_iter = c_iter->lvl_prv; + + /* build all of the blocks for this level */ + do { + b_iter = _gen_bpf_node(state, c_iter, a_state); + if (b_iter == NULL) + goto chain_failure; + if (b_head != NULL) { + b_iter->lvl_prv = b_tail; + b_tail->lvl_nxt = b_iter; + b_tail = b_iter; + } else { + b_head = b_iter; + b_tail = b_iter; + } + c_iter = c_iter->lvl_nxt; + } while (c_iter != NULL); + + /* resolve the TGT_NXT jumps */ + b_iter = b_head; + do { + b_next = b_iter->lvl_nxt; + for (iter = 0; iter < b_iter->blk_cnt; iter++) { + i_iter = &b_iter->blks[iter]; + if (i_iter->jt.type == TGT_NXT) { + if (i_iter->jt.tgt.nxt != 0) + goto chain_failure; + if (b_next == NULL) + i_iter->jt = *nxt_jump; + else + i_iter->jt = + _BPF_JMP_BLK(b_next); + } + if (i_iter->jf.type == TGT_NXT) { + if (i_iter->jf.tgt.nxt != 0) + goto chain_failure; + if (b_next == NULL) + i_iter->jf = *nxt_jump; + else + i_iter->jf = + _BPF_JMP_BLK(b_next); + } + } + b_iter = b_next; + } while (b_iter != NULL); + } + + /* resolve all of the blocks */ + memset(&nxt_jump_tmp, 0, sizeof(nxt_jump_tmp)); + b_iter = b_tail; + do { + /* b_iter may change after resolving, so save the linkage */ + b_prev = b_iter->lvl_prv; + b_next = b_iter->lvl_nxt; + + nxt_jump_tmp = _BPF_JMP_BLK(b_next); + b_iter = _gen_bpf_chain_lvl_res(state, sys, b_iter, + (b_next == NULL ? + nxt_jump : + &nxt_jump_tmp)); + if (b_iter == NULL) + goto chain_failure; + + /* restore the block linkage on this level */ + if (b_prev != NULL) + b_prev->lvl_nxt = b_iter; + b_iter->lvl_prv = b_prev; + b_iter->lvl_nxt = b_next; + if (b_next != NULL) + b_next->lvl_prv = b_iter; + if (b_iter->lvl_prv == NULL) + b_head = b_iter; + + b_iter = b_prev; + } while (b_iter != NULL); + + return b_head; + +chain_failure: + while (b_head != NULL) { + b_iter = b_head; + b_head = b_iter->lvl_nxt; + _blk_free(state, b_iter); + } + return NULL; +} + +/** + * Generate the BPF instruction blocks for a given syscall + * @param state the BPF state + * @param sys the syscall filter DB entry + * @param nxt_hash the hash value of the next syscall filter DB entry + * @param acc_reset accumulator reset flag + * + * Generate the BPF instruction blocks for the given syscall filter and return + * a pointer to the first block on success; returns NULL on failure. It is + * important to note that the block returned has not been added to the hash + * table, however, any linked/referenced blocks have been added to the hash + * table. + * + */ +static struct bpf_blk *_gen_bpf_syscall(struct bpf_state *state, + const struct db_sys_list *sys, + uint64_t nxt_hash, + bool acc_reset) +{ + int rc; + struct bpf_instr instr; + struct bpf_blk *blk_c, *blk_s = NULL; + struct bpf_jump def_jump; + struct acc_state a_state; + + /* we do the memset before the assignment to keep valgrind happy */ + memset(&def_jump, 0, sizeof(def_jump)); + def_jump = _BPF_JMP_HSH(state->def_hsh); + + /* setup the accumulator state */ + if (acc_reset) { + _BPF_INSTR(instr, BPF_LD + BPF_ABS, _BPF_JMP_NO, _BPF_JMP_NO, + _BPF_SYSCALL); + blk_s = _blk_append(state, NULL, &instr); + if (blk_s == NULL) + return NULL; + a_state.offset = _BPF_OFFSET_SYSCALL; + a_state.mask = ARG_MASK_MAX; + } else { + /* set the accumulator state to an unknown value */ + a_state.offset = -1; + a_state.mask = ARG_MASK_MAX; + } + + /* generate the argument chains */ + blk_c = _gen_bpf_chain(state, sys, sys->chains, &def_jump, &a_state); + if (blk_c == NULL) + return NULL; + + /* syscall check */ + _BPF_INSTR(instr, BPF_JMP + BPF_JEQ, + _BPF_JMP_HSH(blk_c->hash), _BPF_JMP_HSH(nxt_hash), + _BPF_K(sys->num)); + blk_s = _blk_append(state, blk_s, &instr); + if (blk_s == NULL) + return NULL; + blk_s->priority = sys->priority; + + /* add to the hash table */ + rc = _hsh_add(state, &blk_s, 1); + if (rc < 0) { + _blk_free(state, blk_s); + return NULL; + } + + return blk_s; +} + +/** + * Generate the BPF instruction blocks for a given filter/architecture + * @param state the BPF state + * @param db the filter DB + * @param db_secondary the secondary DB + * + * Generate the BPF instruction block for the given filter DB(s)/architecture(s) + * and return a pointer to the block on succes, NULL on failure. The resulting + * block assumes that the architecture token has already been loaded into the + * BPF accumulator. + * + */ +static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state, + const struct db_filter *db, + const struct db_filter *db_secondary) +{ + int rc; + unsigned int blk_cnt = 0; + bool acc_reset; + struct bpf_instr instr; + struct db_sys_list *s_head = NULL, *s_tail = NULL, *s_iter, *s_iter_b; + struct bpf_blk *b_head = NULL, *b_tail = NULL, *b_iter, *b_new; + + state->arch = db->arch; + + /* sort the syscall list */ + db_list_foreach(s_iter, db->syscalls) { + if (s_head != NULL) { + s_iter_b = s_head; + while ((s_iter_b->pri_nxt != NULL) && + (s_iter->priority <= s_iter_b->priority)) + s_iter_b = s_iter_b->pri_nxt; + + if (s_iter->priority > s_iter_b->priority) { + s_iter->pri_prv = s_iter_b->pri_prv; + s_iter->pri_nxt = s_iter_b; + if (s_iter_b == s_head) { + s_head->pri_prv = s_iter; + s_head = s_iter; + } else { + s_iter->pri_prv->pri_nxt = s_iter; + s_iter->pri_nxt->pri_prv = s_iter; + } + } else { + s_iter->pri_prv = s_tail; + s_iter->pri_nxt = NULL; + s_iter->pri_prv->pri_nxt = s_iter; + s_tail = s_iter; + } + } else { + s_head = s_iter; + s_tail = s_iter; + s_head->pri_prv = NULL; + s_head->pri_nxt = NULL; + } + } + if (db_secondary != NULL) { + db_list_foreach(s_iter, db_secondary->syscalls) { + if (s_head != NULL) { + s_iter_b = s_head; + while ((s_iter_b->pri_nxt != NULL) && + (s_iter->priority <= s_iter_b->priority)) + s_iter_b = s_iter_b->pri_nxt; + + if (s_iter->priority > s_iter_b->priority) { + s_iter->pri_prv = s_iter_b->pri_prv; + s_iter->pri_nxt = s_iter_b; + if (s_iter_b == s_head) { + s_head->pri_prv = s_iter; + s_head = s_iter; + } else { + s_iter->pri_prv->pri_nxt = + s_iter; + s_iter->pri_nxt->pri_prv = + s_iter; + } + } else { + s_iter->pri_prv = s_tail; + s_iter->pri_nxt = NULL; + s_iter->pri_prv->pri_nxt = s_iter; + s_tail = s_iter; + } + } else { + s_head = s_iter; + s_tail = s_iter; + s_head->pri_prv = NULL; + s_head->pri_nxt = NULL; + } + } + } + + if ((db->arch->token == SCMP_ARCH_X86_64 || + db->arch->token == SCMP_ARCH_X32) && (db_secondary == NULL)) + acc_reset = false; + else + acc_reset = true; + + /* create the syscall filters and add them to block list group */ + for (s_iter = s_tail; s_iter != NULL; s_iter = s_iter->pri_prv) { + if (!s_iter->valid) + continue; + + /* build the syscall filter */ + b_new = _gen_bpf_syscall(state, s_iter, + (b_head == NULL ? + state->def_hsh : b_head->hash), + (s_iter == s_head ? + acc_reset : false)); + if (b_new == NULL) + goto arch_failure; + + /* add the filter to the list head */ + b_new->prev = NULL; + b_new->next = b_head; + if (b_tail != NULL) { + b_head->prev = b_new; + b_head = b_new; + } else { + b_head = b_new; + b_tail = b_head; + } + + if (b_tail->next != NULL) + b_tail = b_tail->next; + blk_cnt++; + } + + /* additional ABI filtering */ + if ((db->arch->token == SCMP_ARCH_X86_64 || + db->arch->token == SCMP_ARCH_X32) && (db_secondary == NULL)) { + _BPF_INSTR(instr, BPF_LD + BPF_ABS, _BPF_JMP_NO, _BPF_JMP_NO, + _BPF_SYSCALL); + b_new = _blk_append(state, NULL, &instr); + if (b_new == NULL) + goto arch_failure; + if (db->arch->token == SCMP_ARCH_X86_64) { + /* filter out x32 */ + _BPF_INSTR(instr, BPF_JMP + BPF_JGE, + _BPF_JMP_NXT(blk_cnt++), _BPF_JMP_NO, + _BPF_K(X32_SYSCALL_BIT)); + if (b_head != NULL) + instr.jf = _BPF_JMP_HSH(b_head->hash); + else + instr.jf = _BPF_JMP_HSH(state->def_hsh); + } else if (db->arch->token == SCMP_ARCH_X32) { + /* filter out x86_64 */ + _BPF_INSTR(instr, BPF_JMP + BPF_JGE, + _BPF_JMP_NO, _BPF_JMP_NXT(blk_cnt++), + _BPF_K(X32_SYSCALL_BIT)); + if (b_head != NULL) + instr.jt = _BPF_JMP_HSH(b_head->hash); + else + instr.jt = _BPF_JMP_HSH(state->def_hsh); + } else + /* we should never get here */ + goto arch_failure; + b_new = _blk_append(state, b_new, &instr); + if (b_new == NULL) + goto arch_failure; + b_new->next = b_head; + if (b_head != NULL) + b_head->prev = b_new; + b_head = b_new; + rc = _hsh_add(state, &b_head, 1); + if (rc < 0) + goto arch_failure; + } + + /* do the ABI/architecture check */ + _BPF_INSTR(instr, BPF_JMP + BPF_JEQ, + _BPF_JMP_NO, _BPF_JMP_NXT(blk_cnt++), + _BPF_K(db->arch->token_bpf)); + if (b_head != NULL) + instr.jt = _BPF_JMP_HSH(b_head->hash); + else + instr.jt = _BPF_JMP_HSH(state->def_hsh); + b_new = _blk_append(state, NULL, &instr); + if (b_new == NULL) + goto arch_failure; + b_new->next = b_head; + if (b_head != NULL) + b_head->prev = b_new; + b_head = b_new; + rc = _hsh_add(state, &b_head, 1); + if (rc < 0) + goto arch_failure; + + state->arch = NULL; + return b_head; + +arch_failure: + /* NOTE: we do the cleanup here and not just return an error as all of + * the instruction blocks may not be added to the hash table when we + * hit an error */ + state->arch = NULL; + b_iter = b_head; + while (b_iter != NULL) { + b_new = b_iter->next; + _blk_free(state, b_iter); + b_iter = b_new; + } + return NULL; +} + +/** + * Find the target block for the "next" jump + * @param blk the instruction block + * @param nxt the next offset + * + * Find the target block for the TGT_NXT jump using the given offset. Returns + * a pointer to the target block on success or NULL on failure. + * + */ +static struct bpf_blk *_gen_bpf_find_nxt(const struct bpf_blk *blk, + unsigned int nxt) +{ + struct bpf_blk *iter = blk->next; + + for (; (iter != NULL) && (nxt > 0); nxt--) + iter = iter->next; + + return iter; +} + +/** + * Manage jumps to return instructions + * @param state the BPF state + * @param blk the instruction block to check + * @param offset the instruction offset into the instruction block + * @param blk_ret the return instruction block + * + * Using the given block and instruction offset, calculate the jump distance + * between the jumping instruction and return instruction block. If the jump + * distance is too great, duplicate the return instruction to reduce the + * distance to the maximum value. Returns 1 if a long jump was added, zero if + * the existing jump is valid, and negative values on failure. + * + */ +static int _gen_bpf_build_jmp_ret(struct bpf_state *state, + struct bpf_blk *blk, unsigned int offset, + struct bpf_blk *blk_ret) +{ + unsigned int j_len; + uint64_t tgt_hash = blk_ret->hash; + struct bpf_blk *b_jmp, *b_new; + + /* calculate the jump distance */ + j_len = blk->blk_cnt - (offset + 1); + b_jmp = blk->next; + while (b_jmp != NULL && b_jmp != blk_ret && j_len < _BPF_JMP_MAX_RET) { + j_len += b_jmp->blk_cnt; + b_jmp = b_jmp->next; + } + if (j_len <= _BPF_JMP_MAX_RET && b_jmp == blk_ret) + return 0; + if (b_jmp == NULL) + return -EFAULT; + + /* we need a closer return instruction, see if one already exists */ + j_len = blk->blk_cnt - (offset + 1); + b_jmp = blk->next; + while (b_jmp != NULL && b_jmp->hash != tgt_hash && + j_len < _BPF_JMP_MAX_RET) { + j_len += b_jmp->blk_cnt; + b_jmp = b_jmp->next; + } + if (j_len <= _BPF_JMP_MAX_RET && b_jmp->hash == tgt_hash) + return 0; + if (b_jmp == NULL) + return -EFAULT; + + /* we need to insert a new return instruction - create one */ + b_new = _gen_bpf_action(state, NULL, blk_ret->blks[0].k.tgt.imm_k); + if (b_new == NULL) + return -EFAULT; + + /* NOTE - we need to be careful here, we're giving the block a hash + * value (this is a sneaky way to ensure we leverage the + * inserted long jumps as much as possible) but we never add the + * block to the hash table so it won't get cleaned up + * automatically */ + b_new->hash = tgt_hash; + + /* insert the jump after the current jumping block */ + b_new->prev = blk; + b_new->next = blk->next; + blk->next->prev = b_new; + blk->next = b_new; + + return 1; +} + +/** + * Manage jump lengths by duplicating and adding jumps if needed + * @param state the BPF state + * @param tail the tail of the instruction block list + * @param blk the instruction block to check + * @param offset the instruction offset into the instruction block + * @param tgt_hash the hash of the jump destination block + * + * Using the given block and instruction offset, calculate the jump distance + * between the jumping instruction and the destination. If the jump distance + * is too great, add a long jump instruction to reduce the distance to a legal + * value. Returns 1 if a new instruction was added, zero if the existing jump + * is valid, and negative values on failure. + * + */ +static int _gen_bpf_build_jmp(struct bpf_state *state, + struct bpf_blk *tail, + struct bpf_blk *blk, unsigned int offset, + uint64_t tgt_hash) +{ + int rc; + unsigned int jmp_len; + struct bpf_instr instr; + struct bpf_blk *b_new, *b_jmp, *b_tgt; + + /* find the jump target */ + b_tgt = tail; + while (b_tgt != blk && b_tgt->hash != tgt_hash) + b_tgt = b_tgt->prev; + if (b_tgt == blk) + return -EFAULT; + + if (b_tgt->blk_cnt == 1 && b_tgt->blks[0].op == BPF_RET) { + rc = _gen_bpf_build_jmp_ret(state, blk, offset, b_tgt); + if (rc == 1) + return 1; + else if (rc < 0) + return rc; + } + + /* calculate the jump distance */ + jmp_len = blk->blk_cnt - (offset + 1); + b_jmp = blk->next; + while (b_jmp != NULL && b_jmp != b_tgt && jmp_len < _BPF_JMP_MAX) { + jmp_len += b_jmp->blk_cnt; + b_jmp = b_jmp->next; + } + if (jmp_len <= _BPF_JMP_MAX && b_jmp == b_tgt) + return 0; + if (b_jmp == NULL) + return -EFAULT; + + /* we need a long jump, see if one already exists */ + jmp_len = blk->blk_cnt - (offset + 1); + b_jmp = blk->next; + while (b_jmp != NULL && b_jmp->hash != tgt_hash && + jmp_len < _BPF_JMP_MAX) { + jmp_len += b_jmp->blk_cnt; + b_jmp = b_jmp->next; + } + if (jmp_len <= _BPF_JMP_MAX && b_jmp->hash == tgt_hash) + return 0; + if (b_jmp == NULL) + return -EFAULT; + + /* we need to insert a long jump - create one */ + _BPF_INSTR(instr, BPF_JMP + BPF_JA, + _BPF_JMP_NO, _BPF_JMP_NO, _BPF_JMP_HSH(tgt_hash)); + b_new = _blk_append(state, NULL, &instr); + if (b_new == NULL) + return -EFAULT; + + /* NOTE - we need to be careful here, we're giving the block a hash + * value (this is a sneaky way to ensure we leverage the + * inserted long jumps as much as possible) but we never add the + * block to the hash table so it won't get cleaned up + * automatically */ + b_new->hash = tgt_hash; + + /* insert the jump after the current jumping block */ + b_new->prev = blk; + b_new->next = blk->next; + blk->next->prev = b_new; + blk->next = b_new; + + return 1; +} + +/** + * Generate the BPF program for the given filter collection + * @param state the BPF state + * @param col the filter collection + * + * Generate the BPF program for the given filter collection. Returns zero on + * success, negative values on failure. + * + */ +static int _gen_bpf_build_bpf(struct bpf_state *state, + const struct db_filter_col *col) +{ + int rc; + int iter; + uint64_t h_val; + unsigned int res_cnt; + unsigned int jmp_len; + int arch_x86_64 = -1, arch_x32 = -1; + struct bpf_instr instr; + struct bpf_instr *i_iter; + struct bpf_blk *b_badarch, *b_default; + struct bpf_blk *b_head = NULL, *b_tail = NULL, *b_iter, *b_new, *b_jmp; + struct db_filter *db_secondary = NULL; + + if (col->filter_cnt == 0) + return -EINVAL; + + /* generate the badarch action */ + b_badarch = _gen_bpf_action(state, NULL, state->attr->act_badarch); + if (b_badarch == NULL) + return -ENOMEM; + rc = _hsh_add(state, &b_badarch, 1); + if (rc < 0) + return rc; + + /* generate the default action */ + b_default = _gen_bpf_action(state, NULL, state->attr->act_default); + if (b_default == NULL) + return -ENOMEM; + rc = _hsh_add(state, &b_default, 0); + if (rc < 0) + return rc; + state->def_hsh = b_default->hash; + + /* load the architecture token/number */ + _BPF_INSTR(instr, BPF_LD + BPF_ABS, _BPF_JMP_NO, _BPF_JMP_NO, + _BPF_K(offsetof(struct seccomp_data, arch))); + b_head = _blk_append(state, NULL, &instr); + if (b_head == NULL) + return -ENOMEM; + rc = _hsh_add(state, &b_head, 1); + if (rc < 0) + return rc; + b_tail = b_head; + + /* generate the per-architecture filters */ + for (iter = 0; iter < col->filter_cnt; iter++) { + if (col->filters[iter]->arch->token == SCMP_ARCH_X86_64) + arch_x86_64 = iter; + if (col->filters[iter]->arch->token == SCMP_ARCH_X32) + arch_x32 = iter; + } + for (iter = 0; iter < col->filter_cnt; iter++) { + /* figure out the secondary arch filter mess */ + if (iter == arch_x86_64) { + if (arch_x32 > iter) + db_secondary = col->filters[arch_x32]; + else if (arch_x32 >= 0) + continue; + } else if (iter == arch_x32) { + if (arch_x86_64 > iter) + db_secondary = col->filters[arch_x86_64]; + else if (arch_x86_64 >= 0) + continue; + } else + db_secondary = NULL; + + /* create the filter for the architecture(s) */ + b_new = _gen_bpf_arch(state, col->filters[iter], db_secondary); + if (b_new == NULL) + return -ENOMEM; + b_new->prev = b_tail; + b_tail->next = b_new; + b_tail = b_new; + while (b_tail->next != NULL) + b_tail = b_tail->next; + } + + /* add a badarch action to the end */ + b_badarch->prev = b_tail; + b_badarch->next = NULL; + b_tail->next = b_badarch; + b_tail = b_badarch; + + /* resolve any TGT_NXT jumps at the top level */ + b_iter = b_head; + do { + for (iter = 0; iter < b_iter->blk_cnt; iter++) { + i_iter = &b_iter->blks[iter]; + if (i_iter->jt.type == TGT_NXT) { + b_jmp = _gen_bpf_find_nxt(b_iter, + i_iter->jt.tgt.nxt); + if (b_jmp == NULL) + return -EFAULT; + i_iter->jt = _BPF_JMP_HSH(b_jmp->hash); + } + if (i_iter->jf.type == TGT_NXT) { + b_jmp = _gen_bpf_find_nxt(b_iter, + i_iter->jf.tgt.nxt); + if (b_jmp == NULL) + return -EFAULT; + i_iter->jf = _BPF_JMP_HSH(b_jmp->hash); + } + /* we shouldn't need to worry about a TGT_NXT in k */ + } + b_iter = b_iter->next; + } while (b_iter != NULL && b_iter->next != NULL); + + /* pull in all of the TGT_PTR_HSH jumps, one layer at a time */ + b_iter = b_tail; + do { + b_jmp = NULL; + /* look for jumps - backwards (shorter jumps) */ + for (iter = b_iter->blk_cnt - 1; + (iter >= 0) && (b_jmp == NULL); + iter--) { + i_iter = &b_iter->blks[iter]; + if (i_iter->jt.type == TGT_PTR_HSH) + b_jmp = _hsh_find_once(state, + i_iter->jt.tgt.hash); + if (b_jmp == NULL && i_iter->jf.type == TGT_PTR_HSH) + b_jmp = _hsh_find_once(state, + i_iter->jf.tgt.hash); + if (b_jmp == NULL && i_iter->k.type == TGT_PTR_HSH) + b_jmp = _hsh_find_once(state, + i_iter->k.tgt.hash); + if (b_jmp != NULL) { + /* insert the new block after this block */ + b_jmp->prev = b_iter; + b_jmp->next = b_iter->next; + b_iter->next = b_jmp; + if (b_jmp->next) + b_jmp->next->prev = b_jmp; + } + } + if (b_jmp != NULL) { + while (b_tail->next != NULL) + b_tail = b_tail->next; + b_iter = b_tail; + } else + b_iter = b_iter->prev; + } while (b_iter != NULL); + + /* NOTE - from here to the end of the function we need to fail via the + * the build_bpf_free_blks label, not just return an error; see + * the _gen_bpf_build_jmp() function for details */ + + /* check for long jumps and insert if necessary, we also verify that + * all our jump targets are valid at this point in the process */ + b_iter = b_tail; + do { + res_cnt = 0; + for (iter = b_iter->blk_cnt - 1; iter >= 0; iter--) { + i_iter = &b_iter->blks[iter]; + switch (i_iter->jt.type) { + case TGT_NONE: + case TGT_IMM: + break; + case TGT_PTR_HSH: + h_val = i_iter->jt.tgt.hash; + rc = _gen_bpf_build_jmp(state, b_tail, + b_iter, iter, + h_val); + if (rc < 0) + goto build_bpf_free_blks; + res_cnt += rc; + break; + default: + /* fatal error */ + goto build_bpf_free_blks; + } + switch (i_iter->jf.type) { + case TGT_NONE: + case TGT_IMM: + break; + case TGT_PTR_HSH: + h_val = i_iter->jf.tgt.hash; + rc = _gen_bpf_build_jmp(state, b_tail, + b_iter, iter, + h_val); + if (rc < 0) + goto build_bpf_free_blks; + res_cnt += rc; + break; + default: + /* fatal error */ + goto build_bpf_free_blks; + } + } + if (res_cnt == 0) + b_iter = b_iter->prev; + } while (b_iter != NULL); + + /* build the bpf program */ + do { + b_iter = b_head; + /* resolve the TGT_PTR_HSH jumps */ + for (iter = 0; iter < b_iter->blk_cnt; iter++) { + i_iter = &b_iter->blks[iter]; + if (i_iter->jt.type == TGT_PTR_HSH) { + h_val = i_iter->jt.tgt.hash; + jmp_len = b_iter->blk_cnt - (iter + 1); + b_jmp = b_iter->next; + while (b_jmp != NULL && b_jmp->hash != h_val) { + jmp_len += b_jmp->blk_cnt; + b_jmp = b_jmp->next; + } + if (b_jmp == NULL || jmp_len > _BPF_JMP_MAX) + goto build_bpf_free_blks; + i_iter->jt = _BPF_JMP_IMM(jmp_len); + } + if (i_iter->jf.type == TGT_PTR_HSH) { + h_val = i_iter->jf.tgt.hash; + jmp_len = b_iter->blk_cnt - (iter + 1); + b_jmp = b_iter->next; + while (b_jmp != NULL && b_jmp->hash != h_val) { + jmp_len += b_jmp->blk_cnt; + b_jmp = b_jmp->next; + } + if (b_jmp == NULL || jmp_len > _BPF_JMP_MAX) + goto build_bpf_free_blks; + i_iter->jf = _BPF_JMP_IMM(jmp_len); + } + if (i_iter->k.type == TGT_PTR_HSH) { + h_val = i_iter->k.tgt.hash; + jmp_len = b_iter->blk_cnt - (iter + 1); + b_jmp = b_tail; + while (b_jmp->hash != h_val) + b_jmp = b_jmp->prev; + b_jmp = b_jmp->prev; + while (b_jmp != b_iter) { + jmp_len += b_jmp->blk_cnt; + b_jmp = b_jmp->prev; + } + if (b_jmp == NULL) + goto build_bpf_free_blks; + i_iter->k = _BPF_K(jmp_len); + } + } + + /* build the bpf program */ + if (_bpf_append_blk(state->bpf, b_iter) < 0) + goto build_bpf_free_blks; + + /* we're done with the block, free it */ + b_head = b_iter->next; + _blk_free(state, b_iter); + } while (b_head != NULL); + + return 0; + +build_bpf_free_blks: + b_iter = b_head; + while (b_iter != NULL) { + b_jmp = b_iter->next; + _hsh_remove(state, b_iter->hash); + __blk_free(state, b_iter); + b_iter = b_jmp; + } + return -EFAULT; +} + +/** + * Generate a BPF representation of the filter DB + * @param col the seccomp filter collection + * + * This function generates a BPF representation of the given filter collection. + * Returns a pointer to a valid bpf_program on success, NULL on failure. + * + */ +struct bpf_program *gen_bpf_generate(const struct db_filter_col *col) +{ + int rc; + struct bpf_state state; + + memset(&state, 0, sizeof(state)); + state.attr = &col->attr; + + state.bpf = malloc(sizeof(*(state.bpf))); + if (state.bpf == NULL) + return NULL; + memset(state.bpf, 0, sizeof(*(state.bpf))); + + rc = _gen_bpf_build_bpf(&state, col); + if (rc < 0) + goto bpf_generate_end; + +bpf_generate_end: + if (rc < 0) + _state_release(&state); + return state.bpf; +} + +/** + * Free memory associated with a BPF representation + * @param fprog the BPF representation + * + * Free the memory associated with a BPF representation generated by the + * gen_bpf_generate() function. + * + */ +void gen_bpf_release(struct bpf_program *program) +{ + _program_free(program); +} diff --git a/src/gen_bpf.h b/src/gen_bpf.h new file mode 100644 index 0000000..fe0580e --- /dev/null +++ b/src/gen_bpf.h @@ -0,0 +1,42 @@ +/** + * Seccomp BPF Translator + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _TRANSLATOR_BPF_H +#define _TRANSLATOR_BPF_H + +#include + +#include "arch.h" +#include "db.h" +#include "system.h" + +/* NOTE - do not change this structure, it is part of the prctl() API */ +struct bpf_program { + uint16_t blk_cnt; + bpf_instr_raw *blks; +}; +#define BPF_PGM_SIZE(x) \ + ((x)->blk_cnt * sizeof(*((x)->blks))) + +struct bpf_program *gen_bpf_generate(const struct db_filter_col *col); +void gen_bpf_release(struct bpf_program *program); + +#endif diff --git a/src/gen_pfc.c b/src/gen_pfc.c new file mode 100644 index 0000000..954feab --- /dev/null +++ b/src/gen_pfc.c @@ -0,0 +1,336 @@ +/** + * Seccomp Pseudo Filter Code (PFC) Generator + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +/* NOTE: needed for the arch->token decoding in _pfc_arch() */ +#include + +#include + +#include "arch.h" +#include "db.h" +#include "gen_pfc.h" + +struct pfc_sys_list { + struct db_sys_list *sys; + struct pfc_sys_list *next; +}; + +/* XXX - we should check the fprintf() return values */ + +/** + * Display a string representation of the architecture + * @param arch the architecture definition + */ +static const char *_pfc_arch(const struct arch_def *arch) +{ + switch (arch->token) { + case SCMP_ARCH_X86: + return "x86"; + case SCMP_ARCH_X86_64: + return "x86_64"; + case SCMP_ARCH_X32: + return "x32"; + case SCMP_ARCH_ARM: + return "arm"; + default: + return "UNKNOWN"; + } +} + +/** + * Display a string representation of the node argument + * @param fds the file stream to send the output + * @param arch the architecture definition + * @param node the node + */ +static void _pfc_arg(FILE *fds, + const struct arch_def *arch, + const struct db_arg_chain_tree *node) +{ + if (arch->size == ARCH_SIZE_64) { + if (arch_arg_offset_hi(arch, node->arg) == node->arg_offset) + fprintf(fds, "$a%d.hi32", node->arg); + else + fprintf(fds, "$a%d.lo32", node->arg); + } else + fprintf(fds, "$a%d", node->arg); +} + +/** + * Display a string representation of the filter action + * @param fds the file stream to send the output + * @param action the action + */ +static void _pfc_action(FILE *fds, uint32_t action) +{ + switch (action & 0xffff0000) { + case SCMP_ACT_KILL: + fprintf(fds, "action KILL;\n"); + break; + case SCMP_ACT_TRAP: + fprintf(fds, "action TRAP;\n"); + break; + case SCMP_ACT_ERRNO(0): + fprintf(fds, "action ERRNO(%u);\n", (action & 0x0000ffff)); + break; + case SCMP_ACT_TRACE(0): + fprintf(fds, "action TRACE(%u);\n", (action & 0x0000ffff)); + break; + case SCMP_ACT_ALLOW: + fprintf(fds, "action ALLOW;\n"); + break; + default: + fprintf(fds, "action 0x%x;\n", action); + } +} + +/** + * Indent the output stream + * @param fds the file stream to send the output + * @param lvl the indentation level + * + * This function indents the output stream with whitespace based on the + * requested indentation level. + */ +static void _indent(FILE *fds, unsigned int lvl) +{ + while (lvl-- > 0) + fprintf(fds, " "); +} + +/** + * Generate the pseudo filter code for an argument chain + * @param arch the architecture definition + * @param node the head of the argument chain + * @param lvl the indentation level + * @param fds the file stream to send the output + * + * This function generates the pseudo filter code representation of the given + * argument chain and writes it to the given output stream. + * + */ +static void _gen_pfc_chain(const struct arch_def *arch, + const struct db_arg_chain_tree *node, + unsigned int lvl, FILE *fds) +{ + const struct db_arg_chain_tree *c_iter; + + /* get to the start */ + c_iter = node; + while (c_iter->lvl_prv != NULL) + c_iter = c_iter->lvl_prv; + + while (c_iter != NULL) { + /* comparison operation */ + _indent(fds, lvl); + fprintf(fds, "if ("); + _pfc_arg(fds, arch, c_iter); + switch (c_iter->op) { + case SCMP_CMP_EQ: + fprintf(fds, " == "); + break; + case SCMP_CMP_GE: + fprintf(fds, " >= "); + break; + case SCMP_CMP_GT: + fprintf(fds, " > "); + break; + case SCMP_CMP_MASKED_EQ: + fprintf(fds, " & 0x%.8x == ", c_iter->mask); + break; + default: + fprintf(fds, " ??? "); + } + fprintf(fds, "%u)\n", c_iter->datum); + + /* true result */ + if (c_iter->act_t_flg) { + _indent(fds, lvl + 1); + _pfc_action(fds, c_iter->act_t); + } else if (c_iter->nxt_t != NULL) + _gen_pfc_chain(arch, c_iter->nxt_t, lvl + 1, fds); + + /* false result */ + if (c_iter->act_f_flg) { + _indent(fds, lvl); + fprintf(fds, "else\n"); + _indent(fds, lvl + 1); + _pfc_action(fds, c_iter->act_f); + } else if (c_iter->nxt_f != NULL) { + _indent(fds, lvl); + fprintf(fds, "else\n"); + _gen_pfc_chain(arch, c_iter->nxt_f, lvl + 1, fds); + } + + c_iter = c_iter->lvl_nxt; + } +} + +/** + * Generate pseudo filter code for a syscall + * @param arch the architecture definition + * @param sys the syscall filter + * @param fds the file stream to send the output + * + * This function generates a pseduo filter code representation of the given + * syscall filter and writes it to the given output stream. + * + */ +static void _gen_pfc_syscall(const struct arch_def *arch, + const struct db_sys_list *sys, FILE *fds) +{ + unsigned int sys_num = sys->num; + const char *sys_name = arch_syscall_resolve_num(arch, sys_num); + + _indent(fds, 1); + fprintf(fds, "# filter for syscall \"%s\" (%d) [priority: %d]\n", + (sys_name ? sys_name : "UNKNOWN"), sys_num, sys->priority); + _indent(fds, 1); + fprintf(fds, "if ($syscall == %d)\n", sys_num); + if (sys->chains == NULL) { + _indent(fds, 2); + _pfc_action(fds, sys->action); + } else + _gen_pfc_chain(arch, sys->chains, 2, fds); +} + +/** + * Generate pseudo filter code for an architecture + * @param col the seccomp filter collection + * @param db the single seccomp filter + * @param fds the file stream to send the output + * + * This function generates a pseudo filter code representation of the given + * filter DB and writes it to the given output stream. Returns zero on + * success, negative values on failure. + * + */ +static int _gen_pfc_arch(const struct db_filter_col *col, + const struct db_filter *db, FILE *fds) +{ + int rc; + struct db_sys_list *s_iter; + struct pfc_sys_list *p_iter = NULL, *p_new, *p_head = NULL, *p_prev; + + /* sort the syscall list */ + db_list_foreach(s_iter, db->syscalls) { + p_new = malloc(sizeof(*p_new)); + if (p_new == NULL) { + rc = -ENOMEM; + goto arch_return; + } + memset(p_new, 0, sizeof(*p_new)); + p_new->sys = s_iter; + + p_prev = NULL; + p_iter = p_head; + while (p_iter != NULL && + s_iter->priority < p_iter->sys->priority) { + p_prev = p_iter; + p_iter = p_iter->next; + } + if (p_head == NULL) + p_head = p_new; + else if (p_prev == NULL) { + p_new->next = p_head; + p_head = p_new; + } else { + p_new->next = p_iter; + p_prev->next = p_new; + } + } + + fprintf(fds, "# filter for arch %s (%u)\n", + _pfc_arch(db->arch), db->arch->token_bpf); + fprintf(fds, "if ($arch == %u)\n", db->arch->token_bpf); + p_iter = p_head; + while (p_iter != NULL) { + if (!p_iter->sys->valid) + continue; + _gen_pfc_syscall(db->arch, p_iter->sys, fds); + p_iter = p_iter->next; + } + _indent(fds, 1); + fprintf(fds, "# default action\n"); + _indent(fds, 1); + _pfc_action(fds, col->attr.act_default); + +arch_return: + while (p_head != NULL) { + p_iter = p_head; + p_head = p_head->next; + free(p_iter); + } + return rc; +} + +/** + * Generate a pseudo filter code string representation + * @param col the seccomp filter collection + * @param fd the fd to send the output + * + * This function generates a pseudo filter code representation of the given + * filter collection and writes it to the given fd. Returns zero on success, + * negative values on failure. + * + */ +int gen_pfc_generate(const struct db_filter_col *col, int fd) +{ + int rc = 0; + int newfd; + unsigned int iter; + FILE *fds; + + newfd = dup(fd); + if (newfd < 0) + return errno; + fds = fdopen(newfd, "a"); + if (fds == NULL) { + close(newfd); + return errno; + } + + /* generate the pfc */ + fprintf(fds, "#\n"); + fprintf(fds, "# pseudo filter code start\n"); + fprintf(fds, "#\n"); + + for (iter = 0; iter < col->filter_cnt; iter++) + _gen_pfc_arch(col, col->filters[iter], fds); + + fprintf(fds, "# invalid architecture action\n"); + _pfc_action(fds, col->attr.act_badarch); + fprintf(fds, "#\n"); + fprintf(fds, "# pseudo filter code end\n"); + fprintf(fds, "#\n"); + + fflush(fds); + fclose(fds); + + return rc; +} diff --git a/src/gen_pfc.h b/src/gen_pfc.h new file mode 100644 index 0000000..80f680f --- /dev/null +++ b/src/gen_pfc.h @@ -0,0 +1,29 @@ +/** + * Seccomp String Translator + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _TRANSLATOR_STR_H +#define _TRANSLATOR_STR_H + +#include "db.h" + +int gen_pfc_generate(const struct db_filter_col *col, int fd); + +#endif diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..cb52b3b --- /dev/null +++ b/src/hash.c @@ -0,0 +1,674 @@ +/** + * Seccomp Library hash code + * + * Release under the Public Domain + * Author: Bob Jenkins + */ + +/* + * lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * These are functions for producing 32-bit hashes for hash table lookup. + * jhash_word(), jhash_le(), jhash_be(), mix(), and final() are externally useful + * functions. Routines to test the hash are included if SELF_TEST is defined. + * You can use this free for any purpose. It's in the public domain. It has + * no warranty. + * + * You probably want to use jhash_le(). jhash_le() and jhash_be() hash byte + * arrays. jhash_le() is is faster than jhash_be() on little-endian machines. + * Intel and AMD are little-endian machines. + * + * If you want to find a hash of, say, exactly 7 integers, do + * a = i1; b = i2; c = i3; + * mix(a,b,c); + * a += i4; b += i5; c += i6; + * mix(a,b,c); + * a += i7; + * final(a,b,c); + * + * then use c as the hash value. If you have a variable length array of + * 4-byte integers to hash, use jhash_word(). If you have a byte array (like + * a character string), use jhash_le(). If you have several byte arrays, or + * a mix of things, see the comments above jhash_le(). + * + * Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then + * mix those integers. This is fast (you can do a lot more thorough mixing + * with 12*3 instructions on 3 integers than you can with 3 instructions on 1 + * byte), but shoehorning those bytes into integers efficiently is messy. + */ + +#include + +#include "arch.h" +#include "hash.h" + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/** + * Mix 3 32-bit values reversibly + * @param a 32-bit value + * @param b 32-bit value + * @param c 32-bit value + * + * This is reversible, so any information in (a,b,c) before mix() is still + * in (a,b,c) after mix(). + * + * If four pairs of (a,b,c) inputs are run through mix(), or through mix() in + * reverse, there are at least 32 bits of the output that are sometimes the + * same for one pair and different for another pair. + * + * This was tested for: + * - pairs that differed by one bit, by two bits, in any combination of top + * bits of (a,b,c), or in any combination of bottom bits of (a,b,c). + * - "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the + * output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly + * produced by subtraction) look like a single 1-bit difference. + * - the base values were pseudorandom, all zero but one bit set, or all zero + * plus a counter that starts at zero. + * + * Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that + * satisfy this are + * 4 6 8 16 19 4 + * 9 15 3 18 27 15 + * 14 9 3 7 17 3 + * + * Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" + * defined as + with a one-bit base and a two-bit delta. I used + * http://burtleburtle.net/bob/hash/avalanche.html to choose the operations, + * constants, and arrangements of the variables. + * + * This does not achieve avalanche. There are input bits of (a,b,c) that fail + * to affect some output bits of (a,b,c), especially of a. The most thoroughly + * mixed value is c, but it doesn't really even achieve avalanche in c. + * + * This allows some parallelism. Read-after-writes are good at doubling the + * number of bits affected, so the goal of mixing pulls in the opposite + * direction as the goal of parallelism. I did what I could. Rotates seem to + * cost as much as shifts on every machine I could lay my hands on, and rotates + * are much kinder to the top and bottom bits, so I used rotates. + * + */ +#define mix(a,b,c) \ + { \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ + } + +/** + * Final mixing of 3 32-bit values (a,b,c) into c + * @param a 32-bit value + * @param b 32-bit value + * @param c 32-bit value + * + * Pairs of (a,b,c) values differing in only a few bits will usually produce + * values of c that look totally different. This was tested for: + * - pairs that differed by one bit, by two bits, in any combination of top + * bits of (a,b,c), or in any combination of bottom bits of (a,b,c). + * - "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the + * output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly + * produced by subtraction) look like a single 1-bit difference. + * - the base values were pseudorandom, all zero but one bit set, or all zero + * plus a counter that starts at zero. + * + * These constants passed: + * 14 11 25 16 4 14 24 + * 12 14 25 16 4 14 24 + * and these came close: + * 4 8 15 26 3 22 24 + * 10 8 15 26 3 22 24 + * 11 8 15 26 3 22 24 + * + */ +#define final(a,b,c) \ + { \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ + } + +/** + * Hash an array of 32-bit values + * @param k the key, an array of uint32_t values + * @param length the number of array elements + * @param initval the previous hash, or an arbitrary value + * + * This works on all machines. To be useful, it requires: + * - that the key be an array of uint32_t's, and + * - that the length be the number of uint32_t's in the key + * + * The function jhash_word() is identical to jhash_le() on little-endian + * machines, and identical to jhash_be() on big-endian machines, except that + * the length has to be measured in uint32_ts rather than in bytes. jhash_le() + * is more complicated than jhash_word() only because jhash_le() has to dance + * around fitting the key bytes into registers. + * + */ +static uint32_t jhash_word(const uint32_t *k, size_t length, uint32_t initval) +{ + uint32_t a, b, c; + + /* set up the internal state */ + a = b = c = 0xdeadbeef + (((uint32_t)length) << 2) + initval; + + /* handle most of the key */ + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 3; + k += 3; + } + + /* handle the last 3 uint32_t's */ + switch(length) { + case 3 : + c += k[2]; + case 2 : + b += k[1]; + case 1 : + a += k[0]; + final(a, b, c); + case 0: + /* nothing left to add */ + break; + } + + return c; +} + +/** + * Hash a variable-length key into a 32-bit value + * @param k the key (the unaligned variable-length array of bytes) + * @param length the length of the key, counting by bytes + * @param initval can be any 4-byte value + * + * Returns a 32-bit value. Every bit of the key affects every bit of the + * return value. Two keys differing by one or two bits will have totally + * different hash values. + * + * The best hash table sizes are powers of 2. There is no need to do mod a + * prime (mod is sooo slow!). If you need less than 32 bits, use a bitmask. + * For example, if you need only 10 bits, do: + * h = (h & hashmask(10)); + * In which case, the hash table should have hashsize(10) elements. + * + * If you are hashing n strings (uint8_t **)k, do it like this: + * for (i=0, h=0; iendian == ARCH_ENDIAN_LITTLE) && + ((u.i & 0x3) == 0)) { + /* read 32-bit chunks */ + const uint32_t *k = (const uint32_t *)key; + + while (length > 12) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 12; + k += 3; + } + + /* "k[2]&0xffffff" actually reads beyond the end of the string, + * but then masks off the part it's not allowed to read. + * Because the string is aligned, the masked-off tail is in the + * same word as the rest of the string. Every machine with + * memory protection I've seen does it on word boundaries, so + * is OK with this. But VALGRIND will still catch it and + * complain. The masking trick does make the hash noticably + * faster for short strings (like English words). */ +#ifndef VALGRIND + + switch(length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff; + b += k[1]; + a += k[0]; + break; + case 9 : + c += k[2] & 0xff; + b += k[1]; + a += k[0]; + break; + case 8 : + b += k[1]; + a += k[0]; + break; + case 7 : + b += k[1] & 0xffffff; + a += k[0]; + break; + case 6 : + b += k[1] & 0xffff; + a += k[0]; + break; + case 5 : + b += k[1] & 0xff; + a += k[0]; + break; + case 4 : + a += k[0]; + break; + case 3 : + a += k[0] & 0xffffff; + break; + case 2 : + a += k[0] & 0xffff; + break; + case 1 : + a += k[0] & 0xff; + break; + case 0 : + /* zero length strings require no mixing */ + return c; + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t)k8[10]) << 16; + case 10: + c += ((uint32_t)k8[9]) << 8; + case 9 : + c += k8[8]; + case 8 : + b += k[1]; + a += k[0]; + break; + case 7 : + b += ((uint32_t)k8[6]) << 16; + case 6 : + b += ((uint32_t)k8[5]) << 8; + case 5 : + b += k8[4]; + case 4 : + a += k[0]; + break; + case 3 : + a += ((uint32_t)k8[2]) << 16; + case 2 : + a += ((uint32_t)k8[1]) << 8; + case 1 : + a += k8[0]; + break; + case 0 : + return c; + } + +#endif /* !valgrind */ + + } else if ((arch_def_native->endian == ARCH_ENDIAN_LITTLE) && + ((u.i & 0x1) == 0)) { + /* read 16-bit chunks */ + const uint16_t *k = (const uint16_t *)key; + const uint8_t *k8; + + while (length > 12) { + a += k[0] + (((uint32_t)k[1]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + c += k[4] + (((uint32_t)k[5]) << 16); + mix(a, b, c); + length -= 12; + k += 6; + } + + k8 = (const uint8_t *)k; + switch(length) { + case 12: + c += k[4] + (((uint32_t)k[5]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 11: + c += ((uint32_t)k8[10]) << 16; + case 10: + c += k[4]; + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 9 : + c += k8[8]; + case 8 : + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 7 : + b += ((uint32_t)k8[6]) << 16; + case 6 : + b += k[2]; + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 5 : + b += k8[4]; + case 4 : + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 3 : + a += ((uint32_t)k8[2]) << 16; + case 2 : + a += k[0]; + break; + case 1 : + a += k8[0]; + break; + case 0 : + /* zero length requires no mixing */ + return c; + } + + } else { + /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + while (length > 12) { + a += k[0]; + a += ((uint32_t)k[1]) << 8; + a += ((uint32_t)k[2]) << 16; + a += ((uint32_t)k[3]) << 24; + b += k[4]; + b += ((uint32_t)k[5]) << 8; + b += ((uint32_t)k[6]) << 16; + b += ((uint32_t)k[7]) << 24; + c += k[8]; + c += ((uint32_t)k[9]) << 8; + c += ((uint32_t)k[10]) << 16; + c += ((uint32_t)k[11]) << 24; + mix(a, b, c); + length -= 12; + k += 12; + } + + switch(length) { + case 12: + c += ((uint32_t)k[11]) << 24; + case 11: + c += ((uint32_t)k[10]) << 16; + case 10: + c += ((uint32_t)k[9]) << 8; + case 9 : + c += k[8]; + case 8 : + b += ((uint32_t)k[7]) << 24; + case 7 : + b += ((uint32_t)k[6]) << 16; + case 6 : + b += ((uint32_t)k[5]) << 8; + case 5 : + b += k[4]; + case 4 : + a += ((uint32_t)k[3]) << 24; + case 3 : + a += ((uint32_t)k[2]) << 16; + case 2 : + a += ((uint32_t)k[1]) << 8; + case 1 : + a += k[0]; + break; + case 0 : + return c; + } + } + + final(a, b, c); + return c; +} + +/** + * Hash a variable-length key into a 32-bit value + * @param k the key (the unaligned variable-length array of bytes) + * @param length the length of the key, counting by bytes + * @param initval can be any 4-byte value + * + * This is the same as jhash_word() on big-endian machines. It is different + * from jhash_le() on all machines. jhash_be() takes advantage of big-endian + * byte ordering. + * + */ +static uint32_t jhash_be( const void *key, size_t length, uint32_t initval) +{ + uint32_t a, b, c; + union { + const void *ptr; + size_t i; + } u; /* to cast key to (size_t) happily */ + + /* set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if ((arch_def_native->endian == ARCH_ENDIAN_BIG) && + ((u.i & 0x3) == 0)) { + /* read 32-bit chunks */ + const uint32_t *k = (const uint32_t *)key; + + while (length > 12) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 12; + k += 3; + } + + /* "k[2]<<8" actually reads beyond the end of the string, but + * then shifts out the part it's not allowed to read. Because + * the string is aligned, the illegal read is in the same word + * as the rest of the string. Every machine with memory + * protection I've seen does it on word boundaries, so is OK + * with this. But VALGRIND will still catch it and complain. + * The masking trick does make the hash noticably faster for + * short strings (like English words). */ +#ifndef VALGRIND + + switch(length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff00; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff0000; + b += k[1]; + a += k[0]; + break; + case 9 : + c += k[2] & 0xff000000; + b += k[1]; + a += k[0]; + break; + case 8 : + b += k[1]; + a += k[0]; + break; + case 7 : + b += k[1] & 0xffffff00; + a += k[0]; + break; + case 6 : + b += k[1] & 0xffff0000; + a += k[0]; + break; + case 5 : + b += k[1] & 0xff000000; + a += k[0]; + break; + case 4 : + a += k[0]; + break; + case 3 : + a += k[0] & 0xffffff00; + break; + case 2 : + a += k[0] & 0xffff0000; + break; + case 1 : + a += k[0] & 0xff000000; + break; + case 0 : + /* zero length strings require no mixing */ + return c; + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t)k8[10]) << 8; + case 10: + c += ((uint32_t)k8[9]) << 16; + case 9 : + c += ((uint32_t)k8[8]) << 24; + case 8 : + b += k[1]; + a += k[0]; + break; + case 7 : + b += ((uint32_t)k8[6]) << 8; + case 6 : + b += ((uint32_t)k8[5]) << 16; + case 5 : + b += ((uint32_t)k8[4]) << 24; + case 4 : + a += k[0]; + break; + case 3 : + a += ((uint32_t)k8[2]) << 8; + case 2 : + a += ((uint32_t)k8[1]) << 16; + case 1 : + a += ((uint32_t)k8[0]) << 24; + break; + case 0 : + return c; + } + +#endif /* !VALGRIND */ + + } else { + /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + while (length > 12) { + a += ((uint32_t)k[0]) << 24; + a += ((uint32_t)k[1]) << 16; + a += ((uint32_t)k[2]) << 8; + a += ((uint32_t)k[3]); + b += ((uint32_t)k[4]) << 24; + b += ((uint32_t)k[5]) << 16; + b += ((uint32_t)k[6]) << 8; + b += ((uint32_t)k[7]); + c += ((uint32_t)k[8]) << 24; + c += ((uint32_t)k[9]) << 16; + c += ((uint32_t)k[10]) << 8; + c += ((uint32_t)k[11]); + mix(a, b, c); + length -= 12; + k += 12; + } + + switch(length) { + case 12: + c += k[11]; + case 11: + c += ((uint32_t)k[10]) << 8; + case 10: + c += ((uint32_t)k[9]) << 16; + case 9 : + c += ((uint32_t)k[8]) << 24; + case 8 : + b += k[7]; + case 7 : + b += ((uint32_t)k[6]) << 8; + case 6 : + b += ((uint32_t)k[5]) << 16; + case 5 : + b += ((uint32_t)k[4]) << 24; + case 4 : + a += k[3]; + case 3 : + a += ((uint32_t)k[2]) << 8; + case 2 : + a += ((uint32_t)k[1]) << 16; + case 1 : + a += ((uint32_t)k[0]) << 24; + break; + case 0 : + return c; + } + } + + final(a, b, c); + return c; +} + +/** + * Hash a variable-length key into a 32-bit value + * @param k the key (the unaligned variable-length array of bytes) + * @param length the length of the key, counting by bytes + * @param initval can be any 4-byte value + * + * A small wrapper function that selects the proper hash function based on the + * native machine's byte-ordering. + * + */ +uint32_t jhash(const void *key, size_t length, uint32_t initval) +{ + if (length % sizeof(uint32_t) == 0) + return jhash_word(key, (length / sizeof(uint32_t)), initval); + else if (arch_def_native->endian == ARCH_ENDIAN_BIG) + return jhash_be(key, length, initval); + else + return jhash_le(key, length, initval); +} diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..efd252f --- /dev/null +++ b/src/hash.h @@ -0,0 +1,26 @@ +/** + * The "lookup3.c" Hash Implementation from Bob Jenkins + * + * Original Author: Bob Jenkins + * Source: http://burtleburtle.net/bob/c/lookup3.c + */ + +/* + * Original License: + * + * These are functions for producing 32-bit hashes for hash table lookup. + * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() + * are externally useful functions. Routines to test the hash are included + * if SELF_TEST is defined. You can use this free for any purpose. It's in + * the public domain. It has no warranty. + */ + +#ifndef _HASH_H +#define _HASH_H + +#include + +uint32_t jhash(const void *key, size_t length, uint32_t initval); + +#endif + diff --git a/src/python/Makefile b/src/python/Makefile new file mode 100644 index 0000000..3543a65 --- /dev/null +++ b/src/python/Makefile @@ -0,0 +1,54 @@ +# +# Enhanced Seccomp Library Python Bindings Makefile +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# +# macros +# + +include ../../macros.mk + +# +# configuration +# + +include $(TOPDIR)/version_info.mk +include $(TOPDIR)/configure.mk +include $(TOPDIR)/install.mk + +LIB_STATIC = ../libseccomp.a + +# +# targets +# + +.PHONY: all install clean + +all: build + +build: $(LIB_STATIC) libseccomp.pxd seccomp.pyx + @$(RM) seccomp.c + $(PY_BUILD) && touch build + +install: build + $(PY_INSTALL) install --prefix=$(DESTDIR)/$(INSTALL_PREFIX) + +clean: + $(RM) -rf build seccomp.c diff --git a/src/python/libseccomp.pxd b/src/python/libseccomp.pxd new file mode 100644 index 0000000..411b08e --- /dev/null +++ b/src/python/libseccomp.pxd @@ -0,0 +1,98 @@ +# +# Seccomp Library Python Bindings +# +# Copyright (c) 2012,2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +from libc.stdint cimport uint8_t, uint32_t, uint64_t + +cdef extern from "seccomp.h": + + ctypedef void* scmp_filter_ctx + + cdef enum: + SCMP_ARCH_NATIVE + SCMP_ARCH_X86 + SCMP_ARCH_X86_64 + SCMP_ARCH_X32 + SCMP_ARCH_ARM + + cdef enum scmp_filter_attr: + SCMP_FLTATR_ACT_DEFAULT + SCMP_FLTATR_ACT_BADARCH + SCMP_FLTATR_CTL_NNP + + cdef enum scmp_compare: + SCMP_CMP_NE + SCMP_CMP_LT + SCMP_CMP_LE + SCMP_CMP_EQ + SCMP_CMP_GE + SCMP_CMP_GT + SCMP_CMP_MASKED_EQ + + cdef enum: + SCMP_ACT_KILL + SCMP_ACT_TRAP + SCMP_ACT_ALLOW + unsigned int SCMP_ACT_ERRNO(int errno) + unsigned int SCMP_ACT_TRACE(int value) + + ctypedef uint64_t scmp_datum_t + + cdef struct scmp_arg_cmp: + unsigned int arg + scmp_compare op + scmp_datum_t datum_a + scmp_datum_t datum_b + + scmp_filter_ctx seccomp_init(uint32_t def_action) + int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action) + void seccomp_release(scmp_filter_ctx ctx) + + int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src) + + uint32_t seccomp_arch_native() + int seccomp_arch_exist(scmp_filter_ctx ctx, uint32_t arch_token) + int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token) + int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token) + + int seccomp_load(scmp_filter_ctx ctx) + + int seccomp_attr_get(scmp_filter_ctx ctx, + scmp_filter_attr attr, uint32_t* value) + int seccomp_attr_set(scmp_filter_ctx ctx, + scmp_filter_attr attr, uint32_t value) + + char *seccomp_syscall_resolve_num_arch(uint32_t arch_token, int num) + int seccomp_syscall_resolve_name_arch(uint32_t arch_token, char *name) + int seccomp_syscall_resolve_name(char *name) + int seccomp_syscall_priority(scmp_filter_ctx ctx, + int syscall, uint8_t priority) + + int seccomp_rule_add(scmp_filter_ctx ctx, uint32_t action, + int syscall, unsigned int arg_cnt, ...) + + int seccomp_rule_add_exact(scmp_filter_ctx ctx, uint32_t action, + int syscall, unsigned int arg_cnt, ...) + + int seccomp_export_pfc(scmp_filter_ctx ctx, int fd) + int seccomp_export_bpf(scmp_filter_ctx ctx, int fd) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/src/python/seccomp.pyx b/src/python/seccomp.pyx new file mode 100644 index 0000000..47d2ae1 --- /dev/null +++ b/src/python/seccomp.pyx @@ -0,0 +1,572 @@ +# +# Seccomp Library Python Bindings +# +# Copyright (c) 2012,2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +""" Python bindings for the libseccomp library + +The libseccomp library provides and easy to use, platform independent, +interface to the Linux Kernel's syscall filtering mechanism: seccomp. The +libseccomp API is designed to abstract away the underlying BPF based +syscall filter language and present a more conventional function-call +based filtering interface that should be familiar to, and easily adopted +by application developers. + +Filter action values: + KILL - kill the process + ALLOW - allow the syscall to execute + TRAP - a SIGSYS signal will be thrown + ERRNO(x) - syscall will return (x) + TRACE(x) - if the process is being traced, (x) will be returned to the + tracing process via PTRACE_EVENT_SECCOMP and the + PTRACE_GETEVENTMSG option + +Argument comparison values (see the Arg class): + + NE - arg != datum_a + LT - arg < datum_a + LE - arg <= datum_a + EQ - arg == datum_a + GT - arg > datum_a + GE - arg >= datum_a + MASKED_EQ - (arg & datum_b) == datum_a + + +Example: + + import sys + from seccomp import * + + # create a filter object with a default KILL action + f = SyscallFilter(defaction=KILL) + + # add syscall filter rules to allow certain syscalls + f.add_rule(ALLOW, "open") + f.add_rule(ALLOW, "close") + f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin)) + f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout)) + f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stderr)) + f.add_rule(ALLOW, "rt_sigreturn") + + # load the filter into the kernel + f.load() +""" +__author__ = 'Paul Moore ' +__date__ = "7 January 2013" + +from libc.stdint cimport uint32_t +import errno + +cimport libseccomp + +KILL = libseccomp.SCMP_ACT_KILL +TRAP = libseccomp.SCMP_ACT_TRAP +ALLOW = libseccomp.SCMP_ACT_ALLOW +def ERRNO(int errno): + return libseccomp.SCMP_ACT_ERRNO(errno) +def TRACE(int value): + return libseccomp.SCMP_ACT_TRACE(value) + +NE = libseccomp.SCMP_CMP_NE +LT = libseccomp.SCMP_CMP_LT +LE = libseccomp.SCMP_CMP_LE +EQ = libseccomp.SCMP_CMP_EQ +GE = libseccomp.SCMP_CMP_GE +GT = libseccomp.SCMP_CMP_GT +MASKED_EQ = libseccomp.SCMP_CMP_MASKED_EQ + +def system_arch(): + """ Return the system architecture value. + + Description: + Returns the native system architecture value. + """ + return libseccomp.seccomp_arch_native() + +def resolve_syscall(arch, syscall): + """ Resolve the syscall. + + Arguments: + arch - the architecture value, e.g. Arch.* + syscall - the syscall name or number + + Description: + Resolve an architecture's syscall name to the correct number or the + syscall number to the correct name. + """ + if (isinstance(syscall, basestring)): + return libseccomp.seccomp_syscall_resolve_name_arch(arch, syscall) + elif (isinstance(syscall, int)): + return libseccomp.seccomp_syscall_resolve_num_arch(arch, syscall) + else: + raise TypeError("Syscall must either be an int or str type") + +cdef class Arch: + """ Python object representing the SyscallFilter architecture values. + + Data values: + NATIVE - the native architecture + X86 - 32-bit x86 + X86_64 - 64-bit x86 + X32 - 64-bit x86 using the x32 ABI + ARM - ARM + """ + + NATIVE = libseccomp.SCMP_ARCH_NATIVE + X86 = libseccomp.SCMP_ARCH_X86 + X86_64 = libseccomp.SCMP_ARCH_X86_64 + X32 = libseccomp.SCMP_ARCH_X32 + ARM = libseccomp.SCMP_ARCH_ARM + +cdef class Attr: + """ Python object representing the SyscallFilter attributes. + + Data values: + ACT_DEFAULT - the filter's default action + ACT_BADARCH - the filter's bad architecture action + CTL_NNP - the filter's "no new privileges" flag + """ + ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT + ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH + CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP + +cdef class Arg: + """ Python object representing a SyscallFilter syscall argument. + """ + cdef libseccomp.scmp_arg_cmp _arg + + def __cinit__(self, arg, op, datum_a, datum_b = 0): + """ Initialize the argument comparison. + + Arguments: + arg - the arguement number, starting at 0 + op - the argument comparison operator, e.g. {NE,LT,LE,...} + datum_a - argument value + datum_b - argument value, only valid when op == MASKED_EQ + + Description: + Create an argument comparison object for use with SyscallFilter. + """ + self._arg.arg = arg + self._arg.op = op + self._arg.datum_a = datum_a + self._arg.datum_b = datum_b + + def to_c(self): + """ Convert the object into a C structure. + + Description: + Helper function which should only be used internally by + SyscallFilter objects and exists for the sole purpose of making it + easier to deal with the varadic functions of the libseccomp API, + e.g. seccomp_rule_add(). + """ + return self._arg + +cdef class SyscallFilter: + """ Python object representing a seccomp syscall filter. """ + cdef int _defaction + cdef libseccomp.scmp_filter_ctx _ctx + + def __cinit__(self, int defaction): + self._ctx = libseccomp.seccomp_init(defaction) + if self._ctx == NULL: + raise RuntimeError("Library error") + _defaction = defaction + + def __init__(self, defaction): + """ Initialize the filter state + + Arguments: + defaction - the default filter action + + Description: + Initializes the seccomp filter state to the defaults. + """ + + def __dealloc__(self): + """ Destroys the filter state and releases any resources. + + Description: + Destroys the seccomp filter state and releases any resources + associated with the filter state. This function does not affect + any seccomp filters already loaded into the kernel. + """ + if self._ctx != NULL: + libseccomp.seccomp_release(self._ctx) + + def reset(self, int defaction = -1): + """ Reset the filter state. + + Arguments: + defaction - the default filter action + + Description: + Resets the seccomp filter state to an initial default state, if a + default filter action is not specified in the reset call the + original action will be reused. This function does not affect any + seccomp filters alread loaded into the kernel. + """ + if defaction == -1: + defaction = self._defaction + rc = libseccomp.seccomp_reset(self._ctx, defaction) + if rc == -errno.EINVAL: + raise ValueError("Invalid action") + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + _defaction = defaction + + def merge(self, SyscallFilter filter): + """ Merge two existing SyscallFilter objects. + + Arguments: + filter - a valid SyscallFilter object + + Description: + Merges a valid SyscallFilter object with the current SyscallFilter + object; the passed filter object will be reset on success. In + order to successfully merge two seccomp filters they must have the + same attribute values and not share any of the same architectures. + """ + rc = libseccomp.seccomp_merge(self._ctx, filter._ctx) + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + filter._ctx = NULL + filter = SyscallFilter(filter._defaction) + + def exist_arch(self, arch): + """ Check if the seccomp filter contains a given architecture. + + Arguments: + arch - the architecture value, e.g. Arch.* + + Description: + Test to see if a given architecture is included in the filter. + Return True is the architecture exists, False if it does not + exist. + """ + rc = libseccomp.seccomp_arch_exist(self._ctx, arch) + if rc == 0: + return True + elif rc == -errno.EEXIST: + return False + elif rc == -errno.EINVAL: + raise ValueError("Invalid architecture") + else: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def add_arch(self, arch): + """ Add an architecture to the filter. + + Arguments: + arch - the architecture value, e.g. Arch.* + + Description: + Add the given architecture to the filter. Any new rules added + after this method returns successfully will be added to this new + architecture, but any existing rules will not be added to the new + architecture. + """ + rc = libseccomp.seccomp_arch_add(self._ctx, arch) + if rc == -errno.EINVAL: + raise ValueError("Invalid architecture") + elif rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def remove_arch(self, arch): + """ Remove an architecture from the filter. + + Arguments: + arch - the architecture value, e.g. Arch.* + + Description: + Remove the given architecture from the filter. The filter must + always contain at least one architecture, so if only one + architecture exists in the filter this method will fail. + """ + rc = libseccomp.seccomp_arch_remove(self._ctx, arch) + if rc == -errno.EINVAL: + raise ValueError("Invalid architecture") + elif rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def load(self): + """ Load the filter into the Linux Kernel. + + Description: + Load the current filter into the Linux Kernel. As soon as the + method returns the filter will be active and enforcing. + """ + rc = libseccomp.seccomp_load(self._ctx) + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def get_attr(self, attr): + """ Get an attribute value from the filter. + + Arguments: + attr - the attribute, e.g. Attr.* + + Description: + Lookup the given attribute in the filter and return the + attribute's value to the caller. + """ + value = 0 + rc = libseccomp.seccomp_attr_get(self._ctx, + attr, &value) + if rc == -errno.EINVAL: + raise ValueError("Invalid attribute") + elif rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + return value + + def set_attr(self, attr, int value): + """ Set a filter attribute. + + Arguments: + attr - the attribute, e.g. Attr.* + value - the attribute value + + Description: + Lookup the given attribute in the filter and assign it the given + value. + """ + rc = libseccomp.seccomp_attr_set(self._ctx, attr, value) + if rc == -errno.EINVAL: + raise ValueError("Invalid attribute") + elif rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def syscall_priority(self, syscall, int priority): + """ Set the filter priority of a syscall. + + Arguments: + syscall - the syscall name or number + priority - the priority of the syscall + + Description: + Set the filter priority of the given syscall. A syscall with a + higher priority will have less overhead in the generated filter + code which is loaded into the system. Priority values can range + from 0 to 255 inclusive. + """ + if priority < 0 or priority > 255: + raise ValueError("Syscall priority must be between 0 and 255") + if isinstance(syscall, str): + syscall_str = syscall.encode() + syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str) + elif isinstance(syscall, int): + syscall_num = syscall + else: + raise TypeError("Syscall must either be an int or str type") + rc = libseccomp.seccomp_syscall_priority(self._ctx, + syscall_num, priority) + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def add_rule(self, int action, syscall, *args): + """ Add a new rule to filter. + + Arguments: + action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW + syscall - the syscall name or number + args - variable number of Arg objects + + Description: + Add a new rule to the filter, matching on the given syscall and an + optional list of argument comparisons. If the rule is triggered + the given action will be taken by the kernel. In order for the + rule to trigger, the syscall as well as each argument comparison + must be true. + + In the case where the specific rule is not valid on a specific + architecture, e.g. socket() on 32-bit x86, this method rewrites + the rule to the best possible match. If you don't want this fule + rewriting to take place use add_rule_exactly(). + """ + cdef libseccomp.scmp_arg_cmp c_arg[6] + if isinstance(syscall, str): + syscall_str = syscall.encode() + syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str) + elif isinstance(syscall, int): + syscall_num = syscall + else: + raise TypeError("Syscall must either be an int or str type") + """ NOTE: the code below exists solely to deal with the varadic + nature of seccomp_rule_add() function and the inability of Cython + to handle this automatically """ + for i, arg in enumerate(args): + c_arg[i] = arg.to_c() + if len(args) == 0: + rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, 0) + elif len(args) == 1: + rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, + len(args), + c_arg[0]) + elif len(args) == 2: + rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, + len(args), + c_arg[0], + c_arg[1]) + elif len(args) == 3: + rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, + len(args), + c_arg[0], + c_arg[1], + c_arg[2]) + elif len(args) == 4: + rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, + len(args), + c_arg[0], + c_arg[1], + c_arg[2], + c_arg[3]) + elif len(args) == 5: + rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, + len(args), + c_arg[0], + c_arg[1], + c_arg[2], + c_arg[3], + c_arg[4]) + elif len(args) == 6: + rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, + len(args), + c_arg[0], + c_arg[1], + c_arg[2], + c_arg[3], + c_arg[4], + c_arg[5]) + else: + raise RuntimeError("Maximum number of arguments exceeded") + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def add_rule_exactly(self, int action, syscall, *args): + """ Add a new rule to filter. + + Arguments: + action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW + syscall - the syscall name or number + args - variable number of Arg objects + + Description: + Add a new rule to the filter, matching on the given syscall and an + optional list of argument comparisons. If the rule is triggered + the given action will be taken by the kernel. In order for the + rule to trigger, the syscall as well as each argument comparison + must be true. + + This method attempts to add the filter rule exactly as specified + which can cause problems on certain architectures, e.g. socket() + on 32-bit x86. For a architecture independent version of this + method use add_rule(). + """ + cdef libseccomp.scmp_arg_cmp c_arg[6] + if isinstance(syscall, str): + syscall_str = syscall.encode() + syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str) + elif isinstance(syscall, int): + syscall_num = syscall + else: + raise TypeError("Syscall must either be an int or str type") + """ NOTE: the code below exists solely to deal with the varadic + nature of seccomp_rule_add_exact() function and the inability of + Cython to handle this automatically """ + for i, arg in enumerate(args): + c_arg[i] = arg.to_c() + if len(args) == 0: + rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, + syscall_num, 0) + elif len(args) == 1: + rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, + syscall_num, len(args), + c_arg[0]) + elif len(args) == 2: + rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, + syscall_num, len(args), + c_arg[0], + c_arg[1]) + elif len(args) == 3: + rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, + syscall_num, len(args), + c_arg[0], + c_arg[1], + c_arg[2]) + elif len(args) == 4: + rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, + syscall_num, len(args), + c_arg[0], + c_arg[1], + c_arg[2], + c_arg[3]) + elif len(args) == 5: + rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, + syscall_num, len(args), + c_arg[0], + c_arg[1], + c_arg[2], + c_arg[3], + c_arg[4]) + elif len(args) == 6: + rc = libseccomp.seccomp_rule_add_exact(self._ctx, action, + syscall_num, len(args), + c_arg[0], + c_arg[1], + c_arg[2], + c_arg[3], + c_arg[4], + c_arg[5]) + else: + raise RuntimeError("Maximum number of arguments exceeded") + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def export_pfc(self, file): + """ Export the filter in PFC format. + + Arguments: + file - the output file + + Description: + Output the filter in Pseudo Filter Code (PFC) to the given file. + The output is functionally equivalent to the BPF based filter + which is loaded into the Linux Kernel. + """ + rc = libseccomp.seccomp_export_pfc(self._ctx, file.fileno()) + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + + def export_bpf(self, file): + """ Export the filter in BPF format. + + Arguments: + file - the output file + + Output the filter in Berkley Packet Filter (BPF) to the given + file. The output is identical to what is loaded into the + Linux Kernel. + """ + rc = libseccomp.seccomp_export_bpf(self._ctx, file.fileno()) + if rc != 0: + raise RuntimeError(str.format("Library error (errno = {0})", rc)) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/src/python/setup.py b/src/python/setup.py new file mode 100644 index 0000000..872642e --- /dev/null +++ b/src/python/setup.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# +# Enhanced Seccomp Library Python Module Build Script +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import os + +from distutils.core import setup +from distutils.extension import Extension +from Cython.Distutils import build_ext + +setup( + name = "seccomp", + version = os.environ["VERSION_RELEASE"], + description = "Python binding for libseccomp", + long_description = "Python API for the Linux Kernel's syscall filtering capability, seccomp.", + url = "http://libseccomp.sf.net", + maintainer = "Paul Moore", + maintainer_email = "paul@paul-moore.com", + license = "LGPLv2.1", + platforms = "Linux", + cmdclass = {'build_ext': build_ext}, + ext_modules = [ + Extension("seccomp", ["seccomp.pyx"], + extra_objects=["../libseccomp.a"]) + ] +) diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..cb14f65 --- /dev/null +++ b/src/system.h @@ -0,0 +1,92 @@ +/** + * Seccomp System Information + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _SYSTEM_H +#define _SYSTEM_H + +#include +#include + +#include + +#ifdef CONF_SYSINC_SECCOMP + +/* system header file */ +#include + +#else + +/* NOTE: the definitions below were taken from the Linux Kernel sources */ +#include + +/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, ) */ +#define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */ +#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ +#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ + +/* + * All BPF programs must return a 32-bit value. + * The bottom 16-bits are for optional return data. + * The upper 16-bits are ordered from least permissive values to most. + * + * The ordering ensures that a min_t() over composed return values always + * selects the least permissive choice. + */ +#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ +#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ +#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ +#define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ +#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ + +/* Masks for the return value sections. */ +#define SECCOMP_RET_ACTION 0x7fff0000U +#define SECCOMP_RET_DATA 0x0000ffffU + +/* + * struct seccomp_data - the format the BPF program executes over. + * @nr: the system call number + * @arch: indicates system call convention as an AUDIT_ARCH_* value + * as defined in . + * @instruction_pointer: at the time of the system call. + * @args: up to 6 system call arguments always stored as 64-bit values + * regardless of the architecture. + */ +struct seccomp_data { + int nr; + __u32 arch; + __u64 instruction_pointer; + __u64 args[6]; +}; + +#endif /* CONF_SYSINC_SECCOMP */ + +/* rename some of the socket filter types to make more sense */ +typedef struct sock_filter bpf_instr_raw; + +#ifndef PR_SET_NO_NEW_PRIVS +#define PR_SET_NO_NEW_PRIVS 38 +#endif /* PR_SET_NO_NEW_PRIVS */ + +#ifndef PR_GET_NO_NEW_PRIVS +#define PR_GET_NO_NEW_PRIVS 39 +#endif /* PR_GET_NO_NEW_PRIVS */ + +#endif diff --git a/tags b/tags new file mode 100644 index 0000000..416dcf6 --- /dev/null +++ b/tags @@ -0,0 +1,779 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.8 // +ACT_BADARCH src/python/seccomp.pyx /^ ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH$/;" v class:Attr +ACT_DEFAULT src/python/seccomp.pyx /^ ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT$/;" v class:Attr +ADDDEP macros.mk /^ADDDEP = \\$/;" m +AINC_BLK src/gen_bpf.c 39;" d file: +AINC_PROG src/gen_bpf.c 40;" d file: +ALLOW src/python/seccomp.pyx /^ALLOW = libseccomp.SCMP_ACT_ALLOW$/;" v +ARCHIVE macros.mk /^ ARCHIVE = @echo " AR $@";$/;" m +ARCH_ENDIAN_BIG src/arch.h /^ ARCH_ENDIAN_BIG,$/;" e enum:arch_def::__anon3 +ARCH_ENDIAN_LITTLE src/arch.h /^ ARCH_ENDIAN_LITTLE,$/;" e enum:arch_def::__anon3 +ARCH_ENDIAN_UNSPEC src/arch.h /^ ARCH_ENDIAN_UNSPEC = 0,$/;" e enum:arch_def::__anon3 +ARCH_SIZE_32 src/arch.h /^ ARCH_SIZE_32 = 32,$/;" e enum:arch_def::__anon2 +ARCH_SIZE_64 src/arch.h /^ ARCH_SIZE_64 = 64,$/;" e enum:arch_def::__anon2 +ARCH_SIZE_UNSPEC src/arch.h /^ ARCH_SIZE_UNSPEC = 0,$/;" e enum:arch_def::__anon2 +ARG_COUNT_MAX src/arch.h 76;" d +ARG_MASK_MAX src/db.h 70;" d +ARM src/python/seccomp.pyx /^ ARM = libseccomp.SCMP_ARCH_ARM$/;" v class:Arch +AWK macros.mk /^AWK ?= awk$/;" m +Arch src/python/seccomp.pyx /^cdef class Arch:$/;" c +Arg src/python/seccomp.pyx /^cdef class Arg:$/;" c +Attr src/python/seccomp.pyx /^cdef class Attr:$/;" c +BINDINGS src/Makefile /^BINDINGS =$/;" m +BPF_A tools/bpf.h 117;" d +BPF_ABS tools/bpf.h 87;" d +BPF_ADD tools/bpf.h 95;" d +BPF_ALU tools/bpf.h 75;" d +BPF_AND tools/bpf.h 100;" d +BPF_B tools/bpf.h 84;" d +BPF_CLASS tools/bpf.h 70;" d +BPF_DIV tools/bpf.h 98;" d +BPF_H tools/bpf.h 83;" d +BPF_IMM tools/bpf.h 86;" d +BPF_IND tools/bpf.h 88;" d +BPF_JA tools/bpf.h 105;" d +BPF_JEQ tools/bpf.h 106;" d +BPF_JGE tools/bpf.h 108;" d +BPF_JGT tools/bpf.h 107;" d +BPF_JMP tools/bpf.h 76;" d +BPF_JSET tools/bpf.h 109;" d +BPF_K tools/bpf.h 112;" d +BPF_LD tools/bpf.h 71;" d +BPF_LDX tools/bpf.h 72;" d +BPF_LEN tools/bpf.h 90;" d +BPF_LSH tools/bpf.h 101;" d +BPF_MEM tools/bpf.h 89;" d +BPF_MISC tools/bpf.h 78;" d +BPF_MISCOP tools/bpf.h 120;" d +BPF_MODE tools/bpf.h 85;" d +BPF_MSH tools/bpf.h 91;" d +BPF_MUL tools/bpf.h 97;" d +BPF_NEG tools/bpf.h 103;" d +BPF_OP tools/bpf.h 93;" d +BPF_OR tools/bpf.h 99;" d +BPF_PGM_SIZE src/gen_bpf.h 36;" d +BPF_PRG_MAX_LEN tools/scmp_bpf_sim.c 36;" d file: +BPF_RET tools/bpf.h 77;" d +BPF_RSH tools/bpf.h 102;" d +BPF_RVAL tools/bpf.h 116;" d +BPF_SCRATCH_SIZE tools/bpf.h 33;" d +BPF_SIZE tools/bpf.h 81;" d +BPF_SRC tools/bpf.h 111;" d +BPF_ST tools/bpf.h 73;" d +BPF_STX tools/bpf.h 74;" d +BPF_SUB tools/bpf.h 96;" d +BPF_SYSCALL_MAX tools/bpf.h 45;" d +BPF_SYS_ARG_MAX tools/bpf.h 38;" d +BPF_TAX tools/bpf.h 121;" d +BPF_TXA tools/bpf.h 122;" d +BPF_W tools/bpf.h 82;" d +BPF_X tools/bpf.h 113;" d +CAT macros.mk /^CAT ?= cat$/;" m +CFLAGS macros.mk /^CFLAGS ?= -Wl,-z,relro -Wall -O0 -g$/;" m +COMPILE macros.mk /^ COMPILE = @echo " CC $@";$/;" m +COMPILE_EXEC macros.mk /^ COMPILE_EXEC = @echo " CC $@";$/;" m +CONFIGS Makefile /^CONFIGS = configure.mk configure.h version_info.mk libseccomp.pc$/;" m +CONF_BINDINGS_PYTHON configure.h 8;" d +CONF_BINDINGS_PYTHON configure.mk /^CONF_BINDINGS_PYTHON = 1$/;" m +CONF_INSTALL_LIBDIR configure.mk /^CONF_INSTALL_LIBDIR = "\/usr\/local\/lib"$/;" m +CONF_INSTALL_PREFIX configure.mk /^CONF_INSTALL_PREFIX = "\/usr\/local"$/;" m +CONF_SYSINC_SECCOMP configure.h 7;" d +CONF_SYSINC_SECCOMP configure.mk /^CONF_SYSINC_SECCOMP = 1$/;" m +CTL_NNP src/python/seccomp.pyx /^ CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP$/;" v class:Attr +D64_HI src/arch.h 74;" d +D64_LO src/arch.h 73;" d +DATUM_MAX src/arch.h 72;" d +DEPS src/Makefile /^DEPS = $(OBJS:%.o=%.d)$/;" m +DEPS tools/Makefile /^DEPS = $(TOOLS:%=%.d)$/;" m +DEPS_OBJS tests/Makefile /^DEPS_OBJS = $(OBJS:%.o=%.d)$/;" m +DEPS_TESTS tests/Makefile /^DEPS_TESTS = $(TESTS:%=%.d)$/;" m +ECHO macros.mk /^ECHO ?= echo$/;" m +ECHO_INFO macros.mk /^ ECHO_INFO ?= $(ECHO) ">> INFO:"$/;" m +ECHO_INFO macros.mk /^ ECHO_INFO ?= \/bin\/true || $(ECHO) ">> INFO:"$/;" m +EQ src/python/seccomp.pyx /^EQ = libseccomp.SCMP_CMP_EQ$/;" v +ERRNO src/python/seccomp.pyx /^def ERRNO(int errno):$/;" f +Extension src/python/setup.py /^from distutils.extension import Extension$/;" i +GCC macros.mk /^GCC ?= gcc$/;" m +GE src/python/seccomp.pyx /^GE = libseccomp.SCMP_CMP_GE$/;" v +GT src/python/seccomp.pyx /^GT = libseccomp.SCMP_CMP_GT$/;" v +HASH_BIG_ENDIAN src/hash.c 55;" d file: +HASH_BIG_ENDIAN src/hash.c 60;" d file: +HASH_BIG_ENDIAN src/hash.c 63;" d file: +HASH_LITTLE_ENDIAN src/hash.c 54;" d file: +HASH_LITTLE_ENDIAN src/hash.c 59;" d file: +HASH_LITTLE_ENDIAN src/hash.c 62;" d file: +HDR_BUILD include/Makefile /^HDR_BUILD = seccomp.h$/;" m +INSTALL macros.mk /^INSTALL ?= install$/;" m +INSTALL_BIN_DIR install.mk /^INSTALL_BIN_DIR ?= $(DESTDIR)\/$(INSTALL_PREFIX)\/bin$/;" m +INSTALL_BIN_MACRO macros.mk /^ INSTALL_BIN_MACRO = @echo " INSTALL $^ ($(INSTALL_BIN_DIR)\/$^)";$/;" m +INSTALL_GROUP install.mk /^INSTALL_GROUP ?= $$(id -g)$/;" m +INSTALL_INC_DIR install.mk /^INSTALL_INC_DIR ?= $(DESTDIR)\/$(INSTALL_PREFIX)\/include$/;" m +INSTALL_INC_MACRO macros.mk /^ INSTALL_INC_MACRO = @echo " INSTALL $^ ($(INSTALL_INC_DIR))";$/;" m +INSTALL_LIB_DIR install.mk /^INSTALL_LIB_DIR ?= $(DESTDIR)\/$(CONF_INSTALL_LIBDIR)$/;" m +INSTALL_LIB_MACRO macros.mk /^ INSTALL_LIB_MACRO = @echo " INSTALL $^ ($(INSTALL_LIB_DIR)\/$^)";$/;" m +INSTALL_MAN1_MACRO macros.mk /^ INSTALL_MAN1_MACRO = \\$/;" m +INSTALL_MAN3_MACRO macros.mk /^ INSTALL_MAN3_MACRO = \\$/;" m +INSTALL_MAN_DIR install.mk /^INSTALL_MAN_DIR ?= $(DESTDIR)\/$(INSTALL_PREFIX)\/share\/man$/;" m +INSTALL_OWNER install.mk /^INSTALL_OWNER ?= $$(id -u)$/;" m +INSTALL_PC_MACRO macros.mk /^ INSTALL_PC_MACRO = \\$/;" m +INSTALL_PREFIX install.mk /^INSTALL_PREFIX ?= $(CONF_INSTALL_PREFIX)$/;" m +INSTALL_SBIN_DIR install.mk /^INSTALL_SBIN_DIR ?= $(DESTDIR)\/$(INSTALL_PREFIX)\/sbin$/;" m +KILL src/python/seccomp.pyx /^KILL = libseccomp.SCMP_ACT_KILL$/;" v +LDFLAGS macros.mk /^LDFLAGS ?= -z relro -g$/;" m +LDFLAGS tests/Makefile /^LDFLAGS := ..\/src\/libseccomp.a $(OBJS)$/;" m +LDFLAGS tools/Makefile /^LDFLAGS := ..\/src\/libseccomp.a$/;" m +LE src/python/seccomp.pyx /^LE = libseccomp.SCMP_CMP_LE$/;" v +LIBFLAGS macros.mk /^LIBFLAGS =$/;" m +LIB_SHARED src/Makefile /^LIB_SHARED = libseccomp.so.$(VERSION_RELEASE)$/;" m +LIB_STATIC src/Makefile /^LIB_STATIC = libseccomp.a$/;" m +LIB_STATIC src/python/Makefile /^LIB_STATIC = ..\/libseccomp.a$/;" m +LINK_EXEC macros.mk /^ LINK_EXEC = @echo " LD $@";$/;" m +LINK_LIB macros.mk /^ LINK_LIB = @echo " LD $@" \\$/;" m +LN macros.mk /^LN ?= ln$/;" m +LT src/python/seccomp.pyx /^LT = libseccomp.SCMP_CMP_LT$/;" v +MAKEDEP macros.mk /^MAKEDEP = @$(GCC) $(CPPFLAGS) -MM -MF $(patsubst %.o,%.d,$@) $<;$/;" m +MAKEDEP_EXEC macros.mk /^MAKEDEP_EXEC = \\$/;" m +MAN1 doc/Makefile /^MAN1 = \\$/;" m +MAN3 doc/Makefile /^MAN3 = \\$/;" m +MASKED_EQ src/python/seccomp.pyx /^MASKED_EQ = libseccomp.SCMP_CMP_MASKED_EQ$/;" v +MKDIR macros.mk /^MKDIR ?= mkdir$/;" m +MV macros.mk /^MV ?= mv$/;" m +NATIVE src/python/seccomp.pyx /^ NATIVE = libseccomp.SCMP_ARCH_NATIVE$/;" v class:Arch +NE src/python/seccomp.pyx /^NE = libseccomp.SCMP_CMP_NE$/;" v +OBJS src/Makefile /^OBJS = \\$/;" m +OBJS tests/Makefile /^OBJS = util.o$/;" m +PR_GET_NO_NEW_PRIVS src/system.h 89;" d +PR_SET_NO_NEW_PRIVS src/system.h 85;" d +PYTHON macros.mk /^PYTHON ?= \/usr\/bin\/env python$/;" m +PY_BUILD macros.mk /^ PY_BUILD = @echo " PYTHON build";$/;" m +PY_DISTUTILS macros.mk /^PY_DISTUTILS = \\$/;" m +PY_INSTALL macros.mk /^ PY_INSTALL = @echo " PYTHON install";$/;" m +SECCOMP_MODE_DISABLED src/system.h 41;" d +SECCOMP_MODE_FILTER src/system.h 43;" d +SECCOMP_MODE_STRICT src/system.h 42;" d +SECCOMP_RET_ACTION src/system.h 60;" d +SECCOMP_RET_ACTION tools/bpf.h 59;" d +SECCOMP_RET_ALLOW src/system.h 57;" d +SECCOMP_RET_ALLOW tools/bpf.h 67;" d +SECCOMP_RET_DATA src/system.h 61;" d +SECCOMP_RET_DATA tools/bpf.h 60;" d +SECCOMP_RET_ERRNO src/system.h 55;" d +SECCOMP_RET_ERRNO tools/bpf.h 65;" d +SECCOMP_RET_KILL src/system.h 53;" d +SECCOMP_RET_KILL tools/bpf.h 63;" d +SECCOMP_RET_TRACE src/system.h 56;" d +SECCOMP_RET_TRACE tools/bpf.h 66;" d +SECCOMP_RET_TRAP src/system.h 54;" d +SECCOMP_RET_TRAP tools/bpf.h 64;" d +SED macros.mk /^SED ?= sed$/;" m +SHELL macros.mk /^SHELL = \/bin\/bash$/;" m +SUBDIRS_BUILD Makefile /^SUBDIRS_BUILD = include src tests tools$/;" m +SUBDIRS_INSTALL Makefile /^SUBDIRS_INSTALL = include src tools doc$/;" m +SyscallFilter src/python/seccomp.pyx /^cdef class SyscallFilter:$/;" c +TAR macros.mk /^TAR ?= tar$/;" m +TESTS tests/Makefile /^TESTS = 01-sim-allow \\$/;" m +TEST_PRIVATE tests/Makefile /^TEST_PRIVATE = 00-test$/;" m +TGT_IMM src/gen_bpf.c /^ TGT_IMM, \/* resolved immediate value *\/$/;" e enum:bpf_jump_type file: +TGT_K src/gen_bpf.c /^ TGT_K, \/* immediate "k" value *\/$/;" e enum:bpf_jump_type file: +TGT_NONE src/gen_bpf.c /^ TGT_NONE = 0,$/;" e enum:bpf_jump_type file: +TGT_NXT src/gen_bpf.c /^ TGT_NXT, \/* fall through to the next block *\/$/;" e enum:bpf_jump_type file: +TGT_PTR_BLK src/gen_bpf.c /^ TGT_PTR_BLK, \/* pointer to an instruction block *\/$/;" e enum:bpf_jump_type file: +TGT_PTR_DB src/gen_bpf.c /^ TGT_PTR_DB, \/* pointer to part of the filter db *\/$/;" e enum:bpf_jump_type file: +TGT_PTR_HSH src/gen_bpf.c /^ TGT_PTR_HSH, \/* pointer to a block hash table *\/$/;" e enum:bpf_jump_type file: +TOOLS tools/Makefile /^TOOLS = scmp_bpf_disasm \\$/;" m +TOOLS_INSTALL tools/Makefile /^TOOLS_INSTALL = scmp_sys_resolver$/;" m +TOPDIR macros.mk /^TOPDIR := $(shell \\$/;" m +TRACE src/python/seccomp.pyx /^def TRACE(int value):$/;" f +TRAP src/python/seccomp.pyx /^TRAP = libseccomp.SCMP_ACT_TRAP$/;" v +V macros.mk /^V ?= 0$/;" m +VERSION_HDR macros.mk /^VERSION_HDR = version.h$/;" m +VERSION_MAJOR version.h 5;" d +VERSION_MAJOR version_info.mk /^VERSION_MAJOR=0$/;" m +VERSION_MICRO version.h 7;" d +VERSION_MICRO version_info.mk /^VERSION_MICRO=0$/;" m +VERSION_MINOR version.h 6;" d +VERSION_MINOR version_info.mk /^VERSION_MINOR=0$/;" m +VERSION_RELEASE version.h 4;" d +VERSION_RELEASE version_info.mk /^VERSION_RELEASE=0.0.0$/;" m +X32 src/python/seccomp.pyx /^ X32 = libseccomp.SCMP_ARCH_X32$/;" v class:Arch +X32_SYSCALL_BIT src/arch-x32.h 30;" d +X86 src/python/seccomp.pyx /^ X86 = libseccomp.SCMP_ARCH_X86$/;" v class:Arch +X86_64 src/python/seccomp.pyx /^ X86_64 = libseccomp.SCMP_ARCH_X86_64$/;" v class:Arch +_ARCH_ARM_H src/arch-arm.h 23;" d +_ARCH_H src/arch.h 23;" d +_ARCH_X32_H src/arch-x32.h 23;" d +_ARCH_X86_H src/arch-x86.h 23;" d +_ARCH_x86_64_H src/arch-x86_64.h 23;" d +_BLK_MSZE src/gen_bpf.c 117;" d file: +_BPF_H tools/bpf.h 23;" d +_BPF_HASH_BITS src/gen_bpf.c 126;" d file: +_BPF_HASH_MASK src/gen_bpf.c 128;" d file: +_BPF_HASH_SIZE src/gen_bpf.c 127;" d file: +_BPF_INSTR src/gen_bpf.c 156;" d file: +_BPF_JMP_BLK src/gen_bpf.c 76;" d file: +_BPF_JMP_DB src/gen_bpf.c 74;" d file: +_BPF_JMP_HSH src/gen_bpf.c 78;" d file: +_BPF_JMP_IMM src/gen_bpf.c 72;" d file: +_BPF_JMP_MAX src/gen_bpf.c 82;" d file: +_BPF_JMP_MAX_RET src/gen_bpf.c 83;" d file: +_BPF_JMP_NO src/gen_bpf.c 68;" d file: +_BPF_JMP_NXT src/gen_bpf.c 70;" d file: +_BPF_K src/gen_bpf.c 80;" d file: +_BPF_OFFSET_SYSCALL src/gen_bpf.c 91;" d file: +_BPF_SYSCALL src/gen_bpf.c 92;" d file: +_CONFIGURE_H configure.h 5;" d +_DB_PRI_MASK_CHAIN src/db.c 41;" d file: +_DB_PRI_MASK_USER src/db.c 42;" d file: +_DB_PRI_USER src/db.c 43;" d file: +_DB_STA_FREED src/db.c 36;" d file: +_DB_STA_VALID src/db.c 35;" d file: +_FILTER_DB_H src/db.h 23;" d +_HASH_H src/hash.h 19;" d +_OP_FMT tools/scmp_bpf_disasm.c 35;" d file: +_SYSTEM_H src/system.h 23;" d +_TRANSLATOR_BPF_H src/gen_bpf.h 23;" d +_TRANSLATOR_STR_H src/gen_pfc.h 23;" d +_UTIL_TEST_H tests/util.h 23;" d +_VERSION_H version.h 3;" d +__NR_OABI_SYSCALL_BASE src/arch-arm-syscalls.c 29;" d file: +__NR_SYSCALL_BASE src/arch-arm-syscalls.c 34;" d file: +__NR_SYSCALL_BASE src/arch-arm-syscalls.c 36;" d file: +__author__ src/python/seccomp.pyx /^__author__ = 'Paul Moore '$/;" v +__blk_free src/gen_bpf.c /^static void __blk_free(struct bpf_state *state, struct bpf_blk *blk)$/;" f file: +__cinit__ src/python/seccomp.pyx /^ def __cinit__(self, arg, op, datum_a, datum_b = 0):$/;" m class:Arg file: +__cinit__ src/python/seccomp.pyx /^ def __cinit__(self, int defaction):$/;" m class:SyscallFilter file: +__date__ src/python/seccomp.pyx /^__date__ = "7 January 2013"$/;" v +__db_tree_free src/db.c /^static unsigned int __db_tree_free(struct db_arg_chain_tree *tree)$/;" f file: +__dealloc__ src/python/seccomp.pyx /^ def __dealloc__(self):$/;" m class:SyscallFilter file: +__x86_NR_ipc src/arch-x86.c 31;" d file: +__x86_NR_socketcall src/arch-x86.c 30;" d file: +_blk_append src/gen_bpf.c /^static struct bpf_blk *_blk_append(struct bpf_state *state,$/;" f file: +_blk_free src/gen_bpf.c /^static void _blk_free(struct bpf_state *state, struct bpf_blk *blk)$/;" f file: +_bpf_append_blk src/gen_bpf.c /^static int _bpf_append_blk(struct bpf_program *prg, const struct bpf_blk *blk)$/;" f file: +_ctx_valid src/api.c /^static int _ctx_valid(const scmp_filter_ctx *ctx)$/;" f file: +_db_node_mask_fixup src/db.c /^static void _db_node_mask_fixup(struct db_arg_chain_tree *node)$/;" f file: +_db_rule_gen_32 src/db.c /^static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch,$/;" f file: +_db_rule_gen_64 src/db.c /^static struct db_sys_list *_db_rule_gen_64(const struct arch_def *arch,$/;" f file: +_db_tree_act_check src/db.c /^static int _db_tree_act_check(struct db_arg_chain_tree *tree, uint32_t action)$/;" f file: +_db_tree_free src/db.c /^static unsigned int _db_tree_free(struct db_arg_chain_tree *tree)$/;" f file: +_db_tree_remove src/db.c /^static unsigned int _db_tree_remove(struct db_arg_chain_tree **tree,$/;" f file: +_db_tree_sub_prune src/db.c /^static int _db_tree_sub_prune(struct db_arg_chain_tree **tree_head,$/;" f file: +_gen_bpf_action src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_action(struct bpf_state *state,$/;" f file: +_gen_bpf_action_hsh src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_action_hsh(struct bpf_state *state,$/;" f file: +_gen_bpf_arch src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,$/;" f file: +_gen_bpf_build_bpf src/gen_bpf.c /^static int _gen_bpf_build_bpf(struct bpf_state *state,$/;" f file: +_gen_bpf_build_jmp src/gen_bpf.c /^static int _gen_bpf_build_jmp(struct bpf_state *state,$/;" f file: +_gen_bpf_build_jmp_ret src/gen_bpf.c /^static int _gen_bpf_build_jmp_ret(struct bpf_state *state,$/;" f file: +_gen_bpf_chain src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_chain(struct bpf_state *state,$/;" f file: +_gen_bpf_chain_lvl_res src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_chain_lvl_res(struct bpf_state *state,$/;" f file: +_gen_bpf_find_nxt src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_find_nxt(const struct bpf_blk *blk,$/;" f file: +_gen_bpf_node src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_node(struct bpf_state *state,$/;" f file: +_gen_bpf_syscall src/gen_bpf.c /^static struct bpf_blk *_gen_bpf_syscall(struct bpf_state *state,$/;" f file: +_gen_pfc_arch src/gen_pfc.c /^static int _gen_pfc_arch(const struct db_filter_col *col,$/;" f file: +_gen_pfc_chain src/gen_pfc.c /^static void _gen_pfc_chain(const struct arch_def *arch,$/;" f file: +_gen_pfc_syscall src/gen_pfc.c /^static void _gen_pfc_syscall(const struct arch_def *arch,$/;" f file: +_hsh_add src/gen_bpf.c /^static int _hsh_add(struct bpf_state *state, struct bpf_blk **blk_p,$/;" f file: +_hsh_find src/gen_bpf.c /^static struct bpf_blk *_hsh_find(const struct bpf_state *state, uint64_t h_val)$/;" f file: +_hsh_find_bkt src/gen_bpf.c /^static struct bpf_hash_bkt *_hsh_find_bkt(const struct bpf_state *state,$/;" f file: +_hsh_find_once src/gen_bpf.c /^static struct bpf_blk *_hsh_find_once(const struct bpf_state *state,$/;" f file: +_hsh_remove src/gen_bpf.c /^static struct bpf_blk *_hsh_remove(struct bpf_state *state, uint64_t h_val)$/;" f file: +_indent src/gen_pfc.c /^static void _indent(FILE *fds, unsigned int lvl)$/;" f file: +_pfc_action src/gen_pfc.c /^static void _pfc_action(FILE *fds, uint32_t action)$/;" f file: +_pfc_arch src/gen_pfc.c /^static const char *_pfc_arch(const struct arch_def *arch)$/;" f file: +_pfc_arg src/gen_pfc.c /^static void _pfc_arg(FILE *fds,$/;" f file: +_program_free src/gen_bpf.c /^static void _program_free(struct bpf_program *prg)$/;" f file: +_seccomp_rule_add src/api.c /^static int _seccomp_rule_add(struct db_filter_col *col,$/;" f file: +_state_release src/gen_bpf.c /^static void _state_release(struct bpf_state *state)$/;" f file: +_syscall_valid src/api.c /^static int _syscall_valid(int syscall)$/;" f file: +_trap_handler tests/util.c /^static void _trap_handler(int signal, siginfo_t *info, void *ctx)$/;" f file: +acc tools/scmp_bpf_sim.c /^ uint32_t acc;$/;" m struct:sim_state file: +acc_state src/gen_bpf.c /^ struct acc_state acc_state;$/;" m struct:bpf_blk typeref:struct:bpf_blk::acc_state file: +acc_state src/gen_bpf.c /^struct acc_state {$/;" s file: +act_badarch src/db.h /^ uint32_t act_badarch;$/;" m struct:db_filter_attr +act_default src/db.h /^ uint32_t act_default;$/;" m struct:db_filter_attr +act_f src/db.h /^ uint32_t act_f;$/;" m struct:db_arg_chain_tree +act_f_flg src/db.h /^ bool act_f_flg;$/;" m struct:db_arg_chain_tree +act_t src/db.h /^ uint32_t act_t;$/;" m struct:db_arg_chain_tree +act_t_flg src/db.h /^ bool act_t_flg;$/;" m struct:db_arg_chain_tree +action src/db.h /^ uint32_t action;$/;" m struct:db_sys_list +add_arch src/python/seccomp.pyx /^ def add_arch(self, arch):$/;" m class:SyscallFilter +add_rule src/python/seccomp.pyx /^ def add_rule(self, int action, syscall, *args):$/;" m class:SyscallFilter +add_rule_exactly src/python/seccomp.pyx /^ def add_rule_exactly(self, int action, syscall, *args):$/;" m class:SyscallFilter +arch src/db.h /^ const struct arch_def *arch;$/;" m struct:db_filter typeref:struct:db_filter::arch_def +arch src/gen_bpf.c /^ const struct arch_def *arch;$/;" m struct:bpf_state typeref:struct:bpf_state::arch_def file: +arch src/system.h /^ __u32 arch;$/;" m struct:seccomp_data +arch tools/bpf.h /^ uint32_t arch;$/;" m struct:seccomp_data +arch_arg_count_max src/arch.c /^int arch_arg_count_max(const struct arch_def *arch)$/;" f +arch_arg_offset src/arch.h 91;" d +arch_arg_offset_hi src/arch.c /^int arch_arg_offset_hi(const struct arch_def *arch, unsigned int arg)$/;" f +arch_arg_offset_lo src/arch.c /^int arch_arg_offset_lo(const struct arch_def *arch, unsigned int arg)$/;" f +arch_def src/arch.h /^struct arch_def {$/;" s +arch_def_arm src/arch-arm.c /^const struct arch_def arch_def_arm = {$/;" v typeref:struct:arch_def +arch_def_lookup src/arch.c /^const struct arch_def *arch_def_lookup(uint32_t token)$/;" f +arch_def_native src/arch.c /^const struct arch_def *arch_def_native = &arch_def_arm;$/;" v typeref:struct:arch_def +arch_def_native src/arch.c /^const struct arch_def *arch_def_native = &arch_def_x32;$/;" v typeref:struct:arch_def +arch_def_native src/arch.c /^const struct arch_def *arch_def_native = &arch_def_x86;$/;" v typeref:struct:arch_def +arch_def_native src/arch.c /^const struct arch_def *arch_def_native = &arch_def_x86_64;$/;" v typeref:struct:arch_def +arch_def_x32 src/arch-x32.c /^const struct arch_def arch_def_x32 = {$/;" v typeref:struct:arch_def +arch_def_x86 src/arch-x86.c /^const struct arch_def arch_def_x86 = {$/;" v typeref:struct:arch_def +arch_def_x86_64 src/arch-x86_64.c /^const struct arch_def arch_def_x86_64 = {$/;" v typeref:struct:arch_def +arch_filter_rewrite src/arch.c /^int arch_filter_rewrite(const struct arch_def *arch,$/;" f +arch_syscall_def src/arch.h /^struct arch_syscall_def {$/;" s +arch_syscall_resolve_name src/arch.c /^int arch_syscall_resolve_name(const struct arch_def *arch, const char *name)$/;" f +arch_syscall_resolve_num src/arch.c /^const char *arch_syscall_resolve_num(const struct arch_def *arch, int num)$/;" f +arch_syscall_rewrite src/arch.c /^int arch_syscall_rewrite(const struct arch_def *arch, bool strict, int *syscall)$/;" f +arch_syscall_translate src/arch.c /^int arch_syscall_translate(const struct arch_def *arch, int *syscall)$/;" f +arch_valid src/arch.c /^int arch_valid(uint32_t arch)$/;" f +arg src/db.h /^ unsigned int arg;$/;" m struct:db_api_arg +arg src/db.h /^ unsigned int arg;$/;" m struct:db_arg_chain_tree +arg_offset src/db.h /^ unsigned int arg_offset;$/;" m struct:db_arg_chain_tree +argparse tests/01-sim-allow.py /^import argparse$/;" i +argparse tests/02-sim-basic.py /^import argparse$/;" i +argparse tests/03-sim-basic_chains.py /^import argparse$/;" i +argparse tests/04-sim-multilevel_chains.py /^import argparse$/;" i +argparse tests/05-sim-long_jumps.py /^import argparse$/;" i +argparse tests/06-sim-actions.py /^import argparse$/;" i +argparse tests/07-sim-db_bug_looping.py /^import argparse$/;" i +argparse tests/08-sim-subtree_checks.py /^import argparse$/;" i +argparse tests/09-sim-syscall_priority_pre.py /^import argparse$/;" i +argparse tests/10-sim-syscall_priority_post.py /^import argparse$/;" i +argparse tests/11-basic-basic_errors.py /^import argparse$/;" i +argparse tests/12-sim-basic_masked_ops.py /^import argparse$/;" i +argparse tests/13-basic-attrs.py /^import argparse$/;" i +argparse tests/14-sim-reset.py /^import argparse$/;" i +argparse tests/15-basic-resolver.py /^import argparse$/;" i +argparse tests/16-sim-arch_basic.py /^import argparse$/;" i +argparse tests/17-sim-arch_merge.py /^import argparse$/;" i +argparse tests/18-sim-basic_whitelist.py /^import argparse$/;" i +argparse tests/19-sim-missing_syscalls.py /^import argparse$/;" i +argparse tests/20-live-basic_die.py /^import argparse$/;" i +argparse tests/21-live-basic_allow.py /^import argparse$/;" i +argparse tests/22-sim-basic_chains_array.py /^import argparse$/;" i +argparse tests/23-sim-arch_all_basic.py /^import argparse$/;" i +argparse tests/24-live-arg_allow.py /^import argparse$/;" i +argparse tests/25-sim-multilevel_chains_adv.py /^import argparse$/;" i +argparse tests/util.py /^import argparse$/;" i +args src/system.h /^ __u64 args[6];$/;" m struct:seccomp_data +args tests/01-sim-allow.py /^args = util.get_opt()$/;" v +args tests/02-sim-basic.py /^args = util.get_opt()$/;" v +args tests/03-sim-basic_chains.py /^args = util.get_opt()$/;" v +args tests/04-sim-multilevel_chains.py /^args = util.get_opt()$/;" v +args tests/05-sim-long_jumps.py /^args = util.get_opt()$/;" v +args tests/06-sim-actions.py /^args = util.get_opt()$/;" v +args tests/07-sim-db_bug_looping.py /^args = util.get_opt()$/;" v +args tests/08-sim-subtree_checks.py /^args = util.get_opt()$/;" v +args tests/09-sim-syscall_priority_pre.py /^args = util.get_opt()$/;" v +args tests/10-sim-syscall_priority_post.py /^args = util.get_opt()$/;" v +args tests/12-sim-basic_masked_ops.py /^args = util.get_opt()$/;" v +args tests/14-sim-reset.py /^args = util.get_opt()$/;" v +args tests/16-sim-arch_basic.py /^args = util.get_opt()$/;" v +args tests/17-sim-arch_merge.py /^args = util.get_opt()$/;" v +args tests/18-sim-basic_whitelist.py /^args = util.get_opt()$/;" v +args tests/19-sim-missing_syscalls.py /^args = util.get_opt()$/;" v +args tests/22-sim-basic_chains_array.py /^args = util.get_opt()$/;" v +args tests/23-sim-arch_all_basic.py /^args = util.get_opt()$/;" v +args tests/25-sim-multilevel_chains_adv.py /^args = util.get_opt()$/;" v +args tools/bpf.h /^ uint64_t args[BPF_SYS_ARG_MAX];$/;" m struct:seccomp_data +arm_arg_count_max src/arch-arm.h 30;" d +arm_syscall_resolve_name src/arch-arm-syscalls.c /^int arm_syscall_resolve_name(const char *name)$/;" f +arm_syscall_resolve_num src/arch-arm-syscalls.c /^const char *arm_syscall_resolve_num(int num)$/;" f +arm_syscall_table src/arch-arm-syscalls.c /^const struct arch_syscall_def arm_syscall_table[] = \\$/;" v typeref:struct:arch_syscall_def +attr src/db.h /^ struct db_filter_attr attr;$/;" m struct:db_filter_col typeref:struct:db_filter_col::db_filter_attr +attr src/gen_bpf.c /^ const struct db_filter_attr *attr;$/;" m struct:bpf_state typeref:struct:bpf_state::db_filter_attr file: +blk src/gen_bpf.c /^ struct bpf_blk *blk;$/;" m union:bpf_jump::__anon1 typeref:struct:bpf_jump::__anon1::bpf_blk file: +blk src/gen_bpf.c /^ struct bpf_blk *blk;$/;" m struct:bpf_hash_bkt typeref:struct:bpf_hash_bkt::bpf_blk file: +blk_alloc src/gen_bpf.c /^ unsigned int blk_alloc;$/;" m struct:bpf_blk file: +blk_cnt src/gen_bpf.c /^ unsigned int blk_cnt;$/;" m struct:bpf_blk file: +blk_cnt src/gen_bpf.h /^ uint16_t blk_cnt;$/;" m struct:bpf_program +blks src/gen_bpf.c /^ struct bpf_instr *blks;$/;" m struct:bpf_blk typeref:struct:bpf_blk::bpf_instr file: +blks src/gen_bpf.h /^ bpf_instr_raw *blks;$/;" m struct:bpf_program +bpf src/gen_bpf.c /^ struct bpf_program *bpf;$/;" m struct:bpf_state typeref:struct:bpf_state::bpf_program file: +bpf_blk src/gen_bpf.c /^struct bpf_blk {$/;" s file: +bpf_decode tools/scmp_bpf_disasm.c /^static int bpf_decode(FILE *file)$/;" f file: +bpf_decode_args tools/scmp_bpf_disasm.c /^static void bpf_decode_args(const bpf_instr_raw *bpf, unsigned int line)$/;" f file: +bpf_decode_op tools/scmp_bpf_disasm.c /^static void bpf_decode_op(const bpf_instr_raw *bpf)$/;" f file: +bpf_execute tools/scmp_bpf_sim.c /^static void bpf_execute(const struct bpf_program *prg,$/;" f file: +bpf_flg tests/util.h /^ int bpf_flg;$/;" m struct:util_options +bpf_hash_bkt src/gen_bpf.c /^struct bpf_hash_bkt {$/;" s file: +bpf_instr src/gen_bpf.c /^struct bpf_instr {$/;" s file: +bpf_instr_raw src/system.h /^typedef struct sock_filter bpf_instr_raw;$/;" t typeref:struct:sock_filter +bpf_instr_raw tools/bpf.h /^typedef struct sock_filter bpf_instr_raw;$/;" t typeref:struct:sock_filter +bpf_jump src/gen_bpf.c /^struct bpf_jump {$/;" s file: +bpf_jump_type src/gen_bpf.c /^enum bpf_jump_type {$/;" g file: +bpf_program src/gen_bpf.h /^struct bpf_program {$/;" s +bpf_program tools/scmp_bpf_sim.c /^struct bpf_program {$/;" s file: +bpf_state src/gen_bpf.c /^struct bpf_state {$/;" s file: +build_ext src/python/setup.py /^from Cython.Distutils import build_ext$/;" i +chains src/db.h /^ struct db_arg_chain_tree *chains;$/;" m struct:db_sys_list typeref:struct:db_sys_list::db_arg_chain_tree +cmdclass src/python/setup.py /^ cmdclass = {'build_ext': build_ext},$/;" v +cnf_entry configure /^function cnf_entry() {$/;" f +cnf_footer configure /^function cnf_footer() {$/;" f +cnf_h_entry configure /^function cnf_h_entry() {$/;" f +cnf_h_footer configure /^function cnf_h_footer() {$/;" f +cnf_h_header configure /^function cnf_h_header() {$/;" f +cnf_header configure /^function cnf_header() {$/;" f +cnf_mk_entry configure /^function cnf_mk_entry() {$/;" f +cnf_mk_footer configure /^function cnf_mk_footer() {$/;" f +cnf_mk_header configure /^function cnf_mk_header() {$/;" f +cnf_reset configure /^function cnf_reset() {$/;" f +code tools/bpf.h /^ uint16_t code;$/;" m struct:sock_filter +ctx tests/01-sim-allow.py /^ctx = test(args)$/;" v +ctx tests/02-sim-basic.py /^ctx = test(args)$/;" v +ctx tests/03-sim-basic_chains.py /^ctx = test(args)$/;" v +ctx tests/04-sim-multilevel_chains.py /^ctx = test(args)$/;" v +ctx tests/05-sim-long_jumps.py /^ctx = test(args)$/;" v +ctx tests/06-sim-actions.py /^ctx = test(args)$/;" v +ctx tests/07-sim-db_bug_looping.py /^ctx = test(args)$/;" v +ctx tests/08-sim-subtree_checks.py /^ctx = test(args)$/;" v +ctx tests/09-sim-syscall_priority_pre.py /^ctx = test(args)$/;" v +ctx tests/10-sim-syscall_priority_post.py /^ctx = test(args)$/;" v +ctx tests/12-sim-basic_masked_ops.py /^ctx = test(args)$/;" v +ctx tests/14-sim-reset.py /^ctx = test(args)$/;" v +ctx tests/16-sim-arch_basic.py /^ctx = test(args)$/;" v +ctx tests/17-sim-arch_merge.py /^ctx = test(args)$/;" v +ctx tests/18-sim-basic_whitelist.py /^ctx = test(args)$/;" v +ctx tests/19-sim-missing_syscalls.py /^ctx = test(args)$/;" v +ctx tests/22-sim-basic_chains_array.py /^ctx = test(args)$/;" v +ctx tests/23-sim-arch_all_basic.py /^ctx = test(args)$/;" v +ctx tests/25-sim-multilevel_chains_adv.py /^ctx = test(args)$/;" v +datum src/db.h /^ scmp_datum_t datum;$/;" m struct:db_api_arg +datum src/db.h /^ uint32_t datum;$/;" m struct:db_arg_chain_tree +db src/gen_bpf.c /^ struct db_arg_chain_tree *db;$/;" m union:bpf_jump::__anon1 typeref:struct:bpf_jump::__anon1::db_arg_chain_tree file: +db_action_valid src/db.c /^int db_action_valid(uint32_t action)$/;" f +db_api_arg src/db.h /^struct db_api_arg {$/;" s +db_arg_chain_tree src/db.h /^struct db_arg_chain_tree {$/;" s +db_chain_eq src/db.h 75;" d +db_chain_eq_result src/db.h 85;" d +db_chain_gt src/db.h 79;" d +db_chain_leaf src/db.h 83;" d +db_chain_lt src/db.h 71;" d +db_col_arch_exist src/db.c /^int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token)$/;" f +db_col_attr_get src/db.c /^int db_col_attr_get(const struct db_filter_col *col,$/;" f +db_col_attr_set src/db.c /^int db_col_attr_set(struct db_filter_col *col,$/;" f +db_col_db_add src/db.c /^int db_col_db_add(struct db_filter_col *col, struct db_filter *db)$/;" f +db_col_db_remove src/db.c /^int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token)$/;" f +db_col_init src/db.c /^struct db_filter_col *db_col_init(uint32_t def_action)$/;" f +db_col_merge src/db.c /^int db_col_merge(struct db_filter_col *col_dst, struct db_filter_col *col_src)$/;" f +db_col_release src/db.c /^void db_col_release(struct db_filter_col *col)$/;" f +db_col_reset src/db.c /^void db_col_reset(struct db_filter_col *col, uint32_t def_action)$/;" f +db_col_valid src/db.c /^int db_col_valid(struct db_filter_col *col)$/;" f +db_filter src/db.h /^struct db_filter {$/;" s +db_filter_attr src/db.h /^struct db_filter_attr {$/;" s +db_filter_col src/db.h /^struct db_filter_col {$/;" s +db_init src/db.c /^struct db_filter *db_init(const struct arch_def *arch)$/;" f +db_list_foreach src/db.h 156;" d +db_release src/db.c /^void db_release(struct db_filter *db)$/;" f +db_reset src/db.c /^void db_reset(struct db_filter *db)$/;" f +db_rule_add src/db.c /^int db_rule_add(struct db_filter *db, uint32_t action, unsigned int syscall,$/;" f +db_sys_list src/db.h /^struct db_sys_list {$/;" s +db_syscall_priority src/db.c /^int db_syscall_priority(struct db_filter *db,$/;" f +def_hsh src/gen_bpf.c /^ uint64_t def_hsh;$/;" m struct:bpf_state file: +description src/python/setup.py /^ description = "Python binding for libseccomp",$/;" v +end_action tools/scmp_bpf_sim.c /^static void end_action(uint32_t action, unsigned int line)$/;" f file: +endian src/arch.h /^ } endian;$/;" m struct:arch_def typeref:enum:arch_def::__anon3 +errno src/python/seccomp.pyx /^import errno$/;" i +errno tests/06-sim-actions.py /^import errno$/;" i +exist_arch src/python/seccomp.pyx /^ def exist_arch(self, arch):$/;" m class:SyscallFilter +exit_error tools/scmp_bpf_sim.c /^static void exit_error(unsigned int rc, unsigned int line)$/;" f file: +exit_fault tools/scmp_bpf_sim.c /^static void exit_fault(unsigned int rc)$/;" f file: +exit_usage tools/scmp_arch_detect.c /^static void exit_usage(const char *program)$/;" f file: +exit_usage tools/scmp_bpf_sim.c /^static void exit_usage(const char *program)$/;" f file: +exit_usage tools/scmp_sys_resolver.c /^static void exit_usage(const char *program)$/;" f file: +export_bpf src/python/seccomp.pyx /^ def export_bpf(self, file):$/;" m class:SyscallFilter +export_pfc src/python/seccomp.pyx /^ def export_pfc(self, file):$/;" m class:SyscallFilter +ext_modules src/python/setup.py /^ ext_modules = [$/;" v +extra_objects src/python/setup.py /^ extra_objects=["..\/libseccomp.a"])$/;" v +filter_cnt src/db.h /^ unsigned int filter_cnt;$/;" m struct:db_filter_col +filter_output tests/util.py /^def filter_output(args, ctx):$/;" f +filters src/db.h /^ struct db_filter **filters;$/;" m struct:db_filter_col typeref:struct:db_filter_col::db_filter +final src/hash.c 149;" d file: +flag_dup src/gen_bpf.c /^ bool flag_dup; \/* duplicate block and in use *\/$/;" m struct:bpf_blk file: +flag_hash src/gen_bpf.c /^ bool flag_hash; \/* added to the hash table *\/$/;" m struct:bpf_blk file: +flag_unique src/gen_bpf.c /^ bool flag_unique; \/* ->blks is unique to this block *\/$/;" m struct:bpf_blk file: +found src/gen_bpf.c /^ unsigned int found;$/;" m struct:bpf_hash_bkt file: +gen_bpf_generate src/gen_bpf.c /^struct bpf_program *gen_bpf_generate(const struct db_filter_col *col)$/;" f +gen_bpf_release src/gen_bpf.c /^void gen_bpf_release(struct bpf_program *program)$/;" f +gen_pfc_generate src/gen_pfc.c /^int gen_pfc_generate(const struct db_filter_col *col, int fd)$/;" f +generate_random_data tests/regression /^function generate_random_data() {$/;" f +generate_test_num tests/regression /^function generate_test_num() {$/;" f +get_attr src/python/seccomp.pyx /^ def get_attr(self, attr):$/;" m class:SyscallFilter +get_opt tests/util.py /^def get_opt():$/;" f +get_range tests/regression /^function get_range() {$/;" f +hash src/gen_bpf.c /^ uint64_t hash;$/;" m union:bpf_jump::__anon1 file: +hash src/gen_bpf.c /^ uint64_t hash;$/;" m struct:bpf_blk file: +hash_nxt src/gen_bpf.c /^ struct bpf_blk *hash_nxt;$/;" m struct:bpf_blk typeref:struct:bpf_blk::bpf_blk file: +hashbig src/hash.c /^uint32_t hashbig( const void *key, size_t length, uint32_t initval)$/;" f +hashlittle src/hash.c /^uint32_t hashlittle( const void *key, size_t length, uint32_t initval)$/;" f +hashlittle src/hash.c 44;" d file: +hashlittle2 src/hash.c /^void hashlittle2($/;" f +hashmask src/hash.c 67;" d file: +hashsize src/hash.c 66;" d file: +hashword src/hash.c /^uint32_t hashword($/;" f +hashword2 src/hash.c /^void hashword2 ($/;" f +htbl src/gen_bpf.c /^ struct bpf_hash_bkt *htbl[_BPF_HASH_SIZE];$/;" m struct:bpf_state typeref:struct:bpf_state::bpf_hash_bkt file: +i tools/scmp_bpf_sim.c /^ bpf_instr_raw *i;$/;" m struct:bpf_program file: +i_cnt tools/scmp_bpf_sim.c /^ size_t i_cnt;$/;" m struct:bpf_program file: +imm_j src/gen_bpf.c /^ uint8_t imm_j;$/;" m union:bpf_jump::__anon1 file: +imm_k src/gen_bpf.c /^ uint32_t imm_k;$/;" m union:bpf_jump::__anon1 file: +install_trap tests/util.py /^def install_trap():$/;" f +instruction_pointer src/system.h /^ __u64 instruction_pointer;$/;" m struct:seccomp_data +instruction_pointer tools/bpf.h /^ uint64_t instruction_pointer;$/;" m struct:seccomp_data +jf src/gen_bpf.c /^ struct bpf_jump jf;$/;" m struct:bpf_instr typeref:struct:bpf_instr::bpf_jump file: +jf tools/bpf.h /^ uint8_t jf;$/;" m struct:sock_filter +jt src/gen_bpf.c /^ struct bpf_jump jt;$/;" m struct:bpf_instr typeref:struct:bpf_instr::bpf_jump file: +jt tools/bpf.h /^ uint8_t jt;$/;" m struct:sock_filter +k src/gen_bpf.c /^ struct bpf_jump k;$/;" m struct:bpf_instr typeref:struct:bpf_instr::bpf_jump file: +k tools/bpf.h /^ uint32_t k;$/;" m struct:sock_filter +libseccomp src/python/seccomp.pyx /^cimport libseccomp$/;" i +license src/python/setup.py /^ license = "LGPLv2.1",$/;" v +load src/python/seccomp.pyx /^ def load(self):$/;" m class:SyscallFilter +long_description src/python/setup.py /^ long_description = "Python API for the Linux Kernel's syscall filtering capability, seccomp.",$/;" v +lvl_nxt src/db.h /^ struct db_arg_chain_tree *lvl_prv, *lvl_nxt;$/;" m struct:db_arg_chain_tree typeref:struct:db_arg_chain_tree:: +lvl_nxt src/gen_bpf.c /^ struct bpf_blk *lvl_prv, *lvl_nxt;$/;" m struct:bpf_blk typeref:struct:bpf_blk:: file: +lvl_prv src/db.h /^ struct db_arg_chain_tree *lvl_prv, *lvl_nxt;$/;" m struct:db_arg_chain_tree typeref:struct:db_arg_chain_tree::db_arg_chain_tree +lvl_prv src/gen_bpf.c /^ struct bpf_blk *lvl_prv, *lvl_nxt;$/;" m struct:bpf_blk typeref:struct:bpf_blk::bpf_blk file: +main tests/00-test.c /^int main(void)$/;" f +main tests/01-sim-allow.c /^int main(int argc, char *argv[])$/;" f +main tests/02-sim-basic.c /^int main(int argc, char *argv[])$/;" f +main tests/03-sim-basic_chains.c /^int main(int argc, char *argv[])$/;" f +main tests/04-sim-multilevel_chains.c /^int main(int argc, char *argv[])$/;" f +main tests/05-sim-long_jumps.c /^int main(int argc, char *argv[])$/;" f +main tests/06-sim-actions.c /^int main(int argc, char *argv[])$/;" f +main tests/07-sim-db_bug_looping.c /^int main(int argc, char *argv[])$/;" f +main tests/08-sim-subtree_checks.c /^int main(int argc, char *argv[])$/;" f +main tests/09-sim-syscall_priority_pre.c /^int main(int argc, char *argv[])$/;" f +main tests/10-sim-syscall_priority_post.c /^int main(int argc, char *argv[])$/;" f +main tests/11-basic-basic_errors.c /^int main(int argc, char *argv[])$/;" f +main tests/12-sim-basic_masked_ops.c /^int main(int argc, char *argv[])$/;" f +main tests/13-basic-attrs.c /^int main(int argc, char *argv[])$/;" f +main tests/14-sim-reset.c /^int main(int argc, char *argv[])$/;" f +main tests/15-basic-resolver.c /^int main(int argc, char *argv[])$/;" f +main tests/16-sim-arch_basic.c /^int main(int argc, char *argv[])$/;" f +main tests/17-sim-arch_merge.c /^int main(int argc, char *argv[])$/;" f +main tests/18-sim-basic_whitelist.c /^int main(int argc, char *argv[])$/;" f +main tests/19-sim-missing_syscalls.c /^int main(int argc, char *argv[])$/;" f +main tests/20-live-basic_die.c /^int main(int argc, char *argv[])$/;" f +main tests/21-live-basic_allow.c /^int main(int argc, char *argv[])$/;" f +main tests/22-sim-basic_chains_array.c /^int main(int argc, char *argv[])$/;" f +main tests/23-sim-arch_all_basic.c /^int main(int argc, char *argv[])$/;" f +main tests/24-live-arg_allow.c /^int main(int argc, char *argv[])$/;" f +main tests/25-sim-multilevel_chains_adv.c /^int main(int argc, char *argv[])$/;" f +main tools/scmp_arch_detect.c /^int main(int argc, char *argv[])$/;" f +main tools/scmp_bpf_disasm.c /^int main(int argc, char *argv[])$/;" f +main tools/scmp_bpf_sim.c /^int main(int argc, char *argv[])$/;" f +main tools/scmp_sys_resolver.c /^int main(int argc, char *argv[])$/;" f +maintainer src/python/setup.py /^ maintainer = "Paul Moore",$/;" v +maintainer_email src/python/setup.py /^ maintainer_email = "paul@paul-moore.com",$/;" v +mask src/db.h /^ scmp_datum_t mask;$/;" m struct:db_api_arg +mask src/db.h /^ uint32_t mask;$/;" m struct:db_arg_chain_tree +mask src/gen_bpf.c /^ uint32_t mask;$/;" m struct:acc_state file: +merge src/python/seccomp.pyx /^ def merge(self, SyscallFilter filter):$/;" m class:SyscallFilter +mix src/hash.c 114;" d file: +msg_error configure /^function msg_error() {$/;" f +msg_summary configure /^function msg_summary() {$/;" f +msg_usage configure /^function msg_usage() {$/;" f +name src/arch.h /^ const char *name;$/;" m struct:arch_syscall_def +name src/python/setup.py /^ name = "seccomp",$/;" v +next src/db.h /^ struct db_sys_list *next;$/;" m struct:db_sys_list typeref:struct:db_sys_list::db_sys_list +next src/gen_bpf.c /^ struct bpf_blk *prev, *next;$/;" m struct:bpf_blk typeref:struct:bpf_blk:: file: +next src/gen_bpf.c /^ struct bpf_hash_bkt *next;$/;" m struct:bpf_hash_bkt typeref:struct:bpf_hash_bkt::bpf_hash_bkt file: +next src/gen_pfc.c /^ struct pfc_sys_list *next;$/;" m struct:pfc_sys_list typeref:struct:pfc_sys_list::pfc_sys_list file: +nnp_enable src/db.h /^ uint32_t nnp_enable;$/;" m struct:db_filter_attr +node src/gen_bpf.c /^ const struct db_arg_chain_tree *node;$/;" m struct:bpf_blk typeref:struct:bpf_blk::db_arg_chain_tree file: +node_cnt src/db.h /^ unsigned int node_cnt;$/;" m struct:db_sys_list +nr src/system.h /^ int nr;$/;" m struct:seccomp_data +nr tools/bpf.h /^ int32_t nr;$/;" m struct:seccomp_data +num src/arch.h /^ unsigned int num;$/;" m struct:arch_syscall_def +num src/db.h /^ unsigned int num;$/;" m struct:db_sys_list +nxt src/gen_bpf.c /^ unsigned int nxt;$/;" m union:bpf_jump::__anon1 file: +nxt_f src/db.h /^ struct db_arg_chain_tree *nxt_f;$/;" m struct:db_arg_chain_tree typeref:struct:db_arg_chain_tree::db_arg_chain_tree +nxt_t src/db.h /^ struct db_arg_chain_tree *nxt_t;$/;" m struct:db_arg_chain_tree typeref:struct:db_arg_chain_tree::db_arg_chain_tree +offset src/gen_bpf.c /^ int32_t offset;$/;" m struct:acc_state file: +op src/db.h /^ enum scmp_compare op;$/;" m struct:db_arg_chain_tree typeref:enum:db_arg_chain_tree::scmp_compare +op src/db.h /^ unsigned int op;$/;" m struct:db_api_arg +op src/gen_bpf.c /^ uint16_t op;$/;" m struct:bpf_instr file: +opt_verbose tools/scmp_bpf_sim.c /^static unsigned int opt_verbose = 0;$/;" v file: +os src/python/setup.py /^import os$/;" i +os tests/24-live-arg_allow.py /^import os$/;" i +os tests/util.py /^import os$/;" i +parse_action tests/util.py /^def parse_action(action):$/;" f +pfc_sys_list src/gen_pfc.c /^struct pfc_sys_list {$/;" s file: +platforms src/python/setup.py /^ platforms = "Linux",$/;" v +prev src/gen_bpf.c /^ struct bpf_blk *prev, *next;$/;" m struct:bpf_blk typeref:struct:bpf_blk::bpf_blk file: +pri_nxt src/db.h /^ struct db_sys_list *pri_prv, *pri_nxt;$/;" m struct:db_sys_list typeref:struct:db_sys_list:: +pri_prv src/db.h /^ struct db_sys_list *pri_prv, *pri_nxt;$/;" m struct:db_sys_list typeref:struct:db_sys_list::db_sys_list +print_data tests/regression /^function print_data() {$/;" f +print_result tests/regression /^function print_result() {$/;" f +print_valgrind tests/regression /^function print_valgrind() {$/;" f +priority src/db.h /^ unsigned int priority;$/;" m struct:db_sys_list +priority src/gen_bpf.c /^ unsigned int priority;$/;" m struct:bpf_blk file: +refcnt src/db.h /^ unsigned int refcnt;$/;" m struct:db_arg_chain_tree +remove_arch src/python/seccomp.pyx /^ def remove_arch(self, arch):$/;" m class:SyscallFilter +reset src/python/seccomp.pyx /^ def reset(self, int defaction = -1):$/;" m class:SyscallFilter +resolve_syscall src/python/seccomp.pyx /^def resolve_syscall(arch, syscall):$/;" f +rot src/hash.c 68;" d file: +run_test tests/regression /^function run_test() {$/;" f +run_test_basic tests/regression /^function run_test_basic() {$/;" f +run_test_bpf_sim tests/regression /^function run_test_bpf_sim() {$/;" f +run_test_bpf_sim_fuzz tests/regression /^function run_test_bpf_sim_fuzz() {$/;" f +run_test_command tests/regression /^function run_test_command() {$/;" f +run_test_live tests/regression /^function run_test_live() {$/;" f +run_tests tests/regression /^function run_tests() {$/;" f +seccomp_arch_add src/api.c /^int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token)$/;" f +seccomp_arch_exist src/api.c /^int seccomp_arch_exist(const scmp_filter_ctx ctx, uint32_t arch_token)$/;" f +seccomp_arch_native src/api.c /^uint32_t seccomp_arch_native(void)$/;" f +seccomp_arch_remove src/api.c /^int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token)$/;" f +seccomp_attr_get src/api.c /^int seccomp_attr_get(const scmp_filter_ctx ctx,$/;" f +seccomp_attr_set src/api.c /^int seccomp_attr_set(scmp_filter_ctx ctx,$/;" f +seccomp_data src/system.h /^struct seccomp_data {$/;" s +seccomp_data tools/bpf.h /^struct seccomp_data {$/;" s +seccomp_export_bpf src/api.c /^int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd)$/;" f +seccomp_export_pfc src/api.c /^int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd)$/;" f +seccomp_init src/api.c /^scmp_filter_ctx seccomp_init(uint32_t def_action)$/;" f +seccomp_load src/api.c /^int seccomp_load(const scmp_filter_ctx ctx)$/;" f +seccomp_merge src/api.c /^int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src)$/;" f +seccomp_release src/api.c /^void seccomp_release(scmp_filter_ctx ctx)$/;" f +seccomp_reset src/api.c /^int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action)$/;" f +seccomp_rule_add src/api.c /^int seccomp_rule_add(scmp_filter_ctx ctx,$/;" f +seccomp_rule_add_array src/api.c /^int seccomp_rule_add_array(scmp_filter_ctx ctx,$/;" f +seccomp_rule_add_exact src/api.c /^int seccomp_rule_add_exact(scmp_filter_ctx ctx, uint32_t action,$/;" f +seccomp_rule_add_exact_array src/api.c /^int seccomp_rule_add_exact_array(scmp_filter_ctx ctx,$/;" f +seccomp_syscall_priority src/api.c /^int seccomp_syscall_priority(scmp_filter_ctx ctx, int syscall, uint8_t priority)$/;" f +seccomp_syscall_resolve_name src/api.c /^int seccomp_syscall_resolve_name(const char *name)$/;" f +seccomp_syscall_resolve_name_arch src/api.c /^int seccomp_syscall_resolve_name_arch(uint32_t arch_token, const char *name)$/;" f +seccomp_syscall_resolve_num_arch src/api.c /^char *seccomp_syscall_resolve_num_arch(uint32_t arch_token, int num)$/;" f +set_attr src/python/seccomp.pyx /^ def set_attr(self, attr, int value):$/;" m class:SyscallFilter +setup src/python/setup.py /^from distutils.core import setup$/;" i +signal tests/util.py /^import signal$/;" i +sim_state tools/scmp_bpf_sim.c /^struct sim_state {$/;" s file: +size src/arch.h /^ } size;$/;" m struct:arch_def typeref:enum:arch_def::__anon2 +sock_filter tools/bpf.h /^struct sock_filter {$/;" s +state src/db.h /^ int state;$/;" m struct:db_filter_col +sys src/gen_pfc.c /^ struct db_sys_list *sys;$/;" m struct:pfc_sys_list typeref:struct:pfc_sys_list::db_sys_list file: +sys tests/01-sim-allow.py /^import sys$/;" i +sys tests/02-sim-basic.py /^import sys$/;" i +sys tests/03-sim-basic_chains.py /^import sys$/;" i +sys tests/04-sim-multilevel_chains.py /^import sys$/;" i +sys tests/05-sim-long_jumps.py /^import sys$/;" i +sys tests/06-sim-actions.py /^import sys$/;" i +sys tests/07-sim-db_bug_looping.py /^import sys$/;" i +sys tests/08-sim-subtree_checks.py /^import sys$/;" i +sys tests/09-sim-syscall_priority_pre.py /^import sys$/;" i +sys tests/10-sim-syscall_priority_post.py /^import sys$/;" i +sys tests/11-basic-basic_errors.py /^import sys$/;" i +sys tests/12-sim-basic_masked_ops.py /^import sys$/;" i +sys tests/13-basic-attrs.py /^import sys$/;" i +sys tests/14-sim-reset.py /^import sys$/;" i +sys tests/15-basic-resolver.py /^import sys$/;" i +sys tests/16-sim-arch_basic.py /^import sys$/;" i +sys tests/17-sim-arch_merge.py /^import sys$/;" i +sys tests/18-sim-basic_whitelist.py /^import sys$/;" i +sys tests/19-sim-missing_syscalls.py /^import sys$/;" i +sys tests/20-live-basic_die.py /^import sys$/;" i +sys tests/21-live-basic_allow.py /^import sys$/;" i +sys tests/22-sim-basic_chains_array.py /^import sys$/;" i +sys tests/23-sim-arch_all_basic.py /^import sys$/;" i +sys tests/24-live-arg_allow.py /^import sys$/;" i +sys tests/25-sim-multilevel_chains_adv.py /^import sys$/;" i +sys tests/util.py /^import sys$/;" i +syscall_priority src/python/seccomp.pyx /^ def syscall_priority(self, syscall, int priority):$/;" m class:SyscallFilter +syscalls src/db.h /^ struct db_sys_list *syscalls;$/;" m struct:db_filter typeref:struct:db_filter::db_sys_list +system_arch src/python/seccomp.pyx /^def system_arch():$/;" f +temp tools/scmp_bpf_sim.c /^ uint32_t temp[BPF_SCRATCH_SIZE];$/;" m struct:sim_state file: +test tests/01-sim-allow.py /^def test(args):$/;" f +test tests/02-sim-basic.py /^def test(args):$/;" f +test tests/03-sim-basic_chains.py /^def test(args):$/;" f +test tests/04-sim-multilevel_chains.py /^def test(args):$/;" f +test tests/05-sim-long_jumps.py /^def test(args):$/;" f +test tests/06-sim-actions.py /^def test(args):$/;" f +test tests/07-sim-db_bug_looping.py /^def test(args):$/;" f +test tests/08-sim-subtree_checks.py /^def test(args):$/;" f +test tests/09-sim-syscall_priority_pre.py /^def test(args):$/;" f +test tests/10-sim-syscall_priority_post.py /^def test(args):$/;" f +test tests/11-basic-basic_errors.py /^def test():$/;" f +test tests/12-sim-basic_masked_ops.py /^def test(args):$/;" f +test tests/13-basic-attrs.py /^def test():$/;" f +test tests/14-sim-reset.py /^def test(args):$/;" f +test tests/15-basic-resolver.py /^def test():$/;" f +test tests/16-sim-arch_basic.py /^def test(args):$/;" f +test tests/17-sim-arch_merge.py /^def test(args):$/;" f +test tests/18-sim-basic_whitelist.py /^def test(args):$/;" f +test tests/19-sim-missing_syscalls.py /^def test(args):$/;" f +test tests/20-live-basic_die.py /^def test():$/;" f +test tests/21-live-basic_allow.py /^def test():$/;" f +test tests/22-sim-basic_chains_array.py /^def test(args):$/;" f +test tests/23-sim-arch_all_basic.py /^def test(args):$/;" f +test tests/24-live-arg_allow.py /^def test():$/;" f +test tests/25-sim-multilevel_chains_adv.py /^def test(args):$/;" f +test_deps configure /^function test_deps() {$/;" f +tgt src/gen_bpf.c /^ } tgt;$/;" m struct:bpf_jump typeref:union:bpf_jump::__anon1 file: +tmpl_filter configure /^function tmpl_filter() {$/;" f +to_c src/python/seccomp.pyx /^ def to_c(self):$/;" m class:Arg +token src/arch.h /^ uint32_t token;$/;" m struct:arch_def +token_bpf src/arch.h /^ uint32_t token_bpf;$/;" m struct:arch_def +trap_handler tests/util.py /^def trap_handler(signum, frame):$/;" f +type src/gen_bpf.c /^ enum bpf_jump_type type;$/;" m struct:bpf_jump typeref:enum:bpf_jump::bpf_jump_type file: +uint32_t src/python/libseccomp.pxd /^from libc.stdint cimport uint8_t, uint32_t, uint64_t$/;" i +uint32_t src/python/seccomp.pyx /^from libc.stdint cimport uint32_t$/;" i +uint64_t src/python/libseccomp.pxd /^from libc.stdint cimport uint8_t, uint32_t, uint64_t$/;" i +uint8_t src/python/libseccomp.pxd /^from libc.stdint cimport uint8_t, uint32_t, uint64_t$/;" i +url src/python/setup.py /^ url = "http:\/\/libseccomp.sf.net",$/;" v +usage tests/regression /^function usage() {$/;" f +util tests/01-sim-allow.py /^import util$/;" i +util tests/02-sim-basic.py /^import util$/;" i +util tests/03-sim-basic_chains.py /^import util$/;" i +util tests/04-sim-multilevel_chains.py /^import util$/;" i +util tests/05-sim-long_jumps.py /^import util$/;" i +util tests/06-sim-actions.py /^import util$/;" i +util tests/07-sim-db_bug_looping.py /^import util$/;" i +util tests/08-sim-subtree_checks.py /^import util$/;" i +util tests/09-sim-syscall_priority_pre.py /^import util$/;" i +util tests/10-sim-syscall_priority_post.py /^import util$/;" i +util tests/11-basic-basic_errors.py /^import util$/;" i +util tests/12-sim-basic_masked_ops.py /^import util$/;" i +util tests/13-basic-attrs.py /^import util$/;" i +util tests/14-sim-reset.py /^import util$/;" i +util tests/15-basic-resolver.py /^import util$/;" i +util tests/16-sim-arch_basic.py /^import util$/;" i +util tests/17-sim-arch_merge.py /^import util$/;" i +util tests/18-sim-basic_whitelist.py /^import util$/;" i +util tests/19-sim-missing_syscalls.py /^import util$/;" i +util tests/20-live-basic_die.py /^import util$/;" i +util tests/21-live-basic_allow.py /^import util$/;" i +util tests/22-sim-basic_chains_array.py /^import util$/;" i +util tests/23-sim-arch_all_basic.py /^import util$/;" i +util tests/24-live-arg_allow.py /^import util$/;" i +util tests/25-sim-multilevel_chains_adv.py /^import util$/;" i +util_action_parse tests/util.c /^int util_action_parse(const char *action)$/;" f +util_file_write tests/util.c /^int util_file_write(const char *path)$/;" f +util_filter_output tests/util.c /^int util_filter_output(const struct util_options *opts,$/;" f +util_getopt tests/util.c /^int util_getopt(int argc, char *argv[], struct util_options *opts)$/;" f +util_options tests/util.h /^struct util_options {$/;" s +util_trap_install tests/util.c /^int util_trap_install(void)$/;" f +valid src/db.h /^ bool valid;$/;" m struct:db_api_arg +valid src/db.h /^ bool valid;$/;" m struct:db_sys_list +verify_deps configure /^function verify_deps() {$/;" f +verify_deps tests/regression /^function verify_deps() {$/;" f +verify_deps tools/scmp_app_inspector /^function verify_deps() {$/;" f +version src/python/setup.py /^ version = os.environ["VERSION_RELEASE"],$/;" v +write_file tests/util.py /^def write_file(path):$/;" f +x32_arg_count_max src/arch-x32.h 32;" d +x32_syscall_resolve_name src/arch-x32-syscalls.c /^int x32_syscall_resolve_name(const char *name)$/;" f +x32_syscall_resolve_num src/arch-x32-syscalls.c /^const char *x32_syscall_resolve_num(int num)$/;" f +x86_64_arg_count_max src/arch-x86_64.h 30;" d +x86_64_arg_offset_hi src/arch-x86_64.h 35;" d +x86_64_arg_offset_lo src/arch-x86_64.h 34;" d +x86_64_syscall_resolve_name src/arch-x86_64-syscalls.c /^int x86_64_syscall_resolve_name(const char *name)$/;" f +x86_64_syscall_resolve_num src/arch-x86_64-syscalls.c /^const char *x86_64_syscall_resolve_num(int num)$/;" f +x86_64_syscall_table src/arch-x86_64-syscalls.c /^const struct arch_syscall_def x86_64_syscall_table[] = \\$/;" v typeref:struct:arch_syscall_def +x86_arg_count_max src/arch-x86.h 31;" d +x86_filter_rewrite src/arch-x86.c /^int x86_filter_rewrite(const struct arch_def *arch, bool strict,$/;" f +x86_syscall_resolve_name src/arch-x86-syscalls.c /^int x86_syscall_resolve_name(const char *name)$/;" f +x86_syscall_resolve_num src/arch-x86-syscalls.c /^const char *x86_syscall_resolve_num(int num)$/;" f +x86_syscall_rewrite src/arch-x86.c /^int x86_syscall_rewrite(const struct arch_def *arch, bool strict, int *syscall)$/;" f +x86_syscall_table src/arch-x86-syscalls.c /^static const struct arch_syscall_def x86_syscall_table[] = \\$/;" v typeref:struct:arch_syscall_def file: diff --git a/tests/00-test.c b/tests/00-test.c new file mode 100644 index 0000000..a0b84bb --- /dev/null +++ b/tests/00-test.c @@ -0,0 +1,60 @@ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include + +#include + +#include "util.h" + +int main(void) +{ + scmp_filter_ctx ctx; + int status; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + return 1; + + status = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 0); + if (status < 0) + return 1; + + status = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); + if (status < 0) + return 1; + +#if 1 + status = seccomp_load(ctx); + if (status < 0) + return 1; +#endif + + status = seccomp_reset(ctx, SCMP_ACT_ALLOW); + if (status < 0) + return 1; + +#if 0 + status = seccomp_load(ctx); + if (status < 0) + return 1; +#endif + + write(2, "OK\n", 3); + + return 0; +} \ No newline at end of file diff --git a/tests/01-sim-allow.c b/tests/01-sim-allow.c new file mode 100644 index 0000000..5f4f74d --- /dev/null +++ b/tests/01-sim-allow.c @@ -0,0 +1,49 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/01-sim-allow.py b/tests/01-sim-allow.py new file mode 100755 index 0000000..db3656b --- /dev/null +++ b/tests/01-sim-allow.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(ALLOW) + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/01-sim-allow.tests b/tests/01-sim-allow.tests new file mode 100644 index 0000000..9630276 --- /dev/null +++ b/tests/01-sim-allow.tests @@ -0,0 +1,21 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +01-sim-allow all 0-350 N N N N N N ALLOW + +test type: bpf-sim-fuzz + +# Testname StressCount +01-sim-allow 50 + +test type: bpf-valgrind + +# Testname +01-sim-allow diff --git a/tests/02-sim-basic.c b/tests/02-sim-basic.c new file mode 100644 index 0000000..b601554 --- /dev/null +++ b/tests/02-sim-basic.c @@ -0,0 +1,72 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +/* + * Just like mode 1 seccomp we allow 4 syscalls: + * read, write, exit, and rt_sigreturn + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/02-sim-basic.py b/tests/02-sim-basic.py new file mode 100755 index 0000000..868664f --- /dev/null +++ b/tests/02-sim-basic.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + f.add_rule_exactly(ALLOW, "read"); + f.add_rule_exactly(ALLOW, "write"); + f.add_rule_exactly(ALLOW, "close"); + f.add_rule_exactly(ALLOW, "rt_sigreturn"); + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/02-sim-basic.tests b/tests/02-sim-basic.tests new file mode 100644 index 0000000..07004a4 --- /dev/null +++ b/tests/02-sim-basic.tests @@ -0,0 +1,30 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +02-sim-basic all read 0 0x856B008 40 N N N ALLOW +02-sim-basic all write 1 0x856B008 40 N N N ALLOW +02-sim-basic all close 4 N N N N N ALLOW +02-sim-basic all rt_sigreturn N N N N N N ALLOW +02-sim-basic all open 0x856B008 4 N N N N KILL +02-sim-basic x86 0-2 N N N N N N KILL +02-sim-basic x86 7-172 N N N N N N KILL +02-sim-basic x86 174-350 N N N N N N KILL +02-sim-basic x86_64 4-14 N N N N N N KILL +02-sim-basic x86_64 16-350 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +02-sim-basic 50 + +test type: bpf-valgrind + +# Testname +02-sim-basic diff --git a/tests/03-sim-basic_chains.c b/tests/03-sim-basic_chains.c new file mode 100644 index 0000000..6e7309b --- /dev/null +++ b/tests/03-sim-basic_chains.c @@ -0,0 +1,73 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/03-sim-basic_chains.py b/tests/03-sim-basic_chains.py new file mode 100755 index 0000000..324170d --- /dev/null +++ b/tests/03-sim-basic_chains.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + f.add_rule_exactly(ALLOW, "read", Arg(0, EQ, sys.stdin.fileno())); + f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno())); + f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno())); + f.add_rule_exactly(ALLOW, "close"); + f.add_rule_exactly(ALLOW, "rt_sigreturn"); + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/03-sim-basic_chains.tests b/tests/03-sim-basic_chains.tests new file mode 100644 index 0000000..ef4353a --- /dev/null +++ b/tests/03-sim-basic_chains.tests @@ -0,0 +1,32 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +03-sim-basic_chains all read 0 0x856B008 10 N N N ALLOW +03-sim-basic_chains all read 1-10 0x856B008 10 N N N KILL +03-sim-basic_chains all write 1-2 0x856B008 10 N N N ALLOW +03-sim-basic_chains all write 3-10 0x856B008 10 N N N KILL +03-sim-basic_chains all close N N N N N N ALLOW +03-sim-basic_chains all rt_sigreturn N N N N N N ALLOW +03-sim-basic_chains all open 0x856B008 4 N N N N KILL +03-sim-basic_chains x86 0-2 N N N N N N KILL +03-sim-basic_chains x86 7-172 N N N N N N KILL +03-sim-basic_chains x86 174-350 N N N N N N KILL +03-sim-basic_chains x86_64 4-14 N N N N N N KILL +03-sim-basic_chains x86_64 16-350 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +03-sim-basic_chains 50 + +test type: bpf-valgrind + +# Testname +03-sim-basic_chains diff --git a/tests/04-sim-multilevel_chains.c b/tests/04-sim-multilevel_chains.c new file mode 100644 index 0000000..aeff58b --- /dev/null +++ b/tests/04-sim-multilevel_chains.c @@ -0,0 +1,87 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 3, + SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO), + SCMP_A1(SCMP_CMP_NE, 0x0), + SCMP_A2(SCMP_CMP_LT, SSIZE_MAX)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 3, + SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO), + SCMP_A1(SCMP_CMP_NE, 0x0), + SCMP_A2(SCMP_CMP_LT, SSIZE_MAX)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 3, + SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO), + SCMP_A1(SCMP_CMP_NE, 0x0), + SCMP_A2(SCMP_CMP_LT, SSIZE_MAX)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/04-sim-multilevel_chains.py b/tests/04-sim-multilevel_chains.py new file mode 100755 index 0000000..e40deee --- /dev/null +++ b/tests/04-sim-multilevel_chains.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + f.add_rule_exactly(ALLOW, "open"); + f.add_rule_exactly(ALLOW, "close"); + f.add_rule_exactly(ALLOW, "read", + Arg(0, EQ, sys.stdin.fileno()), + Arg(1, NE, 0), + Arg(2, LT, sys.maxsize)); + f.add_rule_exactly(ALLOW, "write", + Arg(0, EQ, sys.stdout.fileno()), + Arg(1, NE, 0), + Arg(2, LT, sys.maxsize)); + f.add_rule_exactly(ALLOW, "write", + Arg(0, EQ, sys.stderr.fileno()), + Arg(1, NE, 0), + Arg(2, LT, sys.maxsize)); + f.add_rule_exactly(ALLOW, "close"); + f.add_rule_exactly(ALLOW, "rt_sigreturn"); + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/04-sim-multilevel_chains.tests b/tests/04-sim-multilevel_chains.tests new file mode 100644 index 0000000..cefbc4f --- /dev/null +++ b/tests/04-sim-multilevel_chains.tests @@ -0,0 +1,42 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +04-sim-multilevel_chains all open 0x856B008 4 N N N N ALLOW +04-sim-multilevel_chains all close 4 N N N N N ALLOW +04-sim-multilevel_chains x86 read 0 0x856B008 0x7FFFFFFE N N N ALLOW +04-sim-multilevel_chains x86_64 read 0 0x856B008 0x7FFFFFFFFFFFFFFE N N N ALLOW +04-sim-multilevel_chains x86 read 0 0x856B008 0x7FFFFFFF N N N KILL +04-sim-multilevel_chains x86_64 read 0 0x856B008 0x7FFFFFFFFFFFFFFF N N N KILL +04-sim-multilevel_chains x86 read 0 0 0x7FFFFFFE N N N KILL +04-sim-multilevel_chains x86_64 read 0 0 0x7FFFFFFFFFFFFFFE N N N KILL +04-sim-multilevel_chains all read 1-10 0x856B008 0x7FFFFFFE N N N KILL +04-sim-multilevel_chains x86 write 1-2 0x856B008 0x7FFFFFFE N N N ALLOW +04-sim-multilevel_chains x86_64 write 1-2 0x856B008 0x7FFFFFFFFFFFFFFE N N N ALLOW +04-sim-multilevel_chains x86 write 1-2 0 0x7FFFFFFE N N N KILL +04-sim-multilevel_chains x86_64 write 1-2 0 0x7FFFFFFFFFFFFFFE N N N KILL +04-sim-multilevel_chains x86 write 1-2 0x856B008 0x7FFFFFFF N N N KILL +04-sim-multilevel_chains x86_64 write 1-2 0x856B008 0x7FFFFFFFFFFFFFFF N N N KILL +04-sim-multilevel_chains all write 3-10 0x856B008 0x7FFFFFFE N N N KILL +04-sim-multilevel_chains all rt_sigreturn N N N N N N ALLOW +04-sim-multilevel_chains x86 0-2 N N N N N N KILL +04-sim-multilevel_chains x86 7-172 N N N N N N KILL +04-sim-multilevel_chains x86 174-350 N N N N N N KILL +04-sim-multilevel_chains x86_64 4-14 N N N N N N KILL +04-sim-multilevel_chains x86_64 16-350 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +04-sim-multilevel_chains 50 + +test type: bpf-valgrind + +# Testname +04-sim-multilevel_chains diff --git a/tests/05-sim-long_jumps.c b/tests/05-sim-long_jumps.c new file mode 100644 index 0000000..9f24ecd --- /dev/null +++ b/tests/05-sim-long_jumps.c @@ -0,0 +1,79 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + int iter; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* NOTE - syscalls referenced by number to make the test simpler */ + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1, 0); + if (rc != 0) + goto out; + + /* same syscall, many chains */ + for (iter = 0; iter < 100; iter++) { + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 3, + SCMP_A0(SCMP_CMP_EQ, iter), + SCMP_A1(SCMP_CMP_NE, 0x0), + SCMP_A2(SCMP_CMP_LT, SSIZE_MAX)); + if (rc != 0) + goto out; + } + + /* many syscalls, same chain */ + for (iter = 100; iter < 200; iter++) { + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, iter, 1, + SCMP_A0(SCMP_CMP_NE, 0)); + if (rc != 0) + goto out; + } + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 4, 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/05-sim-long_jumps.py b/tests/05-sim-long_jumps.py new file mode 100755 index 0000000..716f745 --- /dev/null +++ b/tests/05-sim-long_jumps.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + # syscalls referenced by number to make the test simpler + f.add_rule_exactly(ALLOW, 1) + i = 0 + while i < 100: + f.add_rule_exactly(ALLOW, 1000, + Arg(0, EQ, i), + Arg(1, NE, 0), + Arg(2, LT, sys.maxsize)) + i += 1 + i = 100 + while i < 200: + f.add_rule_exactly(ALLOW, i, + Arg(0, NE, 0)) + i += 1 + f.add_rule_exactly(ALLOW, 4) + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; + diff --git a/tests/05-sim-long_jumps.tests b/tests/05-sim-long_jumps.tests new file mode 100644 index 0000000..03eb6d9 --- /dev/null +++ b/tests/05-sim-long_jumps.tests @@ -0,0 +1,37 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +05-sim-long_jumps all 1 1 2 3 4 5 6 ALLOW +05-sim-long_jumps all 2 N N N N N N KILL +05-sim-long_jumps all 999 N N N N N N KILL +05-sim-long_jumps x86 1000 0-5 0x856B008 0x7FFFFFFE N N N ALLOW +05-sim-long_jumps x86_64 1000 0-5 0x856B008 0x7FFFFFFFFFFFFFFE N N N ALLOW +05-sim-long_jumps x86 1000 95-99 0x856B008 0x7FFFFFFE N N N ALLOW +05-sim-long_jumps x86_64 1000 95-99 0x856B008 0x7FFFFFFFFFFFFFFE N N N ALLOW +05-sim-long_jumps x86 1000 100 0x856B008 0x7FFFFFFE N N N KILL +05-sim-long_jumps x86_64 1000 100 0x856B008 0x7FFFFFFFFFFFFFFE N N N KILL +05-sim-long_jumps all 1001 N N N N N N KILL +05-sim-long_jumps all 99 1 N N N N N KILL +05-sim-long_jumps all 100-105 1 N N N N N ALLOW +05-sim-long_jumps all 195-199 1 N N N N N ALLOW +05-sim-long_jumps all 200 1 N N N N N KILL +05-sim-long_jumps all 3 N N N N N N KILL +05-sim-long_jumps all 4 1 2 3 4 5 6 ALLOW +05-sim-long_jumps all 5 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +05-sim-long_jumps 50 + +test type: bpf-valgrind + +# Testname +05-sim-long_jumps diff --git a/tests/06-sim-actions.c b/tests/06-sim-actions.c new file mode 100644 index 0000000..9aff9ef --- /dev/null +++ b/tests/06-sim-actions.c @@ -0,0 +1,68 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ERRNO(EPERM), SCMP_SYS(write), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_TRAP, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_TRACE(1234), SCMP_SYS(open), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/06-sim-actions.py b/tests/06-sim-actions.py new file mode 100755 index 0000000..4bd76f5 --- /dev/null +++ b/tests/06-sim-actions.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import errno +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + f.add_rule(ALLOW, "read") + f.add_rule(ERRNO(errno.EPERM), "write") + f.add_rule(TRAP, "close") + f.add_rule(TRACE(1234), "open") + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/06-sim-actions.tests b/tests/06-sim-actions.tests new file mode 100644 index 0000000..f09f0a0 --- /dev/null +++ b/tests/06-sim-actions.tests @@ -0,0 +1,27 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +06-sim-actions all read 4 0x856B008 80 N N N ALLOW +06-sim-actions all write 1 0x856B008 N N N N ERRNO(1) +06-sim-actions all close 4 N N N N N TRAP +06-sim-actions all open 0x856B008 4 N N N N TRACE(1234) +06-sim-actions x86 0-2 N N N N N N KILL +06-sim-actions x86 7-350 N N N N N N KILL +06-sim-actions x86_64 4-350 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +06-sim-actions 50 + +test type: bpf-valgrind + +# Testname +06-sim-actions diff --git a/tests/07-sim-db_bug_looping.c b/tests/07-sim-db_bug_looping.c new file mode 100644 index 0000000..53fb048 --- /dev/null +++ b/tests/07-sim-db_bug_looping.c @@ -0,0 +1,67 @@ +/** + * Seccomp Library test program + * + * Copyright IBM Corp. 2012 + * Author: Ashley Lai + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* The next three seccomp_rule_add_exact() calls for read must + * go together in this order to catch an infinite loop. */ + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A1(SCMP_CMP_EQ, 0x0)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO)); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/07-sim-db_bug_looping.py b/tests/07-sim-db_bug_looping.py new file mode 100755 index 0000000..3314a3e --- /dev/null +++ b/tests/07-sim-db_bug_looping.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + # the next three seccomp_rule_add_exact() calls for read must go together + # in this order to catch an infinite loop. + f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdout.fileno())) + f.add_rule(ALLOW, "read", Arg(1, EQ, 0)) + f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin.fileno())) + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/07-sim-db_bug_looping.tests b/tests/07-sim-db_bug_looping.tests new file mode 100644 index 0000000..a7ec72b --- /dev/null +++ b/tests/07-sim-db_bug_looping.tests @@ -0,0 +1,23 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +07-sim-db_bug_looping all read 1 0x856B008 10 N N N ALLOW +07-sim-db_bug_looping all read 2-10 0 10 N N N ALLOW +07-sim-db_bug_looping all read 0 0x856B008 10 N N N ALLOW + +test type: bpf-sim-fuzz + +# Testname StressCount +07-sim-db_bug_looping 50 + +test type: bpf-valgrind + +# Testname +07-sim-db_bug_looping diff --git a/tests/08-sim-subtree_checks.c b/tests/08-sim-subtree_checks.c new file mode 100644 index 0000000..2e6577c --- /dev/null +++ b/tests/08-sim-subtree_checks.c @@ -0,0 +1,178 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* the syscall and argument numbers are all fake to make the test + * simpler */ + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 2, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 1, + SCMP_A1(SCMP_CMP_EQ, 1)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1001, 1, + SCMP_A1(SCMP_CMP_EQ, 1)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1001, 2, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1002, 4, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2), + SCMP_A3(SCMP_CMP_EQ, 3)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1002, 2, + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1003, 2, + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1003, 4, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2), + SCMP_A3(SCMP_CMP_EQ, 3)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1004, 4, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2), + SCMP_A3(SCMP_CMP_EQ, 3)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1004, 2, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 11)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1004, 4, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2), + SCMP_A3(SCMP_CMP_EQ, 33)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1004, 2, + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1005, 2, + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1005, 4, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2), + SCMP_A3(SCMP_CMP_EQ, 3)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1005, 2, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 11)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1005, 4, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2), + SCMP_A3(SCMP_CMP_EQ, 33)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1006, 2, + SCMP_A1(SCMP_CMP_NE, 1), + SCMP_A2(SCMP_CMP_EQ, 0)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1006, 2, + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1006, 1, + SCMP_A1(SCMP_CMP_NE, 1)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_TRAP, 1007, 2, + SCMP_A2(SCMP_CMP_EQ, 1), + SCMP_A3(SCMP_CMP_EQ, 3)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1007, 2, + SCMP_A2(SCMP_CMP_EQ, 1), + SCMP_A3(SCMP_CMP_NE, 3)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1007, 1, + SCMP_A3(SCMP_CMP_NE, 3)); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/08-sim-subtree_checks.py b/tests/08-sim-subtree_checks.py new file mode 100755 index 0000000..766c3d1 --- /dev/null +++ b/tests/08-sim-subtree_checks.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + # the syscall and argument numbers are all fake to make the test simpler + f.add_rule_exactly(ALLOW, 1000, + Arg(0, EQ, 0), + Arg(1, EQ, 1)) + f.add_rule_exactly(ALLOW, 1000, + Arg(1, EQ, 1)) + + f.add_rule_exactly(ALLOW, 1001, + Arg(1, EQ, 1)) + f.add_rule_exactly(ALLOW, 1001, + Arg(0, EQ, 0), + Arg(1, EQ, 1)) + + f.add_rule_exactly(ALLOW, 1002, + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2), + Arg(3, EQ, 3)) + f.add_rule_exactly(ALLOW, 1002, + Arg(1, EQ, 1), + Arg(2, EQ, 2)) + + f.add_rule_exactly(ALLOW, 1003, + Arg(1, EQ, 1), + Arg(2, EQ, 2)) + f.add_rule_exactly(ALLOW, 1003, + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2), + Arg(3, EQ, 3)) + + f.add_rule_exactly(ALLOW, 1004, + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2), + Arg(3, EQ, 3)) + f.add_rule_exactly(ALLOW, 1004, + Arg(0, EQ, 0), + Arg(1, EQ, 11)) + f.add_rule_exactly(ALLOW, 1004, + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2), + Arg(3, EQ, 33)) + f.add_rule_exactly(ALLOW, 1004, + Arg(1, EQ, 1), + Arg(2, EQ, 2)) + + f.add_rule_exactly(ALLOW, 1005, + Arg(1, EQ, 1), + Arg(2, EQ, 2)) + f.add_rule_exactly(ALLOW, 1005, + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2), + Arg(3, EQ, 3)) + f.add_rule_exactly(ALLOW, 1005, + Arg(0, EQ, 0), + Arg(1, EQ, 11)) + f.add_rule_exactly(ALLOW, 1005, + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2), + Arg(3, EQ, 33)) + + f.add_rule_exactly(ALLOW, 1006, + Arg(1, NE, 1), + Arg(2, EQ, 0)) + f.add_rule_exactly(ALLOW, 1006, + Arg(1, EQ, 1), + Arg(2, EQ, 2)) + f.add_rule_exactly(ALLOW, 1006, + Arg(1, NE, 1)) + + f.add_rule_exactly(TRAP, 1007, + Arg(2, EQ, 1), + Arg(3, EQ, 3)) + f.add_rule_exactly(ALLOW, 1007, + Arg(2, EQ, 1), + Arg(3, NE, 3)) + f.add_rule_exactly(ALLOW, 1007, + Arg(3, NE, 3)) + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/08-sim-subtree_checks.tests b/tests/08-sim-subtree_checks.tests new file mode 100644 index 0000000..ed3ec42 --- /dev/null +++ b/tests/08-sim-subtree_checks.tests @@ -0,0 +1,47 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +08-sim-subtree_checks all 1000 0-10 1 N N N N ALLOW +08-sim-subtree_checks all 1000 0-10 0 N N N N KILL +08-sim-subtree_checks all 1001 0-10 1 N N N N ALLOW +08-sim-subtree_checks all 1001 0-10 0 N N N N KILL +08-sim-subtree_checks all 1002 0-5 1 2 0-5 N N ALLOW +08-sim-subtree_checks all 1002 0-5 2 1 0-5 N N KILL +08-sim-subtree_checks all 1003 0-5 1 2 0-5 N N ALLOW +08-sim-subtree_checks all 1003 0-5 2 1 0-5 N N KILL +08-sim-subtree_checks all 1004 0 11 5-10 10 10 1-5 ALLOW +08-sim-subtree_checks all 1004 0 1 2 0-5 N N ALLOW +08-sim-subtree_checks all 1004 1-5 1 2 0-5 N N ALLOW +08-sim-subtree_checks all 1004 1-5 1 2 30-35 N N ALLOW +08-sim-subtree_checks all 1004 1-5 2 1 30-35 N N KILL +08-sim-subtree_checks all 1005 0 11 5-10 10 10 1-5 ALLOW +08-sim-subtree_checks all 1005 0 1 2 0-5 N N ALLOW +08-sim-subtree_checks all 1005 1-5 1 2 0-5 N N ALLOW +08-sim-subtree_checks all 1005 1-5 1 2 30-35 N N ALLOW +08-sim-subtree_checks all 1005 1-5 2 1 30-35 N N KILL +08-sim-subtree_checks all 1006 0-10 1 2 N N N ALLOW +08-sim-subtree_checks all 1006 0-10 1 3 N N N KILL +08-sim-subtree_checks all 1006 10 2-100 2 N N N ALLOW +08-sim-subtree_checks all 1007 0 0 1 3 N N TRAP +08-sim-subtree_checks all 1007 1 1 1 0-2 1 1 ALLOW +08-sim-subtree_checks all 1007 1 1 2 0-2 1 1 ALLOW +08-sim-subtree_checks all 1007 1 1 2 4-6 1 1 ALLOW +08-sim-subtree_checks all 1007 1 1 0 3 1 1 KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +08-sim-subtree_checks 50 + + +test type: bpf-valgrind + +# Testname +08-sim-subtree_checks diff --git a/tests/09-sim-syscall_priority_pre.c b/tests/09-sim-syscall_priority_pre.c new file mode 100644 index 0000000..5de45bf --- /dev/null +++ b/tests/09-sim-syscall_priority_pre.c @@ -0,0 +1,75 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* the syscall and argument numbers are all fake to make the test + * simpler */ + + rc = seccomp_syscall_priority(ctx, 1000, 3); + if (rc != 0) + goto out; + rc = seccomp_syscall_priority(ctx, 1001, 2); + if (rc != 0) + goto out; + rc = seccomp_syscall_priority(ctx, 1002, 1); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 2, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1001, 1, + SCMP_A0(SCMP_CMP_EQ, 0)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1002, 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/09-sim-syscall_priority_pre.py b/tests/09-sim-syscall_priority_pre.py new file mode 100755 index 0000000..7b19943 --- /dev/null +++ b/tests/09-sim-syscall_priority_pre.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + # the syscall and argument numbers are all fake to make the test simpler + f.syscall_priority(1000, 3) + f.syscall_priority(1001, 2) + f.syscall_priority(1002, 1) + f.add_rule_exactly(ALLOW, 1000, Arg(0, EQ, 0), Arg(1, EQ, 1)) + f.add_rule_exactly(ALLOW, 1001, Arg(0, EQ, 0)) + f.add_rule_exactly(ALLOW, 1002) + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/09-sim-syscall_priority_pre.tests b/tests/09-sim-syscall_priority_pre.tests new file mode 100644 index 0000000..7b7d53f --- /dev/null +++ b/tests/09-sim-syscall_priority_pre.tests @@ -0,0 +1,26 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +09-sim-syscall_priority_pre all 999 N N N N N N KILL +09-sim-syscall_priority_pre all 1000-1002 0 1 N N N N ALLOW +09-sim-syscall_priority_pre all 1000 0 2 N N N N KILL +09-sim-syscall_priority_pre all 1001-1002 0 2 N N N N ALLOW +09-sim-syscall_priority_pre all 1000-1001 1 1 N N N N KILL +09-sim-syscall_priority_pre all 1003 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +09-sim-syscall_priority_pre 50 + +test type: bpf-valgrind + +# Testname +09-sim-syscall_priority_pre diff --git a/tests/10-sim-syscall_priority_post.c b/tests/10-sim-syscall_priority_post.c new file mode 100644 index 0000000..bafa5dd --- /dev/null +++ b/tests/10-sim-syscall_priority_post.c @@ -0,0 +1,75 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* the syscall and argument numbers are all fake to make the test + * simpler */ + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 2, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1001, 1, + SCMP_A0(SCMP_CMP_EQ, 0)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1002, 0); + if (rc != 0) + goto out; + + rc = seccomp_syscall_priority(ctx, 1000, 3); + if (rc != 0) + goto out; + rc = seccomp_syscall_priority(ctx, 1001, 2); + if (rc != 0) + goto out; + rc = seccomp_syscall_priority(ctx, 1002, 1); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/10-sim-syscall_priority_post.py b/tests/10-sim-syscall_priority_post.py new file mode 100755 index 0000000..bc2e152 --- /dev/null +++ b/tests/10-sim-syscall_priority_post.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + # the syscall and argument numbers are all fake to make the test simpler + f.add_rule_exactly(ALLOW, 1000, Arg(0, EQ, 0), Arg(1, EQ, 1)) + f.add_rule_exactly(ALLOW, 1001, Arg(0, EQ, 0)) + f.add_rule_exactly(ALLOW, 1002) + f.syscall_priority(1000, 3) + f.syscall_priority(1001, 2) + f.syscall_priority(1002, 1) + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/10-sim-syscall_priority_post.tests b/tests/10-sim-syscall_priority_post.tests new file mode 100644 index 0000000..aa0389f --- /dev/null +++ b/tests/10-sim-syscall_priority_post.tests @@ -0,0 +1,26 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +10-sim-syscall_priority_post all 999 N N N N N N KILL +10-sim-syscall_priority_post all 1000-1002 0 1 N N N N ALLOW +10-sim-syscall_priority_post all 1000 0 2 N N N N KILL +10-sim-syscall_priority_post all 1001-1002 0 2 N N N N ALLOW +10-sim-syscall_priority_post all 1000-1001 1 1 N N N N KILL +10-sim-syscall_priority_post all 1003 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +10-sim-syscall_priority_post 50 + +test type: bpf-valgrind + +# Testname +10-sim-syscall_priority_post diff --git a/tests/11-basic-basic_errors.c b/tests/11-basic-basic_errors.c new file mode 100644 index 0000000..c695e8b --- /dev/null +++ b/tests/11-basic-basic_errors.c @@ -0,0 +1,168 @@ +/** + * Seccomp Library test program + * + * Copyright IBM Corp. 2012 + * Author: Corey Bryant + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + int rc; + scmp_filter_ctx ctx; + + /* seccomp_init errors */ + ctx = seccomp_init(SCMP_ACT_ALLOW + 1); + if (ctx != NULL) + return -1; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return -1; + seccomp_release(ctx); + ctx = NULL; + + /* seccomp_reset error */ + rc = seccomp_reset(ctx, SCMP_ACT_KILL + 1); + if (rc != -EINVAL) + return -1; + rc = seccomp_reset(ctx, SCMP_ACT_KILL); + if (rc != -EINVAL) + return -1; + + /* seccomp_load error */ + rc = seccomp_load(ctx); + if (rc != -EINVAL) + return -1; + + /* seccomp_syscall_priority errors */ + rc = seccomp_syscall_priority(ctx, SCMP_SYS(read), 1); + if (rc != -EINVAL) + return -1; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return -1; + else { + rc = seccomp_syscall_priority(ctx, -10, 1); + if (rc != -EINVAL) + return -1; + } + seccomp_release(ctx); + ctx = NULL; + + /* seccomp_rule_add errors */ + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, 0)); + if (rc != -EINVAL) + return -1; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return -1; + else { + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); + if (rc != -EPERM) + return -1; + rc = seccomp_rule_add(ctx, SCMP_ACT_KILL - 1, SCMP_SYS(read), 0); + if (rc != -EINVAL) + return -1; + rc = seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(read), 6); + if (rc != -EINVAL) + return -1; + rc = seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(read), 7, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 0), + SCMP_A2(SCMP_CMP_EQ, 0), + SCMP_A3(SCMP_CMP_EQ, 0), + SCMP_A4(SCMP_CMP_EQ, 0), + SCMP_A5(SCMP_CMP_EQ, 0), + SCMP_CMP(6, SCMP_CMP_EQ, 0)); + if (rc != -EINVAL) + return -1; + rc = seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(read), 1, + SCMP_A0(_SCMP_CMP_MIN, 0)); + if (rc != -EINVAL) + return -1; + rc = seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(read), 1, + SCMP_A0(_SCMP_CMP_MAX, 0)); + if (rc != -EINVAL) + return -1; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, -10001, 0); + if (rc != -EDOM) + return -1; + } + seccomp_release(ctx); + ctx = NULL; + + /* seccomp_rule_add_exact error */ + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return -1; + if (seccomp_arch_native() != SCMP_ARCH_X86) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X86); + if (rc != 0) + return -1; + rc = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE); + if (rc != 0) + return -1; + } + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, SCMP_SYS(socket), 1, + SCMP_A0(SCMP_CMP_EQ, 2)); + if (rc != -EINVAL) + return -1; + seccomp_release(ctx); + ctx = NULL; + + /* seccomp_export_pfc errors */ + rc = seccomp_export_pfc(ctx, STDOUT_FILENO); + if (rc != -EINVAL) + return -1; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return -1; + else { + rc = seccomp_export_pfc(ctx, sysconf(_SC_OPEN_MAX) - 1); + if (rc != EBADF) + return -1; + } + seccomp_release(ctx); + ctx = NULL; + + /* seccomp_export_bpf errors */ + rc = seccomp_export_bpf(ctx, STDOUT_FILENO); + if (rc != -EINVAL) + return -1; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return -1; + else { + rc = seccomp_export_bpf(ctx, sysconf(_SC_OPEN_MAX) - 1); + if (rc != -EBADF) + return -1; + } + seccomp_release(ctx); + ctx = NULL; + + return 0; +} diff --git a/tests/11-basic-basic_errors.py b/tests/11-basic-basic_errors.py new file mode 100755 index 0000000..4923e9b --- /dev/null +++ b/tests/11-basic-basic_errors.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(): + # this test differs from the native test for obvious reasons + try: + f = SyscallFilter(ALLOW + 1) + except RuntimeError: + pass + + f = SyscallFilter(ALLOW) + try: + f.reset(KILL + 1) + except ValueError: + pass + + f = SyscallFilter(ALLOW) + try: + f.syscall_priority(-10000, 1) + except RuntimeError: + pass + + f = SyscallFilter(ALLOW) + try: + f.add_rule(ALLOW, "read") + except RuntimeError: + pass + try: + f.add_rule(KILL - 1, "read") + except RuntimeError: + pass + try: + f.add_rule(KILL, "read", + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2), + Arg(3, EQ, 3), + Arg(4, EQ, 4), + Arg(5, EQ, 5), + Arg(6, EQ, 6), + Arg(7, EQ, 7)) + except RuntimeError: + pass + try: + f.add_rule(KILL, -1001) + except RuntimeError: + pass + + f = SyscallFilter(ALLOW) + if not f.exist_arch(Arch.X86): + f.add_arch(Arch.X86) + f.remove_arch(Arch.NATIVE) + try: + f.add_rule_exactly(KILL, "socket", Arg(0, EQ, 2)) + except RuntimeError: + pass + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/11-basic-basic_errors.tests b/tests/11-basic-basic_errors.tests new file mode 100644 index 0000000..3593392 --- /dev/null +++ b/tests/11-basic-basic_errors.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: basic + +# Test command +11-basic-basic_errors diff --git a/tests/12-sim-basic_masked_ops.c b/tests/12-sim-basic_masked_ops.c new file mode 100644 index 0000000..a6fd939 --- /dev/null +++ b/tests/12-sim-basic_masked_ops.c @@ -0,0 +1,87 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + /* the syscall and argument numbers are all fake to make the test + * simpler */ + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 3, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_EQ, 1), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 3, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_MASKED_EQ, 0x00ff, 1), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 3, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_MASKED_EQ, 0xffff, 11), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 3, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_MASKED_EQ, 0xffff, 111), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 1000, 3, + SCMP_A0(SCMP_CMP_EQ, 0), + SCMP_A1(SCMP_CMP_MASKED_EQ, 0xff00, 1000), + SCMP_A2(SCMP_CMP_EQ, 2)); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/12-sim-basic_masked_ops.py b/tests/12-sim-basic_masked_ops.py new file mode 100755 index 0000000..283534b --- /dev/null +++ b/tests/12-sim-basic_masked_ops.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + # the syscall and argument numbers are all fake to make the test simpler + f.add_rule_exactly(ALLOW, 1000, + Arg(0, EQ, 0), + Arg(1, EQ, 1), + Arg(2, EQ, 2)) + f.add_rule_exactly(ALLOW, 1000, + Arg(0, EQ, 0), + Arg(1, MASKED_EQ, 0x00ff, 1), + Arg(2, EQ, 2)) + f.add_rule_exactly(ALLOW, 1000, + Arg(0, EQ, 0), + Arg(1, MASKED_EQ, 0xffff, 11), + Arg(2, EQ, 2)) + f.add_rule_exactly(ALLOW, 1000, + Arg(0, EQ, 0), + Arg(1, MASKED_EQ, 0xffff, 111), + Arg(2, EQ, 2)) + f.add_rule_exactly(ALLOW, 1000, + Arg(0, EQ, 0), + Arg(1, MASKED_EQ, 0xff00, 1000), + Arg(2, EQ, 2)) + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/12-sim-basic_masked_ops.tests b/tests/12-sim-basic_masked_ops.tests new file mode 100644 index 0000000..20e0f6d --- /dev/null +++ b/tests/12-sim-basic_masked_ops.tests @@ -0,0 +1,42 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +12-sim-basic_masked_ops all 1000 0 1 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x01 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x02-0x0A 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x101 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 11 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x0B 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x0C-0x6E 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x1000B 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 111 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x6F 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x70-0x100 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x102-0x200 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x10002-0x1000A 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x1000C-0x1006E 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x1006F 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 1000 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x3E8 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x2FF 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x300-0x3FF 2 N N N ALLOW +12-sim-basic_masked_ops all 1000 0 0x400 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x402-0x4FF 2 N N N KILL +12-sim-basic_masked_ops all 1000 0 0x10300-0x103FF 2 N N N ALLOW + +test type: bpf-sim-fuzz + +# Testname StressCount +12-sim-basic_masked_ops 50 + +test type: bpf-valgrind + +# Testname +12-sim-basic_masked_ops diff --git a/tests/13-basic-attrs.c b/tests/13-basic-attrs.c new file mode 100644 index 0000000..99e8dcb --- /dev/null +++ b/tests/13-basic-attrs.c @@ -0,0 +1,78 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + uint32_t val = (uint32_t)(-1); + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + goto out; + + rc = seccomp_attr_get(ctx, SCMP_FLTATR_ACT_DEFAULT, &val); + if (rc != 0) + goto out; + if (val != SCMP_ACT_ALLOW) { + rc = -1; + goto out; + } + rc = seccomp_attr_set(ctx, SCMP_FLTATR_ACT_DEFAULT, val); + if (rc != -EACCES) { + rc = -1; + goto out; + } + + rc = seccomp_attr_set(ctx, SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_ALLOW); + if (rc != 0) + goto out; + rc = seccomp_attr_get(ctx, SCMP_FLTATR_ACT_BADARCH, &val); + if (rc != 0) + goto out; + if (val != SCMP_ACT_ALLOW) { + rc = -1; + goto out; + } + + rc = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0); + if (rc != 0) + goto out; + rc = seccomp_attr_get(ctx, SCMP_FLTATR_CTL_NNP, &val); + if (rc != 0) + goto out; + if (val != 0) { + rc = -1; + goto out; + } + + rc = 0; +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/13-basic-attrs.py b/tests/13-basic-attrs.py new file mode 100755 index 0000000..471ab34 --- /dev/null +++ b/tests/13-basic-attrs.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(): + f = SyscallFilter(ALLOW) + if f.get_attr(Attr.ACT_DEFAULT) != ALLOW: + raise RuntimeError("Failed getting Attr.ACT_DEFAULT") + try: + f.set_attr(Attr.ACT_DEFAULT, ALLOW) + except RuntimeError: + pass + f.set_attr(Attr.ACT_BADARCH, ALLOW) + if f.get_attr(Attr.ACT_BADARCH) != ALLOW: + raise RuntimeError("Failed getting Attr.ACT_BADARCH") + f.set_attr(Attr.CTL_NNP, 0) + if f.get_attr(Attr.CTL_NNP) != 0: + raise RuntimeError("Failed getting Attr.CTL_NNP") + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/13-basic-attrs.tests b/tests/13-basic-attrs.tests new file mode 100644 index 0000000..2288787 --- /dev/null +++ b/tests/13-basic-attrs.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +test type: basic + +# Test command +13-basic-attrs diff --git a/tests/14-sim-reset.c b/tests/14-sim-reset.c new file mode 100644 index 0000000..adcc934 --- /dev/null +++ b/tests/14-sim-reset.c @@ -0,0 +1,62 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); + if (rc != 0) + goto out; + + rc = seccomp_reset(ctx, SCMP_ACT_KILL); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/14-sim-reset.py b/tests/14-sim-reset.py new file mode 100755 index 0000000..60c131f --- /dev/null +++ b/tests/14-sim-reset.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + f.add_rule(ALLOW, "read") + f.reset() + f.add_rule(ALLOW, "write") + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/14-sim-reset.tests b/tests/14-sim-reset.tests new file mode 100644 index 0000000..da52b2d --- /dev/null +++ b/tests/14-sim-reset.tests @@ -0,0 +1,29 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +int main(int argc, char *argv[]) +{ + char *name; + + if (seccomp_syscall_resolve_name("open") != __NR_open) + return 1; + if (seccomp_syscall_resolve_name("socket") != __NR_socket) + return 1; + if (seccomp_syscall_resolve_name("INVALID") != __NR_SCMP_ERROR) + return 1; + + if (seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, + "open") != __NR_open) + return 1; + if (seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, + "socket") != __NR_socket) + return 1; + if (seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, + "INVALID") != __NR_SCMP_ERROR) + return 1; + + name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, __NR_open); + if (name == NULL || strcmp(name, "open") != 0) + return 1; + name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, __NR_socket); + if (name == NULL || strcmp(name, "socket") != 0) + return 1; + name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, + __NR_SCMP_ERROR); + if (name != NULL) + return 1; + + return 0; +} diff --git a/tests/15-basic-resolver.py b/tests/15-basic-resolver.py new file mode 100755 index 0000000..a724d1b --- /dev/null +++ b/tests/15-basic-resolver.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(): + f = SyscallFilter(KILL) + # this differs from the native test as we don't support the syscall + # resolution functions by themselves + f.add_rule(ALLOW, "open") + f.add_rule(ALLOW, "socket") + try: + f.add_rule(ALLOW, "INVALID") + except RuntimeError: + pass + + sys_num = resolve_syscall(Arch.NATIVE, "open") + sys_name = resolve_syscall(Arch.NATIVE, sys_num) + if (sys_name != "open"): + raise RuntimeError("Test failure") + sys_num = resolve_syscall(Arch.NATIVE, "socket") + sys_name = resolve_syscall(Arch.NATIVE, sys_num) + if (sys_name != "socket"): + raise RuntimeError("Test failure") + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/15-basic-resolver.tests b/tests/15-basic-resolver.tests new file mode 100644 index 0000000..7e4e7ba --- /dev/null +++ b/tests/15-basic-resolver.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +test type: basic + +# Test command +15-basic-resolver diff --git a/tests/16-sim-arch_basic.c b/tests/16-sim-arch_basic.c new file mode 100644 index 0000000..5b02cca --- /dev/null +++ b/tests/16-sim-arch_basic.c @@ -0,0 +1,102 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + if (seccomp_arch_exist(ctx, SCMP_ARCH_X86)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X86); + if (rc != 0) + goto out; + } + if (seccomp_arch_exist(ctx, SCMP_ARCH_X86_64)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X86_64); + if (rc != 0) + goto out; + } + if (seccomp_arch_exist(ctx, SCMP_ARCH_X32)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X32); + if (rc != 0) + goto out; + } + if (seccomp_arch_exist(ctx, SCMP_ARCH_ARM)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_ARM); + if (rc != 0) + goto out; + } + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(shutdown), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/16-sim-arch_basic.py b/tests/16-sim-arch_basic.py new file mode 100755 index 0000000..d29a5ff --- /dev/null +++ b/tests/16-sim-arch_basic.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + if not f.exist_arch(Arch.X86): + f.add_arch(Arch.X86) + if not f.exist_arch(Arch.X86_64): + f.add_arch(Arch.X86_64) + if not f.exist_arch(Arch.X32): + f.add_arch(Arch.X32) + if not f.exist_arch(Arch.ARM): + f.add_arch(Arch.ARM) + f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin.fileno())) + f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno())) + f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno())) + f.add_rule(ALLOW, "close") + f.add_rule(ALLOW, "socket") + f.add_rule(ALLOW, "connect") + f.add_rule(ALLOW, "shutdown") + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/16-sim-arch_basic.tests b/tests/16-sim-arch_basic.tests new file mode 100644 index 0000000..39917b5 --- /dev/null +++ b/tests/16-sim-arch_basic.tests @@ -0,0 +1,32 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +16-sim-arch_basic +all read 0 0x856B008 10 N N N ALLOW +16-sim-arch_basic +all read 1-10 0x856B008 10 N N N KILL +16-sim-arch_basic +all write 1-2 0x856B008 10 N N N ALLOW +16-sim-arch_basic +all write 3-10 0x856B008 10 N N N KILL +16-sim-arch_basic +all close N N N N N N ALLOW +16-sim-arch_basic +all open 0x856B008 4 N N N N KILL +16-sim-arch_basic +x86 socket 1 N N N N N ALLOW +16-sim-arch_basic +x86 connect 3 N N N N N ALLOW +16-sim-arch_basic +x86 shutdown 13 N N N N N ALLOW +16-sim-arch_basic +x86_64 socket 0 1 2 N N N ALLOW +16-sim-arch_basic +x86_64 connect 0 1 2 N N N ALLOW +16-sim-arch_basic +x86_64 shutdown 0 1 2 N N N ALLOW + +test type: bpf-sim-fuzz + +# Testname StressCount +16-sim-arch_basic 50 + +test type: bpf-valgrind + +# Testname +16-sim-arch_basic diff --git a/tests/17-sim-arch_merge.c b/tests/17-sim-arch_merge.c new file mode 100644 index 0000000..61e1490 --- /dev/null +++ b/tests/17-sim-arch_merge.c @@ -0,0 +1,110 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx_64, ctx_32; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out_all; + + ctx_32 = seccomp_init(SCMP_ACT_KILL); + if (ctx_32 == NULL) + goto out_all; + ctx_64 = seccomp_init(SCMP_ACT_KILL); + if (ctx_64 == NULL) + goto out_all; + + if (seccomp_arch_exist(ctx_32, SCMP_ARCH_X86) == -EEXIST) { + rc = seccomp_arch_add(ctx_32, SCMP_ARCH_X86); + if (rc != 0) + goto out_all; + rc = seccomp_arch_remove(ctx_32, SCMP_ARCH_NATIVE); + if (rc != 0) + goto out_all; + } + if (seccomp_arch_exist(ctx_64, SCMP_ARCH_X86_64) == -EEXIST) { + rc = seccomp_arch_add(ctx_64, SCMP_ARCH_X86_64); + if (rc != 0) + goto out_all; + rc = seccomp_arch_remove(ctx_64, SCMP_ARCH_NATIVE); + if (rc != 0) + goto out_all; + } + + rc = seccomp_rule_add(ctx_32, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO)); + if (rc != 0) + goto out_all; + + rc = seccomp_rule_add(ctx_32, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO)); + if (rc != 0) + goto out_all; + + rc = seccomp_rule_add(ctx_32, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO)); + if (rc != 0) + goto out_all; + + rc = seccomp_rule_add(ctx_32, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out_all; + + rc = seccomp_rule_add(ctx_64, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0); + if (rc != 0) + goto out_all; + + rc = seccomp_rule_add(ctx_64, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0); + if (rc != 0) + goto out_all; + + rc = seccomp_rule_add(ctx_64, SCMP_ACT_ALLOW, SCMP_SYS(shutdown), 0); + if (rc != 0) + goto out_all; + + rc = seccomp_merge(ctx_64, ctx_32); + if (rc != 0) + goto out_all; + + /* NOTE: ctx_32 is no longer valid at this point */ + + rc = util_filter_output(&opts, ctx_64); + if (rc) + goto out; + +out: + seccomp_release(ctx_64); + return (rc < 0 ? -rc : rc); +out_all: + seccomp_release(ctx_32); + goto out; +} diff --git a/tests/17-sim-arch_merge.py b/tests/17-sim-arch_merge.py new file mode 100755 index 0000000..44e9cc4 --- /dev/null +++ b/tests/17-sim-arch_merge.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f32 = SyscallFilter(KILL) + f64 = SyscallFilter(KILL) + if not f32.exist_arch(Arch.X86): + f32.add_arch(Arch.X86) + f32.remove_arch(Arch.NATIVE) + if not f64.exist_arch(Arch.X86_64): + f64.add_arch(Arch.X86_64) + f64.remove_arch(Arch.NATIVE) + f32.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin.fileno())) + f32.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno())) + f32.add_rule(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno())) + f32.add_rule(ALLOW, "close") + f64.add_rule(ALLOW, "socket") + f64.add_rule(ALLOW, "connect") + f64.add_rule(ALLOW, "shutdown") + f64.merge(f32) + return f64 + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/17-sim-arch_merge.tests b/tests/17-sim-arch_merge.tests new file mode 100644 index 0000000..0f27ca9 --- /dev/null +++ b/tests/17-sim-arch_merge.tests @@ -0,0 +1,29 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +17-sim-arch_merge +x86 read 0 0x856B008 10 N N N ALLOW +17-sim-arch_merge +x86 read 1-10 0x856B008 10 N N N KILL +17-sim-arch_merge +x86 write 1-2 0x856B008 10 N N N ALLOW +17-sim-arch_merge +x86 write 3-10 0x856B008 10 N N N KILL +17-sim-arch_merge +x86 close N N N N N N ALLOW +17-sim-arch_merge +x86 open 0x856B008 4 N N N N KILL +17-sim-arch_merge +x86_64 socket 0 1 2 N N N ALLOW +17-sim-arch_merge +x86_64 connect 0 1 2 N N N ALLOW +17-sim-arch_merge +x86_64 shutdown 0 1 2 N N N ALLOW + +test type: bpf-sim-fuzz + +# Testname StressCount +17-sim-arch_merge 50 + +test type: bpf-valgrind + +# Testname +17-sim-arch_merge diff --git a/tests/18-sim-basic_whitelist.c b/tests/18-sim-basic_whitelist.c new file mode 100644 index 0000000..5deefe7 --- /dev/null +++ b/tests/18-sim-basic_whitelist.c @@ -0,0 +1,73 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_KILL, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/18-sim-basic_whitelist.py b/tests/18-sim-basic_whitelist.py new file mode 100755 index 0000000..a7b9cb7 --- /dev/null +++ b/tests/18-sim-basic_whitelist.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(ALLOW) + f.add_rule_exactly(KILL, "read", Arg(0, EQ, sys.stdin.fileno())); + f.add_rule_exactly(KILL, "write", Arg(0, EQ, sys.stdout.fileno())); + f.add_rule_exactly(KILL, "write", Arg(0, EQ, sys.stderr.fileno())); + f.add_rule_exactly(KILL, "close"); + f.add_rule_exactly(KILL, "rt_sigreturn"); + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/18-sim-basic_whitelist.tests b/tests/18-sim-basic_whitelist.tests new file mode 100644 index 0000000..d88d0d2 --- /dev/null +++ b/tests/18-sim-basic_whitelist.tests @@ -0,0 +1,32 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +18-sim-basic_whitelist all read 0 0x856B008 10 N N N KILL +18-sim-basic_whitelist all read 1-10 0x856B008 10 N N N ALLOW +18-sim-basic_whitelist all write 1-2 0x856B008 10 N N N KILL +18-sim-basic_whitelist all write 3-10 0x856B008 10 N N N ALLOW +18-sim-basic_whitelist all close N N N N N N KILL +18-sim-basic_whitelist all rt_sigreturn N N N N N N KILL +18-sim-basic_whitelist all open 0x856B008 4 N N N N ALLOW +18-sim-basic_whitelist x86 0-2 N N N N N N ALLOW +18-sim-basic_whitelist x86 7-172 N N N N N N ALLOW +18-sim-basic_whitelist x86 174-350 N N N N N N ALLOW +18-sim-basic_whitelist x86_64 4-14 N N N N N N ALLOW +18-sim-basic_whitelist x86_64 16-350 N N N N N N ALLOW + +test type: bpf-sim-fuzz + +# Testname StressCount +18-sim-basic_whitelist 50 + +test type: bpf-valgrind + +# Testname +18-sim-basic_whitelist diff --git a/tests/19-sim-missing_syscalls.c b/tests/19-sim-missing_syscalls.c new file mode 100644 index 0000000..0ccb0f5 --- /dev/null +++ b/tests/19-sim-missing_syscalls.c @@ -0,0 +1,66 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + if (seccomp_arch_native() != SCMP_ARCH_X86) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X86); + if (rc != 0) + goto out; + rc = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE); + if (rc != 0) + goto out; + } + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tuxcall), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tuxcall), 0); + if (rc != -EDOM) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/19-sim-missing_syscalls.py b/tests/19-sim-missing_syscalls.py new file mode 100755 index 0000000..38408b1 --- /dev/null +++ b/tests/19-sim-missing_syscalls.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + if not system_arch() == Arch.X86: + f.add_arch(Arch.X86) + f.remove_arch(Arch.NATIVE) + f.add_rule(ALLOW, "tuxcall") + try: + f.add_rule_exactly(ALLOW, "tuxcall") + except RuntimeError: + pass + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/19-sim-missing_syscalls.tests b/tests/19-sim-missing_syscalls.tests new file mode 100644 index 0000000..5a1f244 --- /dev/null +++ b/tests/19-sim-missing_syscalls.tests @@ -0,0 +1,21 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +19-sim-missing_syscalls +x86 0-350 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +19-sim-missing_syscalls 50 + +test type: bpf-valgrind + +# Testname +19-sim-missing_syscalls diff --git a/tests/20-live-basic_die.c b/tests/20-live-basic_die.c new file mode 100644 index 0000000..b71e0f5 --- /dev/null +++ b/tests/20-live-basic_die.c @@ -0,0 +1,69 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + int action; + scmp_filter_ctx ctx; + + rc = util_action_parse(argv[1]); + if (rc == -1) + goto out; + action = rc; + + if (action == SCMP_ACT_TRAP) { + rc = util_trap_install(); + if (rc != 0) + goto out; + } + + ctx = seccomp_init(action); + if (ctx == NULL) + goto out; + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); + if (rc != 0) + goto out; + rc = seccomp_load(ctx); + if (rc != 0) + goto out; + + rc = util_file_write("/dev/null"); + if (rc != 0) + goto out; + + rc = 160; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/20-live-basic_die.py b/tests/20-live-basic_die.py new file mode 100755 index 0000000..2b07776 --- /dev/null +++ b/tests/20-live-basic_die.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(): + action = util.parse_action(sys.argv[1]) + if action == TRAP: + util.install_trap() + f = SyscallFilter(action) + f.add_rule_exactly(ALLOW, "rt_sigreturn") + f.add_rule_exactly(ALLOW, "exit_group") + f.load() + try: + util.write_file("/dev/null") + except OSError as ex: + quit(ex.errno) + quit(160) + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/20-live-basic_die.tests b/tests/20-live-basic_die.tests new file mode 100644 index 0000000..ac30ae1 --- /dev/null +++ b/tests/20-live-basic_die.tests @@ -0,0 +1,13 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + scmp_filter_ctx ctx; + + rc = util_action_parse(argv[1]); + if (rc != SCMP_ACT_ALLOW) { + rc = 1; + goto out; + } + + rc = util_trap_install(); + if (rc != 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_TRAP); + if (ctx == NULL) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); + if (rc != 0) + goto out; + rc = seccomp_load(ctx); + if (rc != 0) + goto out; + + rc = util_file_write("/dev/null"); + if (rc != 0) + goto out; + + rc = 160; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/21-live-basic_allow.py b/tests/21-live-basic_allow.py new file mode 100755 index 0000000..1332f2e --- /dev/null +++ b/tests/21-live-basic_allow.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(): + action = util.parse_action(sys.argv[1]) + if not action == ALLOW: + quit(1) + util.install_trap() + f = SyscallFilter(TRAP) + # NOTE: additional syscalls required for python + f.add_rule_exactly(ALLOW, "stat") + f.add_rule_exactly(ALLOW, "fstat") + f.add_rule_exactly(ALLOW, "open") + f.add_rule_exactly(ALLOW, "mmap") + f.add_rule_exactly(ALLOW, "munmap") + f.add_rule_exactly(ALLOW, "read") + f.add_rule_exactly(ALLOW, "write") + f.add_rule_exactly(ALLOW, "close") + f.add_rule_exactly(ALLOW, "rt_sigaction") + f.add_rule_exactly(ALLOW, "rt_sigreturn") + f.add_rule_exactly(ALLOW, "exit_group") + f.load() + try: + util.write_file("/dev/null") + except OSError as ex: + quit(ex.errno) + quit(160) + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/21-live-basic_allow.tests b/tests/21-live-basic_allow.tests new file mode 100644 index 0000000..e41e4ef --- /dev/null +++ b/tests/21-live-basic_allow.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore , Vitaly Shukela + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + struct scmp_arg_cmp arg_cmp; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + arg_cmp = SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO); + rc = seccomp_rule_add_exact_array(ctx, SCMP_ACT_ALLOW, + SCMP_SYS(read), 1, &arg_cmp); + if (rc != 0) + goto out; + + arg_cmp = SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO); + rc = seccomp_rule_add_exact_array(ctx, SCMP_ACT_ALLOW, + SCMP_SYS(write), 1, &arg_cmp); + if (rc != 0) + goto out; + + arg_cmp = SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO); + rc = seccomp_rule_add_exact_array(ctx, SCMP_ACT_ALLOW, + SCMP_SYS(write), 1, &arg_cmp); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact_array(ctx, SCMP_ACT_ALLOW, + SCMP_SYS(close), 0, NULL); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact_array(ctx, SCMP_ACT_ALLOW, + SCMP_SYS(rt_sigreturn), 0, NULL); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/22-sim-basic_chains_array.py b/tests/22-sim-basic_chains_array.py new file mode 100755 index 0000000..dfc3a58 --- /dev/null +++ b/tests/22-sim-basic_chains_array.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# NOTE: this is identical to 03-sim-basic_chains.py but is here to satisfy the +# need for an equivalent Python test for each native C test + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + f.add_rule_exactly(ALLOW, "read", Arg(0, EQ, sys.stdin.fileno())); + f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno())); + f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno())); + f.add_rule_exactly(ALLOW, "close"); + f.add_rule_exactly(ALLOW, "rt_sigreturn"); + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/22-sim-basic_chains_array.tests b/tests/22-sim-basic_chains_array.tests new file mode 100644 index 0000000..b8867b7 --- /dev/null +++ b/tests/22-sim-basic_chains_array.tests @@ -0,0 +1,31 @@ +# +# libseccomp regression test automation data +# +# Author: Vitaly Shukela +# + +test type: bpf-sim + +# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result +22-sim-basic_chains_array all read 0 0x856B008 10 N N N ALLOW +22-sim-basic_chains_array all read 1-10 0x856B008 10 N N N KILL +22-sim-basic_chains_array all write 1-2 0x856B008 10 N N N ALLOW +22-sim-basic_chains_array all write 3-10 0x856B008 10 N N N KILL +22-sim-basic_chains_array all close N N N N N N ALLOW +22-sim-basic_chains_array all rt_sigreturn N N N N N N ALLOW +22-sim-basic_chains_array all open 0x856B008 4 N N N N KILL +22-sim-basic_chains_array x86 0-2 N N N N N N KILL +22-sim-basic_chains_array x86 7-172 N N N N N N KILL +22-sim-basic_chains_array x86 174-350 N N N N N N KILL +22-sim-basic_chains_array x86_64 4-14 N N N N N N KILL +22-sim-basic_chains_array x86_64 16-350 N N N N N N KILL + +test type: bpf-sim-fuzz + +# Testname StressCount +22-sim-basic_chains_array 50 + +test type: bpf-valgrind + +# Testname +22-sim-basic_chains_array diff --git a/tests/23-sim-arch_all_basic.c b/tests/23-sim-arch_all_basic.c new file mode 100644 index 0000000..1b39914 --- /dev/null +++ b/tests/23-sim-arch_all_basic.c @@ -0,0 +1,93 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + if (seccomp_arch_exist(ctx, SCMP_ARCH_X86)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X86); + if (rc != 0) + goto out; + } + if (seccomp_arch_exist(ctx, SCMP_ARCH_X86_64)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X86_64); + if (rc != 0) + goto out; + } + if (seccomp_arch_exist(ctx, SCMP_ARCH_X32)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_X32); + if (rc != 0) + goto out; + } + if (seccomp_arch_exist(ctx, SCMP_ARCH_ARM)) { + rc = seccomp_arch_add(ctx, SCMP_ARCH_ARM); + if (rc != 0) + goto out; + } + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, + SCMP_A0(SCMP_CMP_EQ, STDIN_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/23-sim-arch_all_basic.py b/tests/23-sim-arch_all_basic.py new file mode 100755 index 0000000..2674636 --- /dev/null +++ b/tests/23-sim-arch_all_basic.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + if not f.exist_arch(Arch.X86): + f.add_arch(Arch.X86) + if not f.exist_arch(Arch.X86_64): + f.add_arch(Arch.X86_64) + if not f.exist_arch(Arch.X32): + f.add_arch(Arch.X32) + if not f.exist_arch(Arch.ARM): + f.add_arch(Arch.ARM) + f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin.fileno())) + f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno())) + f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stderr.fileno())) + f.add_rule(ALLOW, "close") + f.add_rule(ALLOW, "rt_sigreturn") + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/23-sim-arch_all_basic.tests b/tests/23-sim-arch_all_basic.tests new file mode 100644 index 0000000..980268f --- /dev/null +++ b/tests/23-sim-arch_all_basic.tests @@ -0,0 +1,28 @@ +# +# libseccomp regression test automation data +# +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + int fd; + scmp_filter_ctx ctx; + const char buf[] = "testing"; + ssize_t buf_len = strlen(buf); + + rc = util_action_parse(argv[1]); + if (rc != SCMP_ACT_ALLOW) { + rc = 1; + goto out; + } + + rc = util_trap_install(); + if (rc != 0) + goto out; + + fd = open("/dev/null", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) { + rc = errno; + goto out; + } + + ctx = seccomp_init(SCMP_ACT_TRAP); + if (ctx == NULL) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_A0(SCMP_CMP_EQ, fd)); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); + if (rc != 0) + goto out; + rc = seccomp_rule_add_exact(ctx, + SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); + if (rc != 0) + goto out; + rc = seccomp_load(ctx); + if (rc != 0) + goto out; + + if (write(fd, buf, buf_len) < buf_len) { + rc = errno; + goto out; + } + if (close(fd) < 0) { + rc = errno; + goto out; + } + + rc = 160; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/24-live-arg_allow.py b/tests/24-live-arg_allow.py new file mode 100755 index 0000000..32c63ec --- /dev/null +++ b/tests/24-live-arg_allow.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import os +import sys + +import util + +from seccomp import * + +def test(): + action = util.parse_action(sys.argv[1]) + if not action == ALLOW: + quit(1) + util.install_trap() + + fd = os.open("/dev/null", os.O_WRONLY|os.O_CREAT, 0600) + + f = SyscallFilter(TRAP) + # NOTE: additional syscalls required for python + f.add_rule_exactly(ALLOW, "write", Arg(0, EQ, fd)) + f.add_rule_exactly(ALLOW, "close") + f.add_rule_exactly(ALLOW, "rt_sigaction") + f.add_rule_exactly(ALLOW, "rt_sigreturn") + f.add_rule_exactly(ALLOW, "exit_group") + f.load() + + try: + if not os.write(fd, "testing") == len("testing"): + raise IOError("failed to write the full test string") + quit(160) + except OSError as ex: + quit(ex.errno) + os.close(fd) + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/24-live-arg_allow.tests b/tests/24-live-arg_allow.tests new file mode 100644 index 0000000..e383e6a --- /dev/null +++ b/tests/24-live-arg_allow.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + struct util_options opts; + scmp_filter_ctx ctx; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 10, 2, + SCMP_A0(SCMP_CMP_EQ, 11), + SCMP_A1(SCMP_CMP_NE, 12)); + if (rc != 0) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, 20, 3, + SCMP_A0(SCMP_CMP_EQ, 21), + SCMP_A1(SCMP_CMP_NE, 22), + SCMP_A2(SCMP_CMP_EQ, 23)); + if (rc != 0) + goto out; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/25-sim-multilevel_chains_adv.py b/tests/25-sim-multilevel_chains_adv.py new file mode 100755 index 0000000..95a673c --- /dev/null +++ b/tests/25-sim-multilevel_chains_adv.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +import argparse +import sys + +import util + +from seccomp import * + +def test(args): + f = SyscallFilter(KILL) + f.add_rule_exactly(ALLOW, 10, + Arg(0, EQ, 11), + Arg(1, NE, 12)); + f.add_rule_exactly(ALLOW, 20, + Arg(0, EQ, 21), + Arg(1, NE, 22), + Arg(2, EQ, 23)); + return f + +args = util.get_opt() +ctx = test(args) +util.filter_output(args, ctx) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/25-sim-multilevel_chains_adv.tests b/tests/25-sim-multilevel_chains_adv.tests new file mode 100644 index 0000000..1bdfa40 --- /dev/null +++ b/tests/25-sim-multilevel_chains_adv.tests @@ -0,0 +1,30 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# +# macros +# + +include ../macros.mk + +# +# configuration +# + +include $(TOPDIR)/version_info.mk +include $(TOPDIR)/configure.mk + +OBJS = util.o + +LDFLAGS := ../src/libseccomp.a $(OBJS) + +TEST_PRIVATE = 00-test + +TESTS = 01-sim-allow \ + 02-sim-basic \ + 03-sim-basic_chains \ + 04-sim-multilevel_chains \ + 05-sim-long_jumps \ + 06-sim-actions \ + 07-sim-db_bug_looping \ + 08-sim-subtree_checks \ + 09-sim-syscall_priority_pre \ + 10-sim-syscall_priority_post \ + 11-basic-basic_errors \ + 12-sim-basic_masked_ops \ + 13-basic-attrs \ + 14-sim-reset \ + 15-basic-resolver \ + 16-sim-arch_basic \ + 17-sim-arch_merge \ + 18-sim-basic_whitelist \ + 19-sim-missing_syscalls \ + 20-live-basic_die \ + 21-live-basic_allow \ + 22-sim-basic_chains_array \ + 23-sim-arch_all_basic \ + 24-live-arg_allow \ + 25-sim-multilevel_chains_adv + +DEPS_OBJS = $(OBJS:%.o=%.d) +DEPS_TESTS = $(TESTS:%=%.d) + +# +# targets +# + +.PHONY: check clean + +all: $(TESTS) $(OBJS) + +-include $(DEPS_TESTS) $(DEPS_OBJS) + +$(DEPS_TESTS): + $(MAKEDEP_EXEC) + $(ADDDEP) $@ ../src/libseccomp.a + $(ADDDEP) $@ $(OBJS) + +$(TESTS): + $(COMPILE_EXEC) + +$(TEST_PRIVATE): 00-test.c $(OBJS) ../src/libseccomp.a + $(COMPILE_EXEC) + +check: $(TESTS) + ./regression + +clean: + $(RM) $(DEPS_TESTS) $(DEPS_OBJS) $(TESTS) $(TEST_PRIVATE) $(OBJS) *.pyc diff --git a/tests/regression b/tests/regression new file mode 100755 index 0000000..790d5e1 --- /dev/null +++ b/tests/regression @@ -0,0 +1,885 @@ +#!/bin/bash + +# +# libseccomp regression test automation script +# +# Copyright IBM Corp. 2012 +# Author: Corey Bryant +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +GLBL_ARCH_SUPPORT="x86 x86_64 x32 arm" + +GLBL_SYS_ARCH="../tools/scmp_arch_detect" +GLBL_SYS_RESOLVER="../tools/scmp_sys_resolver" +GLBL_SYS_SIM="../tools/scmp_bpf_sim" + +#### +# functions + +# +# Dependency check +# +# Arguments: +# 1 Dependency to check for +# +function check_deps() { + [[ -z "$1" ]] && return + which "$1" >& /dev/null + return $? +} + +# +# Dependency verification +# +# Arguments: +# 1 Dependency to check for +# +function verify_deps() { + [[ -z "$1" ]] && return + if ! check_deps "$1"; then + echo "error: install \"$1\" and include it in your \$PATH" + exit 1 + fi +} + +# +# Print out script usage details +# +function usage() { +cat << EOF +usage: regression [-h] [-v] [-m MODE] [-a] [-b BATCH_NAME] [-l ] + [-s SINGLE_TEST] [-t ] [-T ] + +libseccomp regression test automation script +optional arguments: + -h show this help message and exit + -m MODE specified the test mode [c (default), python] + -a specifies all tests are to be run + -b BATCH_NAME specifies batch of tests to be run + -l [LOG] specifies log file to write test results to + -s SINGLE_TEST specifies individual test number to be run + -t [TEMP_DIR] specifies directory to create temporary files in + -T [TEST_TYPE] only run tests matching the specified type + -v specifies that verbose output be provided +EOF +} + +# +# Generate a string representing the test number +# +# Arguments: +# 1 string containing the batch name +# 2 value of the test number from the input test data file +# 3 value of the subtest number that corresponds to argument 1 +# +# The actual test number from the input test data file is 1 for the first +# test found in the file, 2 for the second, etc. +# +# The subtest number is useful for batches that generate multiple tests based +# on a single line of input from the test data file. The subtest number +# should be set to zero if the corresponding test data is actual test data +# that was read from the input file, and should be set to a value greater than +# zero if the corresponding test data is generated. +# +function generate_test_num() { + local testnumstr=$(printf '%s%%%%%03d-%05d' "$1" $2 $3) + echo "$testnumstr" +} + +# +# Print the test data to the log file +# +# Arguments: +# 1 string containing generated test number +# 2 string containing line of test data +# +function print_data() { + if [[ -n $verbose ]]; then + printf "Test %s data: %s\n" "$1" "$2" >&$logfd + fi +} + +# +# Print the test result to the log file +# +# Arguments: +# 1 string containing generated test number +# 2 string containing the test result (INFO, SUCCESS, ERROR, or FAILURE) +# 3 string containing addition details +# +function print_result() { + if [[ $2 == "INFO" && -z $verbose ]]; then + return + fi + if [[ $3 == "" ]]; then + printf "Test %s result: %s\n" "$1" "$2" >&$logfd + else + printf "Test %s result: %s %s\n" "$1" "$2" "$3" >&$logfd + fi +} + +# +# Print the valgrind header to the log file +# +# Arguments: +# 1 string containing generated test number +# +function print_valgrind() { + if [[ -n $verbose ]]; then + printf "Test %s valgrind output\n" "$1" >&$logfd + fi +} + +# +# Get the low or high range value from a range specification +# +# Arguments: +# 1 value specifying range value to retrieve: low (1) or high (2) +# 2 string containing dash-separated range or a single value +# +function get_range() { + if [[ $2 =~ ^[0-9a-fA-Fx]+-[0-9a-fA-Fx]+$ ]]; then + # if there's a dash, get the low or high range value + range_val=$(echo "$2" | cut -d'-' -f "$1") + else + # otherwise there should just be a single value + range_val="$2" + fi + echo "$range_val" +} + +# +# Run the specified test command (with valgrind if requested) +# +# Arguments: +# 1 string containing generated test number +# 2 string containing command name +# 3 string containing command options +# 4 number for the stdout fd +# 5 number for the stderr fd +# +function run_test_command() { + local cmd + + if [[ $mode == "python" ]]; then + cmd="PYTHONPATH=$PYTHONPATH" + cmd="$cmd:$(cd $(pwd)/../src/python/build/lib.*; pwd)" + cmd="$cmd /usr/bin/env python $2.py $3" + else + cmd="$2 $3" + fi + + # setup the stdout/stderr redirects + local stdout=$4 + local stderr=$5 + [[ -z $stdout ]] && stdout=$logfd + [[ -z $stderr ]] && stderr=$logfd + + # run the command + eval "$cmd" 1>&$stdout 2>&$stderr + + # return the command's return code + return $? +} + +# +# Generate pseudo-random string of alphanumeric characters +# +# The generated string will be no larger than the corresponding +# architecture's register size. +# +function generate_random_data() { + local rcount + local rdata + if [[ $arch == "x86_64" ]]; then + rcount=$[ ($RANDOM % 16) + 1 ] + else + rcount=$[ ($RANDOM % 8) + 1 ] + fi + rdata=$(echo $($tmpfile + run_test_command "$testnumstr" "./$testname" "-b" 4 "" + rc=$? + exec 4>&- + if [[ $rc -ne 0 ]]; then + print_result $testnumstr "ERROR" "$testname rc=$rc" + stats_error=$(($stats_error+1)) + return + fi + + # simulate the fuzzed syscall data against the BPF filter, we + # don't verify the resulting action since we're just testing for + # stability + allow=$($GLBL_SYS_SIM -f $tmpfile -s $sys \ + ${arg[0]} ${arg[1]} ${arg[2]} ${arg[3]} ${arg[4]} \ + ${arg[5]}) + rc=$? + if [[ $rc -ne 0 ]]; then + print_result $testnumstr "ERROR" "bpf_sim rc=$rc" + stats_error=$(($stats_error+1)) + else + print_result $testnumstr "SUCCESS" "" + stats_success=$(($stats_success+1)) + fi + stats_all=$(($stats_all+1)) + done +} + +# +# Run the specified "bpf-sim" test +# +# Tests that belong to the "bpf-sim" test type generate a BPF filter and then +# run a simulated system call test to validate the filter. Tests that belong to +# this test type provide the following data on a single line in the input batch +# file: +# +# Testname - The executable test name (e.g. 01-allow, 02-basic, etc.) +# Arch - The architecture that the test should be run on (all, x86, x86_64) +# Syscall - The syscall to simulate against the generated filter +# Arg0-5 - The syscall arguments to simulate against the generated filter +# Result - The expected simulation result (ALLOW, KILL, etc.) +# +# If a range of syscall or argument values are specified (e.g. 1-9), a test is +# generated for every combination of range values. Otherwise, the individual +# test is run. +# +# Arguments: +# 1 string containing the batch name +# 2 value of test number from batch file +# 3 string containing line of test data from batch file +# +function run_test_bpf_sim() { + local rc + local LOW=1 + local HIGH=2 + local -a arg_empty=(false false false false false false) + + # begin splitting the test data from the line into individual variables + local line=($3) + local testname=${line[0]} + local testarch=${line[1]} + local low_syscall #line[2] + local high_syscall #line[2] + local -a low_arg #line[3-8] + local -a high_arg #line[3-8] + local result=${line[9]} + + if [[ "${testarch:0:1}" == "+" ]]; then + # run the tests on the specified architecture(s) + simarch_list="${testarch:1}" + if [[ "$simarch_list" == "all" ]]; then + simarch_list="$GLBL_ARCH_SUPPORT" + fi + elif [[ "$testarch" != "all" ]] && [[ "$testarch" != "$arch" ]]; then + # only run tests that match the current architecture + print_result $(generate_test_num "$1" $2 1) "INFO" \ + "Test skipped due to test/system architecture difference" + stats_skipped=$(($stats_skipped+1)) + return + else + # run the tests on the native architecture + simarch_list="$arch" + fi + + # get low and high range arg values + line_i=3 + for arg_i in {0..5}; do + low_arg[$arg_i]=$(get_range $LOW "${line[$line_i]}") + high_arg[$arg_i]=$(get_range $HIGH "${line[$line_i]}") + + # fix up empty arg values so the nested loops work + if [[ ${low_arg[$arg_i]} == "N" ]]; then + arg_empty[$arg_i]=true + low_arg[$arg_i]=0 + high_arg[$arg_i]=0 + fi + + line_i=$(($line_i+1)) + done + + # loop through the selected architectures + for simarch in $simarch_list; do + # print architecture header if necessary + if [[ $simarch != $simarch_list ]]; then + echo " test arch: $simarch" >&$logfd + fi + + # reset the subtest number + local subtestnum=1 + + # get low and high syscall values and convert them to numbers + low_syscall=$(get_range $LOW "${line[2]}") + if [[ ! $low_syscall =~ ^[0-9]+$ ]]; then + low_syscall=$($GLBL_SYS_RESOLVER -a $simarch -t \ + $low_syscall) + if [[ $? -ne 0 ]]; then + print_result $(generate_test_num "$1" $2 1) \ + "ERROR" "sys_resolver rc=$?" + stats_error=$(($stats_error+1)) + return + fi + fi + high_syscall=$(get_range $HIGH "${line[2]}") + if [[ ! $high_syscall =~ ^[0-9]+$ ]]; then + high_syscall=$($GLBL_SYS_RESOLVER -a $simarch -t \ + $high_syscall) + if [[ $? -ne 0 ]]; then + print_result $(generate_test_num "$1" $2 1) \ + "ERROR" "sys_resolver rc=$?" + stats_error=$(($stats_error+1)) + return + fi + fi + + # if ranges exist, the following will loop through all syscall + # and arg ranges and generate/run every combination of requested + # tests; if no ranges were specifed, then the single test is + # run + for sys in $(seq -f "%1.0f" $low_syscall $high_syscall); do + for arg0 in $(seq -f "%1.0f" ${low_arg[0]} ${high_arg[0]}); do + for arg1 in $(seq -f "%1.0f" ${low_arg[1]} ${high_arg[1]}); do + for arg2 in $(seq -f "%1.0f" ${low_arg[2]} ${high_arg[2]}); do + for arg3 in $(seq -f "%1.0f" ${low_arg[3]} ${high_arg[3]}); do + for arg4 in $(seq -f "%1.0f" ${low_arg[4]} ${high_arg[4]}); do + for arg5 in $(seq -f "%1.0f" ${low_arg[5]} ${high_arg[5]}); do + local -a arg=($arg0 $arg1 $arg2 $arg3 $arg4 $arg5) + + # Get the generated sub-test num string + local testnumstr=$(generate_test_num "$1" $2 \ + $subtestnum) + + # format any empty args to print to log file + for i in {0..5}; do + if ${arg_empty[$i]}; then + arg[$i]="N" + fi + done + + # set up log file test data line for this + # individual test, spacing is added to align + # the output in the correct columns + local -a COL_WIDTH=(26 08 14 11 17 21 09 06 06) + local testdata=$(printf "%-${COL_WIDTH[0]}s" $testname) + testdata+=$(printf "%-${COL_WIDTH[1]}s" $simarch) + testdata+=$(printf "%-${COL_WIDTH[2]}s" $sys) + testdata+=$(printf "%-${COL_WIDTH[3]}s" ${arg[0]}) + testdata+=$(printf "%-${COL_WIDTH[4]}s" ${arg[1]}) + testdata+=$(printf "%-${COL_WIDTH[5]}s" ${arg[2]}) + testdata+=$(printf "%-${COL_WIDTH[6]}s" ${arg[3]}) + testdata+=$(printf "%-${COL_WIDTH[7]}s" ${arg[4]}) + testdata+=$(printf "%-${COL_WIDTH[8]}s" ${arg[5]}) + testdata+=$(printf "%-${COL_WIDTH[9]}s" $result) + + # print out the test data to the log file + print_data "$testnumstr" "$testdata" + + # set up the syscall arguments to be passed to bpf_sim + for i in {0..5}; do + if ${arg_empty[$i]}; then + arg[$i]="" + else + arg[$i]=" -$i ${arg[$i]} " + fi + done + + # run the test command and put the BPF in a temp file + exec 4>$tmpfile + run_test_command "$testnumstr" "./$testname" "-b" 4 "" + rc=$? + exec 4>&- + if [[ $rc -ne 0 ]]; then + print_result $testnumstr \ + "ERROR" "$testname rc=$rc" + stats_error=$(($stats_error+1)) + return + fi + + # simulate the specifed syscall against the BPF filter + # and verify the results + action=$($GLBL_SYS_SIM -a $simarch -f $tmpfile \ + -s $sys ${arg[0]} ${arg[1]} ${arg[2]} \ + ${arg[3]} ${arg[4]} ${arg[5]}) + rc=$? + if [[ $rc -ne 0 ]]; then + print_result $testnumstr \ + "ERROR" "bpf_sim rc=$rc" + stats_error=$(($stats_error+1)) + elif [[ "$action" != "$result" ]]; then + print_result $testnumstr "FAILURE" \ + "bpf_sim resulted in $action" + stats_failure=$(($stats_failure+1)) + else + print_result $testnumstr "SUCCESS" "" + stats_success=$(($stats_success+1)) + fi + stats_all=$(($stats_all+1)) + + subtestnum=$(($subtestnum+1)) + done # syscall + done # arg0 + done # arg1 + done # arg2 + done # arg3 + done # arg4 + done # arg5 + done # architecture +} + +# +# Run the specified "basic" test +# +# Tests that belong to the "basic" test type will simply have the command +# specified in the input batch file. The command must return zero for success +# and non-zero for failure. +# +# Arguments: +# 1 value of test number from batch file +# 2 string containing line of test data from batch file +# +function run_test_basic() { + local rc + + # print out the input test data to the log file + print_data "$1" "$2" + + # run the command + run_test_command "$1" "./$2" "" "" "" + rc=$? + if [[ $rc -ne 0 ]]; then + print_result $1 "FAILURE" "$2 rc=$rc" + stats_failure=$(($stats_failure+1)) + else + print_result $1 "SUCCESS" "" + stats_success=$(($stats_success+1)) + fi + stats_all=$(($stats_all+1)) +} + +# +# Run the specified "bpf-valgrind" test +# +# Tests that belong to the "bpf-valgrind" test type generate a BPF filter +# while running under valgrind to detect any memory errors. +# +# Arguments: +# 1 value of test number from batch file +# 2 string containing line of test data from batch file +# +function run_test_bpf_valgrind() { + local rc + local testcmd + + # we only support the native/c test mode here + if [[ $mode != "c" ]]; then + stats_skipped=$(($stats_skipped+1)) + return + fi + + # print out the input test data to the log file + print_data "$1" "$2" + + # build the command + testcmd="$2" + testvalgrind="valgrind \ + --tool=memcheck \ + --error-exitcode=1 \ + --leak-check=full \ + --read-var-info=yes \ + --track-origins=yes" + if [[ -n $logfile ]]; then + testvalgrind+=" --log-fd=$logfd" + fi + if [[ -z $verbose ]]; then + testvalgrind+=" --quiet --log-fd=4" + fi + + # run the command + exec 4>/dev/null + print_valgrind "$1" + run_test_command "$1" "$testvalgrind --" "./$testcmd -b" 4 2 + rc=$? + exec 4>&- + if [[ $rc -ne 0 ]]; then + print_result $1 "FAILURE" "$2 rc=$rc" + stats_failure=$(($stats_failure+1)) + else + print_result $1 "SUCCESS" "" + stats_success=$(($stats_success+1)) + fi + stats_all=$(($stats_all+1)) +} + +# +# Run the specified "live" test +# +# Tests that belong to the "live" test type will attempt to run a live test +# of the libseccomp library on the host system; for obvious reasons the host +# system must support seccomp mode 2 for this to work correctly. +# +# Arguments: +# 1 value of test number from batch file +# 2 string containing line of test data from batch file +# +function run_test_live() { + local rc + local line=($2) + + # parse the test line + line_cmd=${line[0]} + line_act=${line[1]} + line_test="$line_cmd $line_act" + + # print out the input test data to the log file + print_data "$1" "$2" + + # run the command + exec 4>/dev/null + run_test_command "$1" "./$line_cmd" "$line_act" "" 4 + rc=$? + exec 4>&- + + # return value codes for this test type: + # 159: KILL + # 160: ALLOW + # 161: TRAP + # 162: TRACE (currently unsupported) + # 163: ERRNO + if [[ $line_act == "KILL" && $rc -eq 159 ]]; then + print_result $1 "SUCCESS" "" + stats_success=$(($stats_success+1)) + elif [[ $line_act == "ALLOW" && $rc -eq 160 ]]; then + print_result $1 "SUCCESS" "" + stats_success=$(($stats_success+1)) + elif [[ $line_act == "TRAP" && $rc -eq 161 ]]; then + print_result $1 "SUCCESS" "" + stats_success=$(($stats_success+1)) + elif [[ $line_act == "TRACE" ]]; then + print_result $1 "ERROR" "unsupported action \"$line_act\"" + stats_error=$(($stats_error+1)) + elif [[ $line_act == "ERRNO" && $rc -eq 163 ]]; then + print_result $1 "SUCCESS" "" + stats_success=$(($stats_success+1)) + else + print_result $1 "FAILURE" "$line_test rc=$rc" + stats_failure=$(($stats_failure+1)) + fi + stats_all=$(($stats_all+1)) +} + +# +# Run a single test from the specified batch +# +# Arguments: +# 1 string containing the batch name +# 2 value of test number from batch file +# 3 string containing line of test data from batch file +# 4 string containing test type that this test belongs to +# +function run_test() { + # generate the test number string for the line of batch test data + local testnumstr=$(generate_test_num "$1" $2 1) + + # ensure we only run tests which match the specified type + [[ -n $type && "$4" != "$type" ]] && return + + # execute the function corresponding to the test type + if [[ "$4" == "basic" ]]; then + run_test_basic "$testnumstr" "$3" + elif [[ "$4" == "bpf-sim" ]]; then + run_test_bpf_sim "$1" $2 "$3" + elif [[ "$4" == "bpf-sim-fuzz" ]]; then + run_test_bpf_sim_fuzz "$1" $2 "$3" + elif [[ "$4" == "bpf-valgrind" ]]; then + # only run this test if valgrind is installed + if check_deps valgrind; then + run_test_bpf_valgrind "$testnumstr" "$3" + else + stats_skipped=$(($stats_skipped+1)) + fi + elif [[ "$4" == "live" ]]; then + # only run this test if explicitly requested + if [[ -n $type ]]; then + run_test_live "$testnumstr" "$3" + else + stats_skipped=$(($stats_skipped+1)) + fi + else + print_result $testnumstr "ERROR" "test type $4 not supported" + stats_error=$(($stats_error+1)) + fi +} + +# +# Run the requested tests +# +function run_tests() { + # loop through all test files + for file in *.tests; do + local testnum=1 + local batch_requested=false + local batch_name="" + + # extract the batch name from the file name + batch_name=$(basename $file .tests) + + # check if this batch was requested + if [[ ${batch_list[@]} ]]; then + for b in ${batch_list[@]}; do + if [[ $b == $batch_name ]]; then + batch_requested=true + break + fi + done + if ! $batch_requested; then + continue + fi + fi + + # print a test batch header + echo " batch name: $batch_name" >&$logfd + + # loop through each line and run the requested tests + while read line; do + # strip whitespace, comments, and blank lines + line=$(echo "$line" | \ + sed -e 's/^[\t ]*//;s/[\t ]*$//;' | \ + sed -e '/^[#].*$/d;/^$/d') + if [[ -z $line ]]; then + continue + fi + + if [[ $line =~ ^"test type": ]]; then + test_type=$(echo "$line" | \ + sed -e 's/^test type: //;') + # print a test mode and type header + echo " test mode: $mode" >&$logfd + echo " test type: $test_type" >&$logfd + continue + fi + + if [[ ${single_list[@]} ]]; then + for i in ${single_list[@]}; do + if [ $i -eq $testnum ]; then + # we're running a single test + run_test "$batch_name" \ + $testnum "$line" \ + "$test_type" + fi + done + else + # we're running a test from a batch + run_test "$batch_name" \ + $testnum "$line" "$test_type" + fi + testnum=$(($testnum+1)) + done < "$file" + done +} + +#### +# main + +# verify general script dependencies +verify_deps head +verify_deps sed +verify_deps seq +verify_deps tr + +# global variables +declare -a batch_list +declare -a single_list +arch= +batch_count=0 +logfile= +logfd= +mode_list="" +runall= +singlecount=0 +tmpfile="" +tmpdir="" +type= +verbose= +stats_all=0 +stats_skipped=0 +stats_success=0 +stats_failure=0 +stats_error=0 + +while getopts "ab:gl:m:s:t:T:vh" opt; do + case $opt in + a) + runall=1 + ;; + b) + batch_list[batch_count]="$OPTARG" + batch_count=$(($batch_count+1)) + ;; + l) + logfile="$OPTARG" + ;; + m) + case $OPTARG in + c) + mode_list="$mode_list c" + ;; + python) + verify_deps python + mode_list="$mode_list python" + ;; + *) + usage + exit 1 + esac + ;; + s) + single_list[single_count]=$OPTARG + single_count=$(($single_count+1)) + ;; + t) + tmpdir="$OPTARG" + ;; + T) + type="$OPTARG" + ;; + v) + verbose=1 + ;; + h|*) + usage + exit 1 + ;; + esac +done + +# default to running the C tests +if [[ -z $mode_list ]]; then + mode_list="c" +fi + +# default to all tests if batch or single tests not requested +if [[ -z $batch_list ]] && [[ -z $single_list ]]; then + runall=1 +fi + +# drop any requested batch and single tests if all tests were requested +if [[ -n $runall ]]; then + batch_list=() + single_list=() +fi + +# open log file for append (default to stdout) +if [[ -n $logfile ]]; then + logfd=3 + exec 3>>"$logfile" +else + logfd=1 +fi + +# open temporary file +if [[ -n $tmpdir ]]; then + tmpfile=$(mktemp -t regression_XXXXXX --tmpdir=$tmpdir) +else + tmpfile=$(mktemp -t regression_XXXXXX) +fi + +# determine the current system's architecture +arch=$($GLBL_SYS_ARCH) + +# display the test output and run the requested tests +echo "=============== $(date) ===============" >&$logfd +echo "Regression Test Report (\"regression $*\")" >&$logfd +for mode in $mode_list; do + run_tests +done +echo "Regression Test Summary" >&$logfd +echo " tests run: $stats_all" >&$logfd +echo " tests skipped: $stats_skipped" >&$logfd +echo " tests passed: $stats_success" >&$logfd +echo " tests failed: $stats_failure" >&$logfd +echo " tests errored: $stats_error" >&$logfd +echo "============================================================" >&$logfd + +# cleanup and exit +rm -f $tmpfile +rc=0 +[[ $stats_failure -gt 0 ]] && rc=$(($rc + 2)) +[[ $stats_error -gt 0 ]] && rc=$(($rc + 4)) + +exit $rc diff --git a/tests/testdiff b/tests/testdiff new file mode 100755 index 0000000..a6ddbac --- /dev/null +++ b/tests/testdiff @@ -0,0 +1,126 @@ +#!/bin/bash + +# +# libseccomp test diff generator +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +#### +# functions + +# +# Print out script usage details +# +function usage() { +cat << EOF +usage: regression [-h] LABEL_1 LABEL_2 + +libseccomp test diff generator script +optional arguments: + -h show this help message and exit +EOF +} + +# +# Print the test header +# +# Arguments: +# 1 string containing generated test number +# +function print_test() { + printf "Test %s comparison:\n" "$1" +} + +# +# Compare the tests +# +# Arguments: +# 1 string containing first test label +# 2 string containing second test label +# +function diff_tests() { + local batch_name + local label_a + local label_b + local file_a + local file_b + + if [[ -n $1 ]]; then + label_a=".$1" + else + label_a="" + fi + + if [[ -n $2 ]]; then + label_b=".$2" + else + label_b="" + fi + + for file in *-sim-*.tests; do + # extract the batch name from the file name + batch_name=$(basename $file .tests) + + print_test "$batch_name" + + file_a="${batch_name}${label_a}" + file_b="${batch_name}${label_b}" + + if [[ -r "$file_a.pfc" && -r "$file_b.pfc" ]]; then + diff -pu "$file_a.pfc" "$file_b.pfc" + fi + + if [[ -r "$file_a.bpf" && -r "$file_b.bpf" ]]; then + diff -pu "$file_a.bpf" "$file_b.bpf" + fi + + if [[ -r "$file_a.bpfd" && -r "$file_b.bpfd" ]]; then + diff -pu "$file_a.bpfd" "$file_b.bpfd" + fi + done + + return +} + +#### +# main + +opt_label= +opt_disasm=0 + +while getopts "h" opt; do + case $opt in + h|*) + usage + exit 1 + ;; + esac +done + +stats_all=0 +stats_failure=0 + +# display the test output and run the requested tests +echo "=============== $(date) ===============" +echo "Comparing Test Output (\"testdiff $*\")" +diff_tests "$1" "$2" +echo "============================================================" + +# exit +exit 0 diff --git a/tests/testgen b/tests/testgen new file mode 100755 index 0000000..0da599d --- /dev/null +++ b/tests/testgen @@ -0,0 +1,206 @@ +#!/bin/bash + +# +# libseccomp test output generator +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +#### +# functions + +# +# Dependency verification +# +# Arguments: +# 1 Dependency to check for +# +function verify_deps() { + [[ -z "$1" ]] && return + if ! which "$1" >& /dev/null; then + echo "error: install \"$1\" and include it in your \$PATH" + exit 1 + fi +} + +# +# Print out script usage details +# +function usage() { +cat << EOF +usage: regression [-h] [-d] [-l LABEL] + +libseccomp test output generator script +optional arguments: + -h show this help message and exit + -b generate BPF output + -d generate disassembled BPF output + -p generate PFC output + -v perform valgrind checks + -l [LABEL] specifies label for the test output +EOF +} + +# +# Print the test result +# +# Arguments: +# 1 string containing generated test number +# 2 string containing the test result +# +function print_result() { + printf "Test %s result: %s\n" "$1" "$2" +} + +# +# Run the tests +# +# Arguments: +# 1 string containing output label +# +function run_tests() { + local batch_name + local label + local rc + + if [[ -n $1 ]]; then + label=".$1" + else + label="" + fi + + for file in *-sim-*.tests; do + # extract the batch name from the file name + batch_name=$(basename $file .tests) + + if [[ -x "$batch_name" ]]; then + if [[ $opt_pfc -eq 1 ]]; then + ./$batch_name > ${batch_name}${label}.pfc + rc=$? + stats_all=$(($stats_all + 1)) + if [[ $rc -eq 0 ]]; then + print_result "$batch_name [pfc]" "SUCCESS" + else + stats_failure=$(($stats_failure + 1)) + print_result "$batch_name [pfc]" "FAILURE" + fi + fi + + if [[ $opt_bpf -eq 1 ]]; then + ./$batch_name -b > ${batch_name}${label}.bpf + rc=$? + stats_all=$(($stats_all + 1)) + if [[ $rc -eq 0 ]]; then + print_result "$batch_name [bpf]" "SUCCESS" + else + stats_failure=$(($stats_failure + 1)) + print_result "$batch_name [bpf]" "FAILURE" + fi + fi + + if [[ $opt_disasm -eq 1 ]]; then + ./$batch_name -b | \ + ../tools/scmp_bpf_disasm > ${batch_name}${label}.bpfd + rc=$? + stats_all=$(($stats_all + 1)) + if [[ $rc -eq 0 ]]; then + print_result "$batch_name [bpfd]" "SUCCESS" + else + stats_failure=$(($stats_failure + 1)) + print_result "$batch_name [bpfd]" "FAILURE" + fi + fi + + if [[ $opt_valgrind -eq 1 ]]; then + valgrind --tool=memcheck \ + --quiet --error-exitcode=1 \ + --leak-check=full \ + --read-var-info=yes \ + --track-origins=yes \ + -- ./$batch_name -b > /dev/null + rc=$? + stats_all=$(($stats_all + 1)) + if [[ $rc -eq 0 ]]; then + print_result "$batch_name [valgrind]" "SUCCESS" + else + stats_failure=$(($stats_failure + 1)) + print_result "$batch_name [valgrind]" "FAILURE" + fi + fi + else + stats_failure=$(($stats_failure + 1)) + print_result "$batch_name" "FAILURE" + fi + done + + return +} + +#### +# main + +opt_label= +opt_bpf=0 +opt_disasm=0 +opt_pfc=0 +opt_valgrind=0 + +while getopts "bphdl:v" opt; do + case $opt in + b) + opt_bpf=1 + ;; + d) + opt_disasm=1 + ;; + l) + opt_label="$OPTARG" + ;; + p) + opt_pfc=1 + ;; + v) + opt_valgrind=1 + ;; + h|*) + usage + exit 1 + ;; + esac +done + +# verify valgrind +[[ $opt_valgrind -eq 1 ]] && verify_deps valgrind + +stats_all=0 +stats_failure=0 + +# display the test output and run the requested tests +echo "=============== $(date) ===============" +echo "Collecting Test Output (\"testgen $*\")" +run_tests "$opt_label" +echo "Test Summary" +echo " tests run: $stats_all" +echo " tests failed: $stats_failure" +echo "============================================================" + +# cleanup and exit +rc=0 +[[ $stats_failure -gt 0 ]] && rc=$(($rc + 2)) + +exit $rc diff --git a/tests/util.c b/tests/util.c new file mode 100644 index 0000000..9c069d6 --- /dev/null +++ b/tests/util.c @@ -0,0 +1,209 @@ +/** + * Seccomp Library utility code for tests + * + * Copyright (c) 2012 Red Hat + * Author: Eric Paris + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "util.h" + +/** + * SIGSYS signal handler + * @param nr the signal number + * @param info siginfo_t pointer + * @param void_context handler context + * + * Simple signal handler for SIGSYS which exits with error code 161. + * + */ +static void _trap_handler(int signal, siginfo_t *info, void *ctx) +{ + _exit(161); +} + +/** + * Parse the arguments passed to main + * @param argc the argument count + * @param argv the argument pointer + * @param opts the options structure + * + * This function parses the arguments passed to the test from the command line. + * Returns zero on success and negative values on failure. + * + */ +int util_getopt(int argc, char *argv[], struct util_options *opts) +{ + int rc = 0; + + if (opts == NULL) + return -EFAULT; + + memset(opts, 0, sizeof(*opts)); + while (1) { + int c, option_index = 0; + const struct option long_options[] = { + {"bpf", no_argument, &(opts->bpf_flg), 1}, + {"pfc", no_argument, &(opts->bpf_flg), 0}, + {0, 0, 0, 0}, + }; + + c = getopt_long(argc, argv, "bp", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + break; + case 'b': + opts->bpf_flg = 1; + break; + case 'p': + opts->bpf_flg = 0; + break; + default: + rc = -EINVAL; + break; + } + } + + if (rc == -EINVAL || optind < argc) { + fprintf(stderr, "usage %s: [--bpf,-b] [--pfc,-p]\n", argv[0]); + rc = -EINVAL; + } + + return rc; +} + +/** + * Output the filter in either BPF or PFC + * @param opts the options structure + * @param ctx the filter context + * + * This function outputs the seccomp filter to stdout in either BPF or PFC + * format depending on the test paramaeters supplied by @opts. + * + */ +int util_filter_output(const struct util_options *opts, + const scmp_filter_ctx ctx) +{ + int rc; + + if (opts == NULL) + return -EFAULT; + + if (opts->bpf_flg) + rc = seccomp_export_bpf(ctx, STDOUT_FILENO); + else + rc = seccomp_export_pfc(ctx, STDOUT_FILENO); + + return rc; +} + +/** + * Install a TRAP action signal handler + * + * This function installs the TRAP action signal handler and is based on + * examples from Will Drewry and Kees Cook. Returns zero on success, negative + * values on failure. + * + */ +int util_trap_install(void) +{ + struct sigaction signal_handler; + sigset_t signal_mask; + + memset(&signal_handler, 0, sizeof(signal_handler)); + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGSYS); + + signal_handler.sa_sigaction = &_trap_handler; + signal_handler.sa_flags = SA_SIGINFO; + if (sigaction(SIGSYS, &signal_handler, NULL) < 0) + return -errno; + if (sigprocmask(SIG_UNBLOCK, &signal_mask, NULL)) + return -errno; + + return 0; +} + +/** + * Parse a filter action string into an action value + * @param action the action string + * + * Parse a seccomp action string into the associated integer value. Returns + * the correct value on success, -1 on failure. + * + */ +int util_action_parse(const char *action) +{ + if (action == NULL) + return -1; + + if (strcasecmp(action, "KILL") == 0) + return SCMP_ACT_KILL; + else if (strcasecmp(action, "TRAP") == 0) + return SCMP_ACT_TRAP; + else if (strcasecmp(action, "ERRNO") == 0) + return SCMP_ACT_ERRNO(163); + else if (strcasecmp(action, "TRACE") == 0) + return -1; /* not yet supported */ + else if (strcasecmp(action, "ALLOW") == 0) + return SCMP_ACT_ALLOW; + + return -1; +} + +/** + * Write a string to a file + * @param path the file path + * + * Open the specified file, write a string to the file, and close the file. + * Return zero on success, negative values on error. + * + */ +int util_file_write(const char *path) +{ + int fd; + const char buf[] = "testing"; + ssize_t buf_len = strlen(buf); + + fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) + return errno; + if (write(fd, buf, buf_len) < buf_len) { + int rc = errno; + close(fd); + return rc; + } + if (close(fd) < 0) + return errno; + + return 0; +} diff --git a/tests/util.h b/tests/util.h new file mode 100644 index 0000000..b3c5a29 --- /dev/null +++ b/tests/util.h @@ -0,0 +1,40 @@ +/** + * Seccomp Library utility code for tests + * + * Copyright IBM Corp. 2012 + * Author: Corey Bryant + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _UTIL_TEST_H +#define _UTIL_TEST_H + +struct util_options { + int bpf_flg; +}; + +int util_getopt(int argc, char *argv[], struct util_options *opts); + +int util_filter_output(const struct util_options *opts, + const scmp_filter_ctx ctx); + +int util_trap_install(void); + +int util_action_parse(const char *action); + +int util_file_write(const char *path); + +#endif diff --git a/tests/util.py b/tests/util.py new file mode 100644 index 0000000..20704f6 --- /dev/null +++ b/tests/util.py @@ -0,0 +1,109 @@ +# +# Seccomp Library utility code for tests +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +""" Python utility code for the libseccomp test suite """ + +import argparse +import os +import sys +import signal + +from seccomp import * + +def trap_handler(signum, frame): + """ SIGSYS signal handler, internal use only + """ + os._exit(161) + +def get_opt(): + """ Parse the arguments passed to main + + Description: + Parse the arguments passed to the test from the command line. Returns + a parsed argparse object. + """ + parser = argparse.ArgumentParser() + parser.add_argument("-b", "--bpf", action="store_true") + parser.add_argument("-p", "--pfc", action="store_true") + return parser.parse_args() + +def filter_output(args, ctx): + """ Output the filter in either BPF or PFC + + Arguments: + args - an argparse object from UtilGetOpt() + ctx - a seccomp SyscallFilter object + + Description: + Output the SyscallFilter to stdout in either BPF or PFC format depending + on the test's command line arguments. + """ + if (args.bpf): + ctx.export_bpf(sys.stdout) + else: + ctx.export_pfc(sys.stdout) + +def install_trap(): + """ Install a TRAP action signal handler + + Description: + Install the TRAP action signal handler. + """ + signal.signal(signal.SIGSYS, trap_handler) + +def parse_action(action): + """ Parse a filter action string into an action value + + Arguments: + action - the action string + + Description: + Parse a seccomp action string into the associated integer value. + """ + if action == "KILL": + return KILL + elif action == "TRAP": + return TRAP + elif action == "ERRNO": + return ERRNO(163) + elif action == "TRACE": + raise RuntimeError("the TRACE action is not currently supported") + elif action == "ALLOW": + return ALLOW + raise RuntimeError("invalid action string") + + +def write_file(path): + """ Write a string to a file + + Arguments: + path - the file path + + Description: + Open the specified file, write a string to the file, and close the file. + """ + fd = os.open(path, os.O_WRONLY|os.O_CREAT, 0600) + if not os.write(fd, "testing") == len("testing"): + raise IOError("failed to write the full test string in write_file()") + os.close(fd) + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..79c7d25 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,66 @@ +# +# Enhanced Seccomp Library Makefile +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +# +# macros +# + +include ../macros.mk + +# +# configuration +# + +include $(TOPDIR)/configure.mk +include $(TOPDIR)/install.mk + +LDFLAGS := ../src/libseccomp.a + +TOOLS = scmp_bpf_disasm \ + scmp_bpf_sim \ + scmp_sys_resolver \ + scmp_arch_detect + +TOOLS_INSTALL = scmp_sys_resolver + +DEPS = $(TOOLS:%=%.d) + +# +# targets +# + +.PHONY: install clean + +all: $(TOOLS) + +-include $(DEPS) + +$(DEPS): + $(MAKEDEP_EXEC) + +$(TOOLS): + $(COMPILE_EXEC) + +install: $(TOOLS_INSTALL) + $(INSTALL_BIN_MACRO) + +clean: + $(RM) $(DEPS) $(TOOLS) diff --git a/tools/bpf.h b/tools/bpf.h new file mode 100644 index 0000000..4fb4c4f --- /dev/null +++ b/tools/bpf.h @@ -0,0 +1,124 @@ +/** + * BPF Language Definitions + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef _BPF_H +#define _BPF_H + +#include +#include + +/* most of these structures and values are designed to match the Linux Kernel's + * BPF interface (see /usr/include/linux/{filter,seccomp}.h), but we define our + * own here so that we can function independent of the host OS */ + +/* XXX - need to verify these values */ +#define BPF_SCRATCH_SIZE 6 + +/** + * Syscall record data format used by seccomp + */ +#define BPF_SYS_ARG_MAX 6 +struct seccomp_data { + int32_t nr; + uint32_t arch; + uint64_t instruction_pointer; + uint64_t args[BPF_SYS_ARG_MAX]; +}; +#define BPF_SYSCALL_MAX (sizeof(struct seccomp_data)) + +/** + * BPF instruction format + */ +struct sock_filter { + uint16_t code; + uint8_t jt; + uint8_t jf; + uint32_t k; +} __attribute__ ((packed)); +typedef struct sock_filter bpf_instr_raw; + +/* seccomp return masks */ +#define SECCOMP_RET_ACTION 0x7fff0000U +#define SECCOMP_RET_DATA 0x0000ffffU + +/* seccomp action values */ +#define SECCOMP_RET_KILL 0x00000000U +#define SECCOMP_RET_TRAP 0x00030000U +#define SECCOMP_RET_ERRNO 0x00050000U +#define SECCOMP_RET_TRACE 0x7ff00000U +#define SECCOMP_RET_ALLOW 0x7fff0000U + +/* bpf command classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* BPF_LD and BPF_LDX */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +#define BPF_OP(code) ((code) & 0xf0) +/* BPF_ALU */ +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +/* BPF_JMP */ +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 + +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* BPF_RET (BPF_K and BPF_X also apply) */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* BPF_MISC */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +#endif diff --git a/tools/check-syntax b/tools/check-syntax new file mode 100755 index 0000000..f356a46 --- /dev/null +++ b/tools/check-syntax @@ -0,0 +1,116 @@ +#!/bin/bash + +# +# libseccomp code syntax checking tool +# +# Copyright (c) 2013 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +CHK_C_LIST="include/seccomp.h.in \ + src/*.c src/*.h \ + tests/*.c tests/*.h \ + tools/*.c tools/*.h" +CHK_C_EXCLUDE="" + +#### +# functions + +# +# Dependency verification +# +# Arguments: +# 1 Dependency to check for +# +function verify_deps() { + [[ -z "$1" ]] && return + if ! which "$1" >& /dev/null; then + echo "error: install \"$1\" and include it in your \$PATH" + exit 1 + fi +} + +# +# Print out script usage details +# +function usage() { +cat << EOF +usage: check-syntax [-h] + +libseccomp code syntax checking tool +optional arguments: + -h show this help message and exit +EOF +} + +# +# Check the formatting on a C source/header file +# +# Arguments: +# 1 File to check +# +function tool_c_style() { + [[ -z "$1" || ! -r "$1" ]] && return + + astyle --options=none --lineend=linux --mode=c \ + --style=linux \ + --indent=force-tab=8 \ + --indent-preprocessor \ + --indent-col1-comments \ + --min-conditional-indent=0 \ + --max-instatement-indent=80 \ + --pad-oper \ + --align-pointer=name \ + --align-reference=name \ + --max-code-length=80 \ + --break-after-logical < "$1" \ + | diff -pu --label="$1" "$1" --label="$1 [CORRECTED]" - +} + +# +# Perform all known syntax checks for the configured C sources/headers +# +function check_c() { + for i in $CHK_C_LIST; do + echo "$CHK_C_EXCLUDE" | grep -q "$i" && continue + echo "Differences for $i" + tool_c_style "$i" + done +} + +#### +# main + +verify_deps astyle + +while getopts "h" opt; do + case $opt in + h|*) + usage + exit 1 + ;; + esac +done + +# display the results +echo "=============== $(date) ===============" +echo "Code Syntax Check Results (\"check-syntax $*\")" +check_c +echo "============================================================" + +# exit +exit 0 diff --git a/tools/scmp_app_inspector b/tools/scmp_app_inspector new file mode 100755 index 0000000..37f880b --- /dev/null +++ b/tools/scmp_app_inspector @@ -0,0 +1,103 @@ +#!/bin/bash + +# +# Runtime syscall inspector +# +# Copyright (c) 2012 Red Hat +# Author: Paul Moore +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +#### +# functions + +function verify_deps() { + [[ -z "$1" ]] && return + if ! which "$1" >& /dev/null; then + echo "error: install \"$1\" and include it in your \$PATH" + exit 1 + fi +} + +#### +# main + +# verify script dependencies +verify_deps strace +verify_deps sed +verify_deps sort +verify_deps uniq + +# get the command line arguments +opt_freq=0 +opt_args=0 +opt_out="/proc/self/fd/1" +while getopts "afo:h" opt; do + case $opt in + a) + opt_args=1 + ;; + f) + opt_freq=1 + ;; + o) + opt_out="$OPTARG" + ;; + h|*) + echo "usage $0 [-f] [-a] [-o ] []" + exit 1 + esac +done +shift $(expr $OPTIND - 1) + +# generate a temporary output file +raw=$(mktemp -t strace-raw_XXXXXX) +out="$raw-out" + +# capture the strace output +strace -o $raw -- $* + +# filter the raw strace +if [[ $opt_args -eq 0 ]]; then + if [[ $opt_freq -eq 0 ]]; then + cat $raw | sed -e 's/(.*//' | sort -u > $out + else + cat $raw | sed -e 's/(.*//' | sort | uniq -c | sort -nr > $out + fi +else + if [[ $opt_freq -eq 0 ]]; then + cat $raw | sed -e 's/)[ \t]*=.*$/)/' \ + | sed -e 's/".*,/"...",/g;s/\/\*.*\*\//.../g' \ + | sed -e 's/0x[a-f0-9]\+/.../g' \ + | sort -u > $out + else + cat $raw | sed -e 's/)[ \t]*=.*$/)/' \ + | sed -e 's/".*,/"...",/g;s/\/\*.*\*\//.../g' \ + | sed -e 's/0x[a-f0-9]\+/.../g' \ + | sort | uniq -c | sort -nr > $out + fi +fi + +# display the output +echo "============================================================" > $opt_out +echo "Syscall Report (\"$*\")" >> $opt_out +[[ $opt_freq -eq 1 ]] && echo " freq syscall" >> $opt_out +echo "============================================================" >> $opt_out +cat $out >> $opt_out + +# cleanup and exit +rm -f $raw $out +exit 0 diff --git a/tools/scmp_arch_detect.c b/tools/scmp_arch_detect.c new file mode 100644 index 0000000..e90f92b --- /dev/null +++ b/tools/scmp_arch_detect.c @@ -0,0 +1,88 @@ +/** + * Architecture Detector + * + * Copyright (c) 2013 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include + +#include + +/** + * Print the usage information to stderr and exit + * @param program the name of the current program being invoked + * + * Print the usage information and exit with EINVAL. + * + */ +static void exit_usage(const char *program) +{ + fprintf(stderr, + "usage: %s [-h] [-t]\n", + program); + exit(EINVAL); +} + +/** + * main + */ +int main(int argc, char *argv[]) +{ + int opt; + int token = 0; + uint32_t arch; + + /* parse the command line */ + while ((opt = getopt(argc, argv, "ht")) > 0) { + switch (opt) { + case 't': + token = 1; + break; + case 'h': + default: + /* usage information */ + exit_usage(argv[0]); + } + } + + arch = seccomp_arch_native(); + if (token == 0) { + switch (arch) { + case SCMP_ARCH_X86: + printf("x86\n"); + break; + case SCMP_ARCH_X86_64: + printf("x86_64\n"); + break; + case SCMP_ARCH_X32: + printf("x32\n"); + break; + case SCMP_ARCH_ARM: + printf("arm\n"); + break; + default: + printf("unknown\n"); + } + } else + printf("%d\n", arch); + + return 0; +} diff --git a/tools/scmp_bpf_disasm.c b/tools/scmp_bpf_disasm.c new file mode 100644 index 0000000..8474eb1 --- /dev/null +++ b/tools/scmp_bpf_disasm.c @@ -0,0 +1,322 @@ +/** + * BPF Disassembler + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf.h" + +#define _OP_FMT "%-3s" + +/** + * Decode the BPF operand + * @param bpf the BPF instruction + * + * Decode the BPF operand and print it to stdout. + * + */ +static void bpf_decode_op(const bpf_instr_raw *bpf) +{ + switch (bpf->code) { + case BPF_LD+BPF_W+BPF_IMM: + case BPF_LD+BPF_W+BPF_ABS: + case BPF_LD+BPF_W+BPF_IND: + case BPF_LD+BPF_W+BPF_MEM: + case BPF_LD+BPF_W+BPF_LEN: + case BPF_LD+BPF_W+BPF_MSH: + printf(_OP_FMT, "ld"); + break; + case BPF_LD+BPF_H+BPF_IMM: + case BPF_LD+BPF_H+BPF_ABS: + case BPF_LD+BPF_H+BPF_IND: + case BPF_LD+BPF_H+BPF_MEM: + case BPF_LD+BPF_H+BPF_LEN: + case BPF_LD+BPF_H+BPF_MSH: + printf(_OP_FMT, "ldh"); + break; + case BPF_LD+BPF_B+BPF_IMM: + case BPF_LD+BPF_B+BPF_ABS: + case BPF_LD+BPF_B+BPF_IND: + case BPF_LD+BPF_B+BPF_MEM: + case BPF_LD+BPF_B+BPF_LEN: + case BPF_LD+BPF_B+BPF_MSH: + printf(_OP_FMT, "ldb"); + break; + case BPF_LDX+BPF_W+BPF_IMM: + case BPF_LDX+BPF_W+BPF_ABS: + case BPF_LDX+BPF_W+BPF_IND: + case BPF_LDX+BPF_W+BPF_MEM: + case BPF_LDX+BPF_W+BPF_LEN: + case BPF_LDX+BPF_W+BPF_MSH: + case BPF_LDX+BPF_H+BPF_IMM: + case BPF_LDX+BPF_H+BPF_ABS: + case BPF_LDX+BPF_H+BPF_IND: + case BPF_LDX+BPF_H+BPF_MEM: + case BPF_LDX+BPF_H+BPF_LEN: + case BPF_LDX+BPF_H+BPF_MSH: + case BPF_LDX+BPF_B+BPF_IMM: + case BPF_LDX+BPF_B+BPF_ABS: + case BPF_LDX+BPF_B+BPF_IND: + case BPF_LDX+BPF_B+BPF_MEM: + case BPF_LDX+BPF_B+BPF_LEN: + case BPF_LDX+BPF_B+BPF_MSH: + printf(_OP_FMT, "ldx"); + break; + case BPF_ST: + printf(_OP_FMT, "st"); + break; + case BPF_STX: + printf(_OP_FMT, "stx"); + break; + case BPF_ALU+BPF_ADD+BPF_K: + case BPF_ALU+BPF_ADD+BPF_X: + printf(_OP_FMT, "add"); + break; + case BPF_ALU+BPF_SUB+BPF_K: + case BPF_ALU+BPF_SUB+BPF_X: + printf(_OP_FMT, "sub"); + break; + case BPF_ALU+BPF_MUL+BPF_K: + case BPF_ALU+BPF_MUL+BPF_X: + printf(_OP_FMT, "mul"); + break; + case BPF_ALU+BPF_DIV+BPF_K: + case BPF_ALU+BPF_DIV+BPF_X: + printf(_OP_FMT, "div"); + break; + case BPF_ALU+BPF_OR+BPF_K: + case BPF_ALU+BPF_OR+BPF_X: + printf(_OP_FMT, "or"); + break; + case BPF_ALU+BPF_AND+BPF_K: + case BPF_ALU+BPF_AND+BPF_X: + printf(_OP_FMT, "and"); + break; + case BPF_ALU+BPF_LSH+BPF_K: + case BPF_ALU+BPF_LSH+BPF_X: + printf(_OP_FMT, "lsh"); + break; + case BPF_ALU+BPF_RSH+BPF_K: + case BPF_ALU+BPF_RSH+BPF_X: + printf(_OP_FMT, "rsh"); + break; + case BPF_ALU+BPF_NEG+BPF_K: + case BPF_ALU+BPF_NEG+BPF_X: + printf(_OP_FMT, "neg"); + break; + case BPF_JMP+BPF_JA+BPF_K: + case BPF_JMP+BPF_JA+BPF_X: + printf(_OP_FMT, "jmp"); + break; + case BPF_JMP+BPF_JEQ+BPF_K: + case BPF_JMP+BPF_JEQ+BPF_X: + printf(_OP_FMT, "jeq"); + break; + case BPF_JMP+BPF_JGT+BPF_K: + case BPF_JMP+BPF_JGT+BPF_X: + printf(_OP_FMT, "jgt"); + break; + case BPF_JMP+BPF_JGE+BPF_K: + case BPF_JMP+BPF_JGE+BPF_X: + printf(_OP_FMT, "jge"); + break; + case BPF_JMP+BPF_JSET+BPF_K: + case BPF_JMP+BPF_JSET+BPF_X: + printf(_OP_FMT, "jset"); + break; + case BPF_RET+BPF_K: + case BPF_RET+BPF_X: + case BPF_RET+BPF_A: + printf(_OP_FMT, "ret"); + break; + case BPF_MISC+BPF_TAX: + printf(_OP_FMT, "tax"); + break; + case BPF_MISC+BPF_TXA: + printf(_OP_FMT, "txa"); + break; + default: + printf(_OP_FMT, "???"); + } +} + +/** + * Decode the BPF arguments (JT, JF, and K) + * @param bpf the BPF instruction + * @param line the current line number + * + * Decode the BPF arguments (JT, JF, and K) and print the relevant information + * to stdout based on the operand. + * + */ +static void bpf_decode_args(const bpf_instr_raw *bpf, unsigned int line) +{ + switch (BPF_CLASS(bpf->code)) { + case BPF_LD: + case BPF_LDX: + switch (BPF_MODE(bpf->code)) { + case BPF_ABS: + printf("$data[%u]", bpf->k); + break; + case BPF_MEM: + printf("$temp[%u]", bpf->k); + break; + } + break; + case BPF_ST: + case BPF_STX: + printf("$temp[%u]", bpf->k); + break; + case BPF_ALU: + if (BPF_SRC(bpf->code) == BPF_K) { + switch (BPF_OP(bpf->code)) { + case BPF_OR: + case BPF_AND: + printf("0x%.8x", bpf->k); + break; + default: + printf("%u", bpf->k); + } + } else + printf("%u", bpf->k); + break; + case BPF_JMP: + if (BPF_OP(bpf->code) == BPF_JA) { + printf("%.4u", (line + 1) + bpf->k); + } else { + printf("%-4u true:%.4u false:%.4u", + bpf->k, + (line + 1) + bpf->jt, + (line + 1) + bpf->jf); + } + break; + case BPF_RET: + if (BPF_RVAL(bpf->code) == BPF_A) { + /* XXX - accumulator? */ + printf("$acc"); + } else if (BPF_SRC(bpf->code) == BPF_K) { + uint32_t act = bpf->k & SECCOMP_RET_ACTION; + uint32_t data = bpf->k & SECCOMP_RET_DATA; + + switch (act) { + case SECCOMP_RET_KILL: + printf("KILL"); + break; + case SECCOMP_RET_TRAP: + printf("TRAP"); + break; + case SECCOMP_RET_ERRNO: + printf("ERRNO(%u)", data); + break; + case SECCOMP_RET_TRACE: + printf("TRACE(%u)", data); + break; + case SECCOMP_RET_ALLOW: + printf("ALLOW"); + break; + default: + printf("0x%.8x", bpf->k); + } + } else if (BPF_SRC(bpf->code) == BPF_X) { + /* XXX - any idea? */ + printf("???"); + } + break; + case BPF_MISC: + break; + default: + printf("???"); + } +} + +/** + * Perform a simple decoding of the BPF program + * @param file the BPF program + * + * Read the BPF program and display the instructions. Returns zero on success, + * negative values on failure. + * + */ +static int bpf_decode(FILE *file) +{ + unsigned int line = 0; + size_t len; + bpf_instr_raw bpf; + + /* header */ + printf(" line OP JT JF K\n"); + printf("=================================\n"); + + while ((len = fread(&bpf, sizeof(bpf), 1, file))) { + printf(" %.4u: 0x%.2x 0x%.2x 0x%.2x 0x%.8x", + line, bpf.code, bpf.jt, bpf.jf, bpf.k); + + printf(" "); + bpf_decode_op(&bpf); + printf(" "); + bpf_decode_args(&bpf, line); + printf("\n"); + + line++; + } + + if (ferror(file)) + return errno; + return 0; +} + +/** + * main + */ +int main(int argc, char *argv[]) +{ + int rc; + FILE *file; + + if (argc > 2) { + fprintf(stderr, "usage: %s []\n", argv[0]); + return EINVAL; + } + + if (argc == 2) { + file = fopen(argv[1], "r"); + if (file == NULL) { + fprintf(stderr, "error: unable to open \"%s\" (%s)\n", + argv[1], strerror(errno)); + return errno; + } + } else + file = stdin; + + rc = bpf_decode(file); + fclose(file); + + return rc; +} + diff --git a/tools/scmp_bpf_sim.c b/tools/scmp_bpf_sim.c new file mode 100644 index 0000000..1b46cc9 --- /dev/null +++ b/tools/scmp_bpf_sim.c @@ -0,0 +1,310 @@ +/** + * BPF Simulator + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf.h" + +#define BPF_PRG_MAX_LEN 4096 + +/** + * BPF simulator machine state + */ +struct sim_state { + uint32_t acc; + uint32_t temp[BPF_SCRATCH_SIZE]; +}; + +struct bpf_program { + size_t i_cnt; + bpf_instr_raw *i; +}; + +static unsigned int opt_verbose = 0; + +/** + * Print the usage information to stderr and exit + * @param program the name of the current program being invoked + * + * Print the usage information and exit with EINVAL. + * + */ +static void exit_usage(const char *program) +{ + fprintf(stderr, + "usage: %s -f [-v]" + " -a -s [-0 ] ... [-5 ]\n", + program); + exit(EINVAL); +} + +/** + * Handle a simulator fault + * @param rc the error or return code + * + * Print a "FAULT" to stderr to indicate a simulator fault, and an errno value + * if the simulator is running in verbose mode, then exit with EFAULT. + * + */ +static void exit_fault(unsigned int rc) +{ + if (opt_verbose) + fprintf(stderr, "FAULT: errno = %d\n", rc); + else + fprintf(stderr, "FAULT\n"); + exit(EFAULT); +} + +/** + * Handle a BPF program error + * @param rc the error or return code + * @param line the line number + * + * Print an "ERROR" to stderr to indicate a program error, and an errno value + * if the simulator is running in verbose mode, then exit with ENOEXEC. + * + */ +static void exit_error(unsigned int rc, unsigned int line) +{ + if (opt_verbose) + fprintf(stderr, "ERROR: errno = %d, line = %d\n", rc, line); + else + fprintf(stderr, "ERROR\n"); + exit(ENOEXEC); +} + +/** + * Handle a simulator return/action + * @param action the return value + * @param line the line number + * + * Display the action to stdout and exit with 0. + * + */ +static void end_action(uint32_t action, unsigned int line) +{ + uint32_t act = action & SECCOMP_RET_ACTION; + uint32_t data = action & SECCOMP_RET_DATA; + + switch (act) { + case SECCOMP_RET_KILL: + fprintf(stdout, "KILL\n"); + break; + case SECCOMP_RET_TRAP: + fprintf(stdout, "TRAP\n"); + break; + case SECCOMP_RET_ERRNO: + fprintf(stdout, "ERRNO(%u)\n", data); + break; + case SECCOMP_RET_TRACE: + fprintf(stdout, "TRACE(%u)\n", data); + break; + case SECCOMP_RET_ALLOW: + fprintf(stdout, "ALLOW\n"); + break; + default: + exit_error(EDOM, line); + } + + exit(0); +} + +/** + * Execute a BPF program + * @param prg the loaded BPF program + * @param sys_data the syscall record being tested + * + * Simulate the BPF program with the given syscall record. + * + */ +static void bpf_execute(const struct bpf_program *prg, + const struct seccomp_data *sys_data) +{ + unsigned int ip, ip_c; + struct sim_state state; + bpf_instr_raw *bpf; + unsigned char *sys_data_b = (unsigned char *)sys_data; + + /* initialize the machine state */ + ip_c = 0; + ip = 0; + memset(&state, 0, sizeof(state)); + + while (ip < prg->i_cnt) { + /* get the instruction and bump the ip */ + ip_c = ip; + bpf = &prg->i[ip++]; + + switch (bpf->code) { + case BPF_LD+BPF_W+BPF_ABS: + if (bpf->k < BPF_SYSCALL_MAX) + state.acc = *((uint32_t *)&sys_data_b[bpf->k]); + else + exit_error(ERANGE, ip_c); + break; + case BPF_ALU+BPF_OR+BPF_K: + state.acc |= bpf->k; + break; + case BPF_ALU+BPF_AND+BPF_K: + state.acc &= bpf->k; + break; + case BPF_JMP+BPF_JA: + ip += bpf->k; + break; + case BPF_JMP+BPF_JEQ+BPF_K: + if (state.acc == bpf->k) + ip += bpf->jt; + else + ip += bpf->jf; + break; + case BPF_JMP+BPF_JGT+BPF_K: + if (state.acc > bpf->k) + ip += bpf->jt; + else + ip += bpf->jf; + break; + case BPF_JMP+BPF_JGE+BPF_K: + if (state.acc >= bpf->k) + ip += bpf->jt; + else + ip += bpf->jf; + break; + case BPF_RET+BPF_K: + end_action(bpf->k, ip_c); + break; + default: + /* since we don't support the full bpf language just + * yet, this could be either a fault or an error, we'll + * treat it as a fault until we provide full support */ + exit_fault(EOPNOTSUPP); + } + } + + /* if we've reached here there is a problem with the program */ + exit_error(ERANGE, ip_c); +} + +/** + * main + */ +int main(int argc, char *argv[]) +{ + int opt; + char *opt_file = NULL; + FILE *file; + size_t file_read_len; + struct seccomp_data sys_data; + struct bpf_program bpf_prg; + + /* clear the syscall record */ + memset(&sys_data, 0, sizeof(sys_data)); + + /* parse the command line */ + while ((opt = getopt(argc, argv, "a:f:h:s:v0:1:2:3:4:5:")) > 0) { + switch (opt) { + case 'a': + if (strcmp(optarg, "x86") == 0) + sys_data.arch = AUDIT_ARCH_I386; + else if (strcmp(optarg, "x86_64") == 0) + sys_data.arch = AUDIT_ARCH_X86_64; + else if (strcmp(optarg, "x32") == 0) + sys_data.arch = AUDIT_ARCH_X86_64; + else if (strcmp(optarg, "arm") == 0) + sys_data.arch = AUDIT_ARCH_ARM; + else + exit_fault(EINVAL); + break; + case 'f': + opt_file = strdup(optarg); + if (opt_file == NULL) + exit_fault(ENOMEM); + break; + case 's': + sys_data.nr = strtol(optarg, NULL, 0); + break; + case 'v': + opt_verbose = 1; + break; + case '0': + sys_data.args[0] = strtoull(optarg, NULL, 0); + break; + case '1': + sys_data.args[1] = strtoull(optarg, NULL, 0); + break; + case '2': + sys_data.args[2] = strtoull(optarg, NULL, 0); + break; + case '3': + sys_data.args[3] = strtoull(optarg, NULL, 0); + break; + case '4': + sys_data.args[4] = strtoull(optarg, NULL, 0); + break; + case '5': + sys_data.args[5] = strtoull(optarg, NULL, 0); + break; + case 'h': + default: + /* usage information */ + exit_usage(argv[0]); + } + } + + /* allocate space for the bpf program */ + /* XXX - we should make this dynamic */ + bpf_prg.i_cnt = 0; + bpf_prg.i = calloc(BPF_PRG_MAX_LEN, sizeof(*bpf_prg.i)); + if (bpf_prg.i == NULL) + exit_fault(ENOMEM); + + /* load the bpf program */ + file = fopen(opt_file, "r"); + if (file == NULL) + exit_fault(errno); + do { + file_read_len = fread(&(bpf_prg.i[bpf_prg.i_cnt]), + sizeof(*bpf_prg.i), 1, file); + if (file_read_len == 1) + bpf_prg.i_cnt++; + + /* check the size */ + if (bpf_prg.i_cnt == BPF_PRG_MAX_LEN) + exit_fault(E2BIG); + } while (file_read_len > 0); + fclose(file); + + /* execute the bpf program */ + bpf_execute(&bpf_prg, &sys_data); + + /* we should never reach here */ + exit_fault(EFAULT); + return 0; +} diff --git a/tools/scmp_sys_resolver.c b/tools/scmp_sys_resolver.c new file mode 100644 index 0000000..e86b400 --- /dev/null +++ b/tools/scmp_sys_resolver.c @@ -0,0 +1,104 @@ +/** + * Syscall resolver + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "../src/arch.h" +#include "../src/arch-x86.h" +#include "../src/arch-x86_64.h" +#include "../src/arch-x32.h" +#include "../src/arch-arm.h" + +/** + * Print the usage information to stderr and exit + * @param program the name of the current program being invoked + * + * Print the usage information and exit with EINVAL. + * + */ +static void exit_usage(const char *program) +{ + fprintf(stderr, + "usage: %s [-h] [-a ] [-t] |\n", + program); + exit(EINVAL); +} + +/** + * main + */ +int main(int argc, char *argv[]) +{ + int opt; + int translate = 0; + const struct arch_def *arch = arch_def_native; + int sys_num; + const char *sys_name; + + /* parse the command line */ + while ((opt = getopt(argc, argv, "a:ht")) > 0) { + switch (opt) { + case 'a': + if (strcmp(optarg, "x86") == 0) + arch = &arch_def_x86; + else if (strcmp(optarg, "x86_64") == 0) + arch = &arch_def_x86_64; + else if (strcmp(optarg, "x32") == 0) + arch = &arch_def_x32; + else if (strcmp(optarg, "arm") == 0) + arch = &arch_def_arm; + else + exit_usage(argv[0]); + break; + case 't': + translate = 1; + break; + case 'h': + default: + /* usage information */ + exit_usage(argv[0]); + } + } + + /* sanity checks */ + if (optind >= argc) + exit_usage(argv[0]); + + /* perform the syscall lookup */ + if (isdigit(argv[optind][0]) || argv[optind][0] == '-') { + sys_num = atoi(argv[optind]); + sys_name = arch_syscall_resolve_num(arch, sys_num); + printf("%s\n", sys_name); + } else { + sys_num = arch_syscall_resolve_name(arch, argv[optind]); + if (translate != 0) + /* ignore errors and just output the resolved number */ + arch_syscall_rewrite(arch, 0, &sys_num); + printf("%d\n", sys_num); + } + + return 0; +} diff --git a/version.h b/version.h new file mode 100644 index 0000000..31769bf --- /dev/null +++ b/version.h @@ -0,0 +1,8 @@ +/* automatically generated - do not edit */ +#ifndef _VERSION_H +#define _VERSION_H +#define VERSION_RELEASE "2.1.1" +#define VERSION_MAJOR 2 +#define VERSION_MINOR 1 +#define VERSION_MICRO 1 +#endif diff --git a/version_info b/version_info new file mode 100644 index 0000000..45a9675 --- /dev/null +++ b/version_info @@ -0,0 +1,8 @@ +# +# version_info - version information for seccomp library +# + +# version components +VERSION_MAJOR=2 +VERSION_MINOR=1 +VERSION_MICRO=1 -- 2.30.2