Import libseccomp_2.1.1.orig.tar.gz
authorKees Cook <kees@debian.org>
Sat, 12 Apr 2014 17:44:22 +0000 (18:44 +0100)
committerKees Cook <kees@debian.org>
Sat, 12 Apr 2014 17:44:22 +0000 (18:44 +0100)
[dgit import orig libseccomp_2.1.1.orig.tar.gz]

157 files changed:
CHANGELOG [new file with mode: 0644]
CREDITS [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
configure [new file with mode: 0755]
doc/Makefile [new file with mode: 0644]
doc/man/man1/scmp_sys_resolver.1 [new file with mode: 0644]
doc/man/man3/seccomp_arch_add.3 [new file with mode: 0644]
doc/man/man3/seccomp_arch_exist.3 [new file with mode: 0644]
doc/man/man3/seccomp_arch_native.3 [new file with mode: 0644]
doc/man/man3/seccomp_arch_remove.3 [new file with mode: 0644]
doc/man/man3/seccomp_attr_get.3 [new file with mode: 0644]
doc/man/man3/seccomp_attr_set.3 [new file with mode: 0644]
doc/man/man3/seccomp_export_bpf.3 [new file with mode: 0644]
doc/man/man3/seccomp_export_pfc.3 [new file with mode: 0644]
doc/man/man3/seccomp_init.3 [new file with mode: 0644]
doc/man/man3/seccomp_load.3 [new file with mode: 0644]
doc/man/man3/seccomp_merge.3 [new file with mode: 0644]
doc/man/man3/seccomp_release.3 [new file with mode: 0644]
doc/man/man3/seccomp_reset.3 [new file with mode: 0644]
doc/man/man3/seccomp_rule_add.3 [new file with mode: 0644]
doc/man/man3/seccomp_rule_add_array.3 [new file with mode: 0644]
doc/man/man3/seccomp_rule_add_exact.3 [new file with mode: 0644]
doc/man/man3/seccomp_rule_add_exact_array.3 [new file with mode: 0644]
doc/man/man3/seccomp_syscall_priority.3 [new file with mode: 0644]
doc/man/man3/seccomp_syscall_resolve_name.3 [new file with mode: 0644]
doc/man/man3/seccomp_syscall_resolve_name_arch.3 [new file with mode: 0644]
doc/man/man3/seccomp_syscall_resolve_num_arch.3 [new file with mode: 0644]
include/Makefile [new file with mode: 0644]
include/seccomp.h.in [new file with mode: 0644]
install.mk [new file with mode: 0644]
libseccomp.pc.in [new file with mode: 0644]
macros.mk [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/api.c [new file with mode: 0644]
src/arch-arm-syscalls.c [new file with mode: 0644]
src/arch-arm.c [new file with mode: 0644]
src/arch-arm.h [new file with mode: 0644]
src/arch-x32-syscalls.c [new file with mode: 0644]
src/arch-x32.c [new file with mode: 0644]
src/arch-x32.h [new file with mode: 0644]
src/arch-x86-syscalls.c [new file with mode: 0644]
src/arch-x86.c [new file with mode: 0644]
src/arch-x86.h [new file with mode: 0644]
src/arch-x86_64-syscalls.c [new file with mode: 0644]
src/arch-x86_64.c [new file with mode: 0644]
src/arch-x86_64.h [new file with mode: 0644]
src/arch.c [new file with mode: 0644]
src/arch.h [new file with mode: 0644]
src/db.c [new file with mode: 0644]
src/db.h [new file with mode: 0644]
src/gen_bpf.c [new file with mode: 0644]
src/gen_bpf.h [new file with mode: 0644]
src/gen_pfc.c [new file with mode: 0644]
src/gen_pfc.h [new file with mode: 0644]
src/hash.c [new file with mode: 0644]
src/hash.h [new file with mode: 0644]
src/python/Makefile [new file with mode: 0644]
src/python/libseccomp.pxd [new file with mode: 0644]
src/python/seccomp.pyx [new file with mode: 0644]
src/python/setup.py [new file with mode: 0644]
src/system.h [new file with mode: 0644]
tags [new file with mode: 0644]
tests/00-test.c [new file with mode: 0644]
tests/01-sim-allow.c [new file with mode: 0644]
tests/01-sim-allow.py [new file with mode: 0755]
tests/01-sim-allow.tests [new file with mode: 0644]
tests/02-sim-basic.c [new file with mode: 0644]
tests/02-sim-basic.py [new file with mode: 0755]
tests/02-sim-basic.tests [new file with mode: 0644]
tests/03-sim-basic_chains.c [new file with mode: 0644]
tests/03-sim-basic_chains.py [new file with mode: 0755]
tests/03-sim-basic_chains.tests [new file with mode: 0644]
tests/04-sim-multilevel_chains.c [new file with mode: 0644]
tests/04-sim-multilevel_chains.py [new file with mode: 0755]
tests/04-sim-multilevel_chains.tests [new file with mode: 0644]
tests/05-sim-long_jumps.c [new file with mode: 0644]
tests/05-sim-long_jumps.py [new file with mode: 0755]
tests/05-sim-long_jumps.tests [new file with mode: 0644]
tests/06-sim-actions.c [new file with mode: 0644]
tests/06-sim-actions.py [new file with mode: 0755]
tests/06-sim-actions.tests [new file with mode: 0644]
tests/07-sim-db_bug_looping.c [new file with mode: 0644]
tests/07-sim-db_bug_looping.py [new file with mode: 0755]
tests/07-sim-db_bug_looping.tests [new file with mode: 0644]
tests/08-sim-subtree_checks.c [new file with mode: 0644]
tests/08-sim-subtree_checks.py [new file with mode: 0755]
tests/08-sim-subtree_checks.tests [new file with mode: 0644]
tests/09-sim-syscall_priority_pre.c [new file with mode: 0644]
tests/09-sim-syscall_priority_pre.py [new file with mode: 0755]
tests/09-sim-syscall_priority_pre.tests [new file with mode: 0644]
tests/10-sim-syscall_priority_post.c [new file with mode: 0644]
tests/10-sim-syscall_priority_post.py [new file with mode: 0755]
tests/10-sim-syscall_priority_post.tests [new file with mode: 0644]
tests/11-basic-basic_errors.c [new file with mode: 0644]
tests/11-basic-basic_errors.py [new file with mode: 0755]
tests/11-basic-basic_errors.tests [new file with mode: 0644]
tests/12-sim-basic_masked_ops.c [new file with mode: 0644]
tests/12-sim-basic_masked_ops.py [new file with mode: 0755]
tests/12-sim-basic_masked_ops.tests [new file with mode: 0644]
tests/13-basic-attrs.c [new file with mode: 0644]
tests/13-basic-attrs.py [new file with mode: 0755]
tests/13-basic-attrs.tests [new file with mode: 0644]
tests/14-sim-reset.c [new file with mode: 0644]
tests/14-sim-reset.py [new file with mode: 0755]
tests/14-sim-reset.tests [new file with mode: 0644]
tests/15-basic-resolver.c [new file with mode: 0644]
tests/15-basic-resolver.py [new file with mode: 0755]
tests/15-basic-resolver.tests [new file with mode: 0644]
tests/16-sim-arch_basic.c [new file with mode: 0644]
tests/16-sim-arch_basic.py [new file with mode: 0755]
tests/16-sim-arch_basic.tests [new file with mode: 0644]
tests/17-sim-arch_merge.c [new file with mode: 0644]
tests/17-sim-arch_merge.py [new file with mode: 0755]
tests/17-sim-arch_merge.tests [new file with mode: 0644]
tests/18-sim-basic_whitelist.c [new file with mode: 0644]
tests/18-sim-basic_whitelist.py [new file with mode: 0755]
tests/18-sim-basic_whitelist.tests [new file with mode: 0644]
tests/19-sim-missing_syscalls.c [new file with mode: 0644]
tests/19-sim-missing_syscalls.py [new file with mode: 0755]
tests/19-sim-missing_syscalls.tests [new file with mode: 0644]
tests/20-live-basic_die.c [new file with mode: 0644]
tests/20-live-basic_die.py [new file with mode: 0755]
tests/20-live-basic_die.tests [new file with mode: 0644]
tests/21-live-basic_allow.c [new file with mode: 0644]
tests/21-live-basic_allow.py [new file with mode: 0755]
tests/21-live-basic_allow.tests [new file with mode: 0644]
tests/22-sim-basic_chains_array.c [new file with mode: 0644]
tests/22-sim-basic_chains_array.py [new file with mode: 0755]
tests/22-sim-basic_chains_array.tests [new file with mode: 0644]
tests/23-sim-arch_all_basic.c [new file with mode: 0644]
tests/23-sim-arch_all_basic.py [new file with mode: 0755]
tests/23-sim-arch_all_basic.tests [new file with mode: 0644]
tests/24-live-arg_allow.c [new file with mode: 0644]
tests/24-live-arg_allow.py [new file with mode: 0755]
tests/24-live-arg_allow.tests [new file with mode: 0644]
tests/25-sim-multilevel_chains_adv.c [new file with mode: 0644]
tests/25-sim-multilevel_chains_adv.py [new file with mode: 0755]
tests/25-sim-multilevel_chains_adv.tests [new file with mode: 0644]
tests/Makefile [new file with mode: 0644]
tests/regression [new file with mode: 0755]
tests/testdiff [new file with mode: 0755]
tests/testgen [new file with mode: 0755]
tests/util.c [new file with mode: 0644]
tests/util.h [new file with mode: 0644]
tests/util.py [new file with mode: 0644]
tools/Makefile [new file with mode: 0644]
tools/bpf.h [new file with mode: 0644]
tools/check-syntax [new file with mode: 0755]
tools/scmp_app_inspector [new file with mode: 0755]
tools/scmp_arch_detect.c [new file with mode: 0644]
tools/scmp_bpf_disasm.c [new file with mode: 0644]
tools/scmp_bpf_sim.c [new file with mode: 0644]
tools/scmp_sys_resolver.c [new file with mode: 0644]
version.h [new file with mode: 0644]
version_info [new file with mode: 0644]

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
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 (file)
index 0000000..d62a39c
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,15 @@
+libseccomp: Contributors
+===============================================================================
+http://libseccomp.sf.net
+
+Andy Lutomirski <luto@amacapital.net>
+Ashley Lai <adlai@us.ibm.com>
+Corey Bryant <coreyb@linux.vnet.ibm.com>
+Eduardo Otubo <otubo@linux.vnet.ibm.com>
+Eric Paris <eparis@redhat.com>
+Jake Edge <jake@lwn.net>
+Joe MacDonald <joe@deserted.net>
+Kees Cook <keescook@chromium.org>
+Paul Moore <pmoore@redhat.com>
+Thiago Marcos P. Santos <thiago.santos@intel.com>
+Vitaly Vi Shukela <vi0oss@gmail.com>
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
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 (file)
index 0000000..1f61f20
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,126 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+#
+# 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 (file)
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 (executable)
index 0000000..7c9f990
--- /dev/null
+++ b/configure
@@ -0,0 +1,277 @@
+#!/bin/bash
+
+#
+# Enhanced Seccomp Library Configure Script
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+# 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>
+
+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 (file)
index 0000000..2cef056
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+#
+# 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 (file)
index 0000000..fc28eaa
--- /dev/null
@@ -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 <paul@paul-moore.com>
diff --git a/doc/man/man3/seccomp_arch_add.3 b/doc/man/man3/seccomp_arch_add.3
new file mode 100644 (file)
index 0000000..fd1da55
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..f72602b
--- /dev/null
@@ -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 (file)
index 0000000..f72602b
--- /dev/null
@@ -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 (file)
index 0000000..f72602b
--- /dev/null
@@ -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 (file)
index 0000000..c1e85be
--- /dev/null
@@ -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 (file)
index 0000000..9a58cec
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..0d18638
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..45c49a3
--- /dev/null
@@ -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 (file)
index 0000000..6c79d41
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..87e0766
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..3a00bcd
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..8a61c9c
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..6f551cd
--- /dev/null
@@ -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 (file)
index 0000000..98878fb
--- /dev/null
@@ -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 <seccomp.h>
+.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 <fcntl.h>
+#include <seccomp.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..53714e7
--- /dev/null
@@ -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 (file)
index 0000000..53714e7
--- /dev/null
@@ -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 (file)
index 0000000..53714e7
--- /dev/null
@@ -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 (file)
index 0000000..7cffde8
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..0e78b55
--- /dev/null
@@ -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 <seccomp.h>
+.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 <seccomp.h>
+
+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 <paul@paul-moore.com>
+.\" //////////////////////////////////////////////////////////////////////////
+.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 (file)
index 0000000..f6d4472
--- /dev/null
@@ -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 (file)
index 0000000..f6d4472
--- /dev/null
@@ -0,0 +1 @@
+.so man3/seccomp_syscall_resolve_name.3
diff --git a/include/Makefile b/include/Makefile
new file mode 100644 (file)
index 0000000..aba3f71
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+#
+# 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 (file)
index 0000000..e150fbd
--- /dev/null
@@ -0,0 +1,1164 @@
+/**
+ * Seccomp Library
+ *
+ * Copyright (c) 2012,2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _SECCOMP_H
+#define _SECCOMP_H
+
+#include <elf.h>
+#include <inttypes.h>
+#include <asm/unistd.h>
+#include <linux/audit.h>
+
+#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 (file)
index 0000000..123af33
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Enhanced Seccomp Library Installation Defaults
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..c195831
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Enhanced Seccomp Library pkg-config Configuration
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..6df5b3a
--- /dev/null
+++ b/macros.mk
@@ -0,0 +1,234 @@
+#
+# Enhanced Seccomp Library Build Macros
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..7b980ab
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+#
+# 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 (file)
index 0000000..86e5f9d
--- /dev/null
+++ b/src/api.c
@@ -0,0 +1,589 @@
+/**
+ * Seccomp Library API
+ *
+ * Copyright (c) 2012,2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <endian.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/prctl.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..66db33b
--- /dev/null
@@ -0,0 +1,479 @@
+/**
+ * Enhanced Seccomp ARM Syscall Table
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <string.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..d2f0834
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Enhanced Seccomp ARM Specific Code
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/audit.h>
+
+#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 (file)
index 0000000..a6f0b00
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * Enhanced Seccomp ARM Specific Code
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _ARCH_ARM_H
+#define _ARCH_ARM_H
+
+#include <inttypes.h>
+
+#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 (file)
index 0000000..00c5bc2
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Enhanced Seccomp x32 Syscall Table
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <string.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..8b5dd97
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * Enhanced Seccomp x32 Specific Code
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/audit.h>
+
+#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 (file)
index 0000000..891a6f1
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Enhanced Seccomp x32 Specific Code
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _ARCH_X32_H
+#define _ARCH_X32_H
+
+#include <inttypes.h>
+
+#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 (file)
index 0000000..79f1b91
--- /dev/null
@@ -0,0 +1,468 @@
+/**
+ * Enhanced Seccomp x86 Syscall Table
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <string.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..66e72dc
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * Enhanced Seccomp x86 Specific Code
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/audit.h>
+
+#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 (file)
index 0000000..a399559
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * Enhanced Seccomp x86 Specific Code
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _ARCH_X86_H
+#define _ARCH_X86_H
+
+#include <stdbool.h>
+
+#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 (file)
index 0000000..af095b8
--- /dev/null
@@ -0,0 +1,468 @@
+/**
+ * Enhanced Seccomp x86_64 Syscall Table
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <string.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..55656c2
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Enhanced Seccomp x86_64 Specific Code
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/audit.h>
+
+#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 (file)
index 0000000..cc1c6bf
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Enhanced Seccomp x86_64 Specific Code
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _ARCH_x86_64_H
+#define _ARCH_x86_64_H
+
+#include <inttypes.h>
+
+#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 (file)
index 0000000..47a539d
--- /dev/null
@@ -0,0 +1,322 @@
+/**
+ * Enhanced Seccomp Architecture/Machine Specific Code
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <asm/bitsperlong.h>
+#include <linux/audit.h>
+#include <stdbool.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..5c4249f
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * Enhanced Seccomp Architecture/Machine Specific Code
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _ARCH_H
+#define _ARCH_H
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <seccomp.h>
+
+#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 <file> | grep '__NR_'
+ *      where <file> 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 <file> | 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 (file)
index 0000000..345a654
--- /dev/null
+++ b/src/db.c
@@ -0,0 +1,1314 @@
+/**
+ * Enhanced Seccomp Filter DB
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..c0472a5
--- /dev/null
+++ b/src/db.h
@@ -0,0 +1,194 @@
+/**
+ * Enhanced Seccomp Filter DB
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _FILTER_DB_H
+#define _FILTER_DB_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..8c96f87
--- /dev/null
@@ -0,0 +1,1755 @@
+/**
+ * Seccomp BPF Translator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..fe0580e
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * Seccomp BPF Translator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _TRANSLATOR_BPF_H
+#define _TRANSLATOR_BPF_H
+
+#include <inttypes.h>
+
+#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 (file)
index 0000000..954feab
--- /dev/null
@@ -0,0 +1,336 @@
+/**
+ * Seccomp Pseudo Filter Code (PFC) Generator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* NOTE: needed for the arch->token decoding in _pfc_arch() */
+#include <linux/audit.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..80f680f
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Seccomp String Translator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#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 (file)
index 0000000..cb52b3b
--- /dev/null
@@ -0,0 +1,674 @@
+/**
+ * Seccomp Library hash code
+ *
+ * Release under the Public Domain
+ * Author: Bob Jenkins <bob_jenkins@burtleburtle.net>
+ */
+
+/*
+ * 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 <stdint.h>
+
+#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; i<n; ++i) h = jhash_le( k[i], len[i], h);
+ *
+ */
+static uint32_t jhash_le(const void *key, size_t length, uint32_t initval)
+{
+       uint32_t a, b, c;
+       union {
+               const void *ptr;
+               size_t i;
+       } u;     /* needed for Mac Powerbook G4 */
+
+       /* set up the internal state */
+       a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+       u.ptr = key;
+       if ((arch_def_native->endian == 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 (file)
index 0000000..efd252f
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * The "lookup3.c" Hash Implementation from Bob Jenkins
+ *
+ * Original Author: Bob Jenkins <bob_jenkins@burtleburtle.net>
+ * 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 <inttypes.h>
+
+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 (file)
index 0000000..3543a65
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# Enhanced Seccomp Library Python Bindings Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+#
+# 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 (file)
index 0000000..411b08e
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# Seccomp Library Python Bindings
+#
+# Copyright (c) 2012,2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..47d2ae1
--- /dev/null
@@ -0,0 +1,572 @@
+#
+# Seccomp Library Python Bindings
+#
+# Copyright (c) 2012,2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+""" 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 <paul@paul-moore.com>'
+__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, <uint32_t *>&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 (file)
index 0000000..872642e
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+#
+# Enhanced Seccomp Library Python Module Build Script
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..cb14f65
--- /dev/null
@@ -0,0 +1,92 @@
+/**
+ * Seccomp System Information
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _SYSTEM_H
+#define _SYSTEM_H
+
+#include <linux/filter.h>
+#include <linux/prctl.h>
+
+#include <configure.h>
+
+#ifdef CONF_SYSINC_SECCOMP
+
+/* system header file */
+#include <linux/seccomp.h>
+
+#else
+
+/* NOTE: the definitions below were taken from the Linux Kernel sources */
+#include <linux/types.h>
+
+/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */
+#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 <linux/audit.h>.
+ * @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 (file)
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 <paul@paul-moore.com>'$/;"  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 (file)
index 0000000..a0b84bb
--- /dev/null
@@ -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 <http://www.gnu.org/licenses>.
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..5f4f74d
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..db3656b
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..9630276
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..b601554
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+/*
+ * Just like mode 1 seccomp we allow 4 syscalls:
+ * read, write, exit, and rt_sigreturn
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..868664f
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..07004a4
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..6e7309b
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..324170d
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..ef4353a
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..aeff58b
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <limits.h>
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..e40deee
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..cefbc4f
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..9f24ecd
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+#include <limits.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..716f745
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..03eb6d9
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..9aff9ef
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..4bd76f5
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..f09f0a0
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..53fb048
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright IBM Corp. 2012
+ * Author: Ashley Lai <adlai@us.ibm.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..3314a3e
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..a7ec72b
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..2e6577c
--- /dev/null
@@ -0,0 +1,178 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..766c3d1
--- /dev/null
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..ed3ec42
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..5de45bf
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..7b19943
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..7b7d53f
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..bafa5dd
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..bc2e152
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..aa0389f
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..c695e8b
--- /dev/null
@@ -0,0 +1,168 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright IBM Corp. 2012
+ * Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <seccomp.h>
+
+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 (executable)
index 0000000..4923e9b
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..3593392
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..a6fd939
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..283534b
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..20e0f6d
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..99e8dcb
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..471ab34
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..2288787
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+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 (file)
index 0000000..adcc934
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..60c131f
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..da52b2d
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com
+#
+
+test type: bpf-sim
+
+# Testname     Arch    Syscall         Arg0            Arg1            Arg2    Arg3    Arg4    Arg5    Result
+14-sim-reset   all     read            0               0x856B008       40      N       N       N       KILL
+14-sim-reset   all     write           1               0x856B008       40      N       N       N       ALLOW
+14-sim-reset   all     close           4               N               N       N       N       N       KILL
+14-sim-reset   all     rt_sigreturn    N               N               N       N       N       N       KILL
+14-sim-reset   all     open            0x856B008       4               N       N       N       N       KILL
+14-sim-reset   x86     0-3             N               N               N       N       N       N       KILL
+14-sim-reset   x86     5-360           N               N               N       N       N       N       KILL
+14-sim-reset   x86_64  0               N               N               N       N       N       N       KILL
+14-sim-reset   x86_64  2-360           N               N               N       N       N       N       KILL
+
+test type: bpf-sim-fuzz
+
+# Testname     StressCount
+14-sim-reset   50
+
+test type: bpf-valgrind
+
+# Testname
+14-sim-reset
diff --git a/tests/15-basic-resolver.c b/tests/15-basic-resolver.c
new file mode 100644 (file)
index 0000000..a103a1a
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <string.h>
+
+#include <seccomp.h>
+
+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 (executable)
index 0000000..a724d1b
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..7e4e7ba
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+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 (file)
index 0000000..5b02cca
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..d29a5ff
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..39917b5
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+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 (file)
index 0000000..61e1490
--- /dev/null
@@ -0,0 +1,110 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..44e9cc4
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..0f27ca9
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+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 (file)
index 0000000..5deefe7
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..a7b9cb7
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..d88d0d2
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+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 (file)
index 0000000..0ccb0f5
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..38408b1
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..5a1f244
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+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 (file)
index 0000000..b71e0f5
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..2b07776
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..ac30ae1
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com
+#
+
+test type: live
+
+# Testname             Result
+20-live-basic_die      KILL
+20-live-basic_die      TRAP
+20-live-basic_die      ERRNO
diff --git a/tests/21-live-basic_allow.c b/tests/21-live-basic_allow.c
new file mode 100644 (file)
index 0000000..1496cef
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..1332f2e
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..e41e4ef
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com
+#
+
+test type: live
+
+# Testname             Result
+21-live-basic_allow    ALLOW
diff --git a/tests/22-sim-basic_chains_array.c b/tests/22-sim-basic_chains_array.c
new file mode 100644 (file)
index 0000000..7eba836
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * Seccomp Library test program
+ *
+ * Author: Paul Moore <pmoore@redhat.com>, Vitaly Shukela <vi0oss@gmail.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..dfc3a58
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+# 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 (file)
index 0000000..b8867b7
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# libseccomp regression test automation data
+#
+# Author: Vitaly Shukela <vi0oss@gmail.com>
+#
+
+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 (file)
index 0000000..1b39914
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..2674636
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..980268f
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# libseccomp regression test automation data
+#
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com
+#
+
+test type: bpf-sim
+
+# Testname             Arch    Syscall         Arg0            Arg1            Arg2    Arg3    Arg4    Arg5    Result
+23-sim-arch_all_basic  +all    read            0               0x856B008       10      N       N       N       ALLOW
+23-sim-arch_all_basic  +all    read            1-10            0x856B008       10      N       N       N       KILL
+23-sim-arch_all_basic  +all    write           1-2             0x856B008       10      N       N       N       ALLOW
+23-sim-arch_all_basic  +all    write           3-10            0x856B008       10      N       N       N       KILL
+23-sim-arch_all_basic  +all    close           N               N               N       N       N       N       ALLOW
+23-sim-arch_all_basic  +all    rt_sigreturn    N               N               N       N       N       N       ALLOW
+23-sim-arch_all_basic  +all    open            0x856B008       4               N       N       N       N       KILL
+
+test type: bpf-sim-fuzz
+
+# Testname             StressCount
+23-sim-arch_all_basic  50
+
+test type: bpf-valgrind
+
+# Testname
+23-sim-arch_all_basic
diff --git a/tests/24-live-arg_allow.c b/tests/24-live-arg_allow.c
new file mode 100644 (file)
index 0000000..e071dda
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..32c63ec
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..e383e6a
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com
+#
+
+test type: live
+
+# Testname             Result
+24-live-arg_allow      ALLOW
diff --git a/tests/25-sim-multilevel_chains_adv.c b/tests/25-sim-multilevel_chains_adv.c
new file mode 100644 (file)
index 0000000..68c24ac
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <stdlib.h>
+
+#include <seccomp.h>
+
+#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 (executable)
index 0000000..95a673c
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (file)
index 0000000..1bdfa40
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com
+#
+
+test type: bpf-sim
+
+# Testname                     Arch            Syscall         Arg0            Arg1            Arg2            Arg3    Arg4    Arg5    Result
+25-sim-multilevel_chains_adv   all             0-9             N               N               N               N       N       N       KILL
+25-sim-multilevel_chains_adv   all             10              0x0000000b      0x00000000      N               N       N       N       ALLOW
+25-sim-multilevel_chains_adv   x86_64          10              0x10000000b     0x00000000      N               N       N       N       KILL
+25-sim-multilevel_chains_adv   x86_64          10              0x0000000b      0x10000000c     N               N       N       N       ALLOW
+25-sim-multilevel_chains_adv   all             11-19           N               N               N               N       N       N       KILL
+25-sim-multilevel_chains_adv   all             20              0x00000015      0x00000000      0x00000017      N       N       N       ALLOW
+25-sim-multilevel_chains_adv   all             20              0x00000015      0x00000016      0x00000017      N       N       N       KILL
+25-sim-multilevel_chains_adv   x86_64          20              0x100000015     0x00000000      0x00000017      N       N       N       KILL
+25-sim-multilevel_chains_adv   x86_64          20              0x00000015      0x00000000      0x100000017     N       N       N       KILL
+25-sim-multilevel_chains_adv   all             21-30           N               N               N               N       N       N       KILL
+
+test type: bpf-sim-fuzz
+
+# Testname                     StressCount
+25-sim-multilevel_chains_adv   50
+
+test type: bpf-valgrind
+
+# Testname
+25-sim-multilevel_chains_adv
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..5fdbca7
--- /dev/null
@@ -0,0 +1,95 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+#
+# 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 (executable)
index 0000000..790d5e1
--- /dev/null
@@ -0,0 +1,885 @@
+#!/bin/bash
+
+#
+# libseccomp regression test automation script
+#
+# Copyright IBM Corp. 2012
+# Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 <LOG>]
+                  [-s SINGLE_TEST] [-t <TEMP_DIR>] [-T <TEST_TYPE>]
+
+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 $(</dev/urandom tr -dc A-Za-z0-9 | head -c"$rcount"))
+       echo "$rdata"
+}
+
+#
+# Run the specified "bpf-sim-fuzz" test
+#
+# Tests that belong to the "bpf-sim-fuzz" test type generate a BPF filter and
+# then run a simulated system call test with pseudo-random fuzz data for the
+# syscall and argument values.  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.)
+#     StressCount - The number of fuzz tests to run against the filter
+#
+# The following test data is output to the logfile for each generated test:
+#
+#     Testname - The executable test name (e.g. 01-allow, 02-basic, etc.)
+#     Syscall - The fuzzed syscall value to be simulated against the filter
+#     Arg0-5 - The fuzzed syscall arg values to be simulated against the filter
+#
+# 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_fuzz() {
+       local rc
+
+       # begin splitting the test data from the line into individual variables
+       local line=($3)
+       local testname=${line[0]}
+       local stress_count=${line[1]}
+
+       for i in $(seq 1 $stress_count); do
+               local sys=$(generate_random_data)
+               local -a arg=($(generate_random_data) $(generate_random_data) \
+                             $(generate_random_data) $(generate_random_data) \
+                             $(generate_random_data) $(generate_random_data))
+
+               # get the generated sub-test num string
+               local testnumstr=$(generate_test_num "$1" $2 $i)
+
+               # 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 17 17 17 17 17 17)
+               local testdata=$(printf "%-${COL_WIDTH[0]}s" $testname)
+               testdata+=$(printf "%-${COL_WIDTH[1]}s" $sys)
+               testdata+=$(printf "%-${COL_WIDTH[2]}s" ${arg[0]})
+               testdata+=$(printf "%-${COL_WIDTH[3]}s" ${arg[1]})
+               testdata+=$(printf "%-${COL_WIDTH[4]}s" ${arg[2]})
+               testdata+=$(printf "%-${COL_WIDTH[5]}s" ${arg[3]})
+               testdata+=$(printf "%-${COL_WIDTH[6]}s" ${arg[4]})
+               testdata+=$(printf "%s" ${arg[5]})
+
+               # print out the generated test data to the log file
+               print_data "$testnumstr" "$testdata"
+
+               # set up the syscall argument values to be passed to bpf_sim
+               for i in {0..5}; do
+                       arg[$i]=" -$i ${arg[$i]} "
+               done
+
+               # run the test command and put the BPF filter 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 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 (executable)
index 0000000..a6ddbac
--- /dev/null
@@ -0,0 +1,126 @@
+#!/bin/bash
+
+#
+# libseccomp test diff generator
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+####
+# 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 (executable)
index 0000000..0da599d
--- /dev/null
@@ -0,0 +1,206 @@
+#!/bin/bash
+
+#
+# libseccomp test output generator
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+####
+# 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 (file)
index 0000000..9c069d6
--- /dev/null
@@ -0,0 +1,209 @@
+/**
+ * Seccomp Library utility code for tests
+ *
+ * Copyright (c) 2012 Red Hat <eparis@redhat.com>
+ * Author: Eric Paris <eparis@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <seccomp.h>
+
+#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 (file)
index 0000000..b3c5a29
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Seccomp Library utility code for tests
+ *
+ * Copyright IBM Corp. 2012
+ * Author: Corey Bryant <coreyb@linux.vnet.ibm.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#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 (file)
index 0000000..20704f6
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# Seccomp Library utility code for tests
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+""" 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 (file)
index 0000000..79c7d25
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+#
+# 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 (file)
index 0000000..4fb4c4f
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ * BPF Language Definitions
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#ifndef _BPF_H
+#define _BPF_H
+
+#include <inttypes.h>
+#include <stddef.h>
+
+/* 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 (executable)
index 0000000..f356a46
--- /dev/null
@@ -0,0 +1,116 @@
+#!/bin/bash
+
+#
+# libseccomp code syntax checking tool
+#
+# Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+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 (executable)
index 0000000..37f880b
--- /dev/null
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+#
+# Runtime syscall inspector
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# 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 <http://www.gnu.org/licenses>.
+#
+
+####
+# 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 <file>] <command> [<args>]"
+               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 (file)
index 0000000..e90f92b
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * Architecture Detector
+ *
+ * Copyright (c) 2013 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <seccomp.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] [-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 (file)
index 0000000..8474eb1
--- /dev/null
@@ -0,0 +1,322 @@
+/**
+ * BPF Disassembler
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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 [<bpf_file>]\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 (file)
index 0000000..1b46cc9
--- /dev/null
@@ -0,0 +1,310 @@
+/**
+ * BPF Simulator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/audit.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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 <bpf_file> [-v]"
+               " -a <arch> -s <syscall_num> [-0 <a0>] ... [-5 <a5>]\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 (file)
index 0000000..e86b400
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+ * Syscall resolver
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * 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 <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <arch>] [-t] <name>|<number>\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 (file)
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 (file)
index 0000000..45a9675
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# version_info - version information for seccomp library
+#
+
+# version components
+VERSION_MAJOR=2
+VERSION_MINOR=1
+VERSION_MICRO=1