summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2012-01-30 12:46:49 -0500
committerPaul Moore <pmoore@redhat.com>2012-01-30 12:46:49 -0500
commit054b63829db348858be3198e6313254e8a611b0c (patch)
tree86b591f1137b6767e9d7c77a58157472f9448b4b
parent02201a5693430c8c1c1b8855633431eec9f54d31 (diff)
downloadlibseccomp-054b63829db348858be3198e6313254e8a611b0c.tar.gz
libseccomp: initial import of project
This patch is the initial import of the libseccomp library, a library intended for use by application developers who wish to leverage the enhanced seccomp (mode 2) support in the Linux Kernel but who do not want to craft their own seccomp filter code by hand. This library will provide a high-level API for developers which will allow them to generate and load seccomp filter code into the kernel by specifying which syscalls, optionally with argument values, are to be allowed or denied by the kernel. Needless to say, this is an initial import into the git repository so everything is still subject to change, and the usual caveats about untested code apply quite strongly. This code is licensed under the GPLv2, with some portions taken from examples provided by Will Drewry <wad@chromium.org> and copyrighted by the Chromium OS Authors <chromium-os-dev@chromium.org> which carries the following license (included in the associated files as well): "The code may be used by anyone for any purpose, and can serve as a starting point for developing applications using prctl(PR_ATTACH_SECCOMP_FILTER). No guarantees are provided with respect to the correctness or functionality of this code." Signed-off-by: Paul Moore <pmoore@redhat.com>
-rw-r--r--LICENSE339
-rw-r--r--Makefile88
-rw-r--r--README1
-rw-r--r--include/seccomp.h59
-rw-r--r--include/seccomp_filter.h84
-rw-r--r--macros.mk71
-rw-r--r--src/Makefile53
-rw-r--r--src/bpf_helper.c89
-rw-r--r--src/bpf_helper.h223
-rw-r--r--src/filter_db.c365
-rw-r--r--src/filter_db.h98
-rw-r--r--src/library_api.c192
-rw-r--r--src/translator_bpf.c407
-rw-r--r--src/translator_bpf.h36
-rw-r--r--src/translator_str.c141
-rw-r--r--src/translator_str.h29
-rw-r--r--tests/01-basic.c37
-rw-r--r--tests/02-basic-pfc.c61
-rw-r--r--tests/Makefile61
-rw-r--r--version_info6
20 files changed, 2440 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..fbd073a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,88 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# macros
+#
+
+include macros.mk
+
+#
+# configuration
+#
+
+INSTALL_PREFIX ?= /usr/local
+
+INSTALL_SBIN_DIR ?= $(INSTALL_PREFIX)/sbin
+INSTALL_BIN_DIR ?= $(INSTALL_PREFIX)/bin
+INSTALL_LIB_DIR ?= $(INSTALL_PREFIX)/lib
+INSTALL_MAN_DIR ?= $(INSTALL_PREFIX)/share/man
+
+INSTALL_OWNER ?= root
+INSTALL_GROUP ?= root
+
+#
+# targets
+#
+
+SUBDIRS = src tests
+
+.PHONY: tarball install clean $(SUBDIRS)
+
+all: $(SUBDIRS)
+
+tarball: clean
+ @ver=$$(source ./version_info; echo $$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=.svn . | (cd $$rel_dir; tar xf -); \
+ (cd $$tmp_dir; tar zcf $$tarball libseccomp-$$ver); \
+ mv $$tmp_dir/$$tarball ..; \
+ rm -rf $$tmp_dir;
+
+install: $(SUBDIRS)
+ @echo "INFO: installing files in $(INSTALL_PREFIX)"
+ @echo "- XXX - TBD"
+
+$(VERSION_HDR): version_info
+ @echo "INFO: creating the version header file"
+ @hdr="$(VERSION_HDR)"; \
+ source ./version_info; \
+ 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 "#endif" >> $$hdr;
+
+$(SUBDIRS): $(VERSION_HDR)
+ @echo "INFO: entering directory $@/ ..."
+ @$(MAKE) -s -C $@
+
+clean:
+ @echo "INFO: removing the version header file"; \
+ rm -f $(VERSION_HDR)
+ @for dir in $(SUBDIRS); do \
+ echo "INFO: cleaning in $$dir/"; \
+ $(MAKE) -s -C $$dir clean; \
+ done
diff --git a/README b/README
index e69de29..f94e27d 100644
--- a/README
+++ b/README
@@ -0,0 +1 @@
+Enhanced seccomp (mode 2) helper library
diff --git a/include/seccomp.h b/include/seccomp.h
new file mode 100644
index 0000000..da50665
--- /dev/null
+++ b/include/seccomp.h
@@ -0,0 +1,59 @@
+/**
+ * Seccomp Library
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SECCOMP_H
+#define _SECCOMP_H
+
+#include <asm/unistd.h>
+
+/* XXX - see notes in seccomp_add_syscall() about pseudo syscalls, we'll need
+ * to define them here for the arch/platforms that require them */
+
+#define SCMP_SYS(x) __NR_##x
+
+enum scmp_flt_action {
+ SCMP_ACT_ALLOW = 0,
+ SCMP_ACT_DENY,
+};
+
+enum scmp_compare {
+ SCMP_CMP_NE = 0, /* not equal */
+ SCMP_CMP_LT, /* less than */
+ SCMP_CMP_LE, /* less than or equal */
+ SCMP_CMP_EQ, /* equal */
+ SCMP_CMP_GE, /* greater than or equal */
+ SCMP_CMP_GT, /* greater than */
+};
+
+int seccomp_reset(enum scmp_flt_action def_action);
+void seccomp_release(void);
+
+int seccomp_enable(void);
+
+int seccomp_add_syscall(enum scmp_flt_action action, int syscall);
+int seccomp_add_syscall_arg(enum scmp_flt_action action, int syscall,
+ unsigned int arg,
+ enum scmp_compare op, unsigned long datum);
+
+int seccomp_gen_pfc(int fd);
+int seccomp_gen_bpf(int fd);
+
+#endif
diff --git a/include/seccomp_filter.h b/include/seccomp_filter.h
new file mode 100644
index 0000000..155b148
--- /dev/null
+++ b/include/seccomp_filter.h
@@ -0,0 +1,84 @@
+/*
+ * Secomp-based system call filtering data structures and definitions.
+ *
+ * Copyright (C) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ */
+
+#ifndef __LINUX_SECCOMP_FILTER_H__
+#define __LINUX_SECCOMP_FILTER_H__
+
+/* XXX - needed for early development only */
+
+#ifndef PR_ATTACH_SECCOMP_FILTER
+#define PR_ATTACH_SECCOMP_FILTER 37
+#endif
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+
+/*
+ * Keep the contents of this file similar to linux/filter.h:
+ * struct sock_filter and sock_fprog and versions.
+ * Custom naming exists solely if divergence is ever needed.
+ */
+
+/*
+ * Current version of the filter code architecture.
+ */
+#define SECCOMP_BPF_MAJOR_VERSION 1
+#define SECCOMP_BPF_MINOR_VERSION 1
+
+struct seccomp_filter_block { /* Filter block */
+ __u16 code; /* Actual filter code */
+ __u8 jt; /* Jump true */
+ __u8 jf; /* Jump false */
+ __u32 k; /* Generic multiuse field */
+};
+
+struct seccomp_fprog { /* Required for SO_ATTACH_FILTER. */
+ unsigned short len; /* Number of filter blocks */
+ struct seccomp_filter_block *filter;
+};
+
+/* Ensure the u32 ordering is consistent with platform byte order. */
+#if defined(__LITTLE_ENDIAN)
+#define SECCOMP_ENDIAN_SWAP(x, y) x, y
+#elif defined(__BIG_ENDIAN)
+#define SECCOMP_ENDIAN_SWAP(x, y) y, x
+#else
+#error edit for your odd arch byteorder.
+#endif
+
+/* System call argument layout for the filter data. */
+union seccomp_filter_arg {
+ struct {
+ __u32 SECCOMP_ENDIAN_SWAP(lo32, hi32);
+ };
+ __u64 u64;
+};
+
+/*
+ * Expected data the BPF program will execute over.
+ * Endianness will be arch specific, but the values will be
+ * swapped, as above, to allow for consistent BPF programs.
+ */
+struct seccomp_filter_data {
+ int syscall_nr;
+ __u32 __reserved;
+ union seccomp_filter_arg args[6];
+};
+
+#undef SECCOMP_ENDIAN_SWAP
+
+/*
+ * Defined valid return values for the BPF program.
+ */
+#define SECCOMP_BPF_ALLOW 0xFFFFFFFF
+#define SECCOMP_BPF_DENY 0
+
+#endif /* __LINUX_SECCOMP_FILTER_H__ */
diff --git a/macros.mk b/macros.mk
new file mode 100644
index 0000000..ac5dccc
--- /dev/null
+++ b/macros.mk
@@ -0,0 +1,71 @@
+#
+# Enhanced Seccomp Library Build Macros
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# simple /bin/sh script to find the top of the tree
+#
+
+TOPDIR = $$( \
+ ftd() { \
+ cd $$1; \
+ if [ -r "macros.mk" ]; then \
+ pwd; \
+ else \
+ ftd "../"; \
+ fi \
+ }; \
+ ftd .)
+
+#
+# build configuration
+#
+
+INCFLAGS = -I$(TOPDIR)/include
+LIBFLAGS =
+
+CFLAGS ?= -O0 -g -Wall
+LDFLAGS ?= -g
+
+#
+# build constants
+#
+
+VERSION_HDR = src/version.h
+
+#
+# build macros
+#
+
+ARCHIVE = @echo " AR $@ (add/update: $?)"; $(AR) -cru $@ $?;
+COMPILE = @echo " CC $@"; $(CC) $(CFLAGS) $(INCFLAGS) -o $*.o -c $<;
+COMPILE_EXEC = @echo " CC $@"; $(CC) $(CFLAGS) $(INCFLAGS) -o $@ $< $(LDFLAGS);
+LINK_EXEC = @echo " LD $@"; $(CC) $(LDFLAGS) -o $@ $^ $(LIBFLAGS);
+LINK_LIB = @echo " LD $@ "; $(CC) $(LDFLAGS) -o $@ $^ -shared -Wl,-soname=$@;
+
+#
+# default build targets
+#
+
+.c.o:
+ $(COMPILE)
+
+
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..342faf3
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,53 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# macros
+#
+
+include ../macros.mk
+
+#
+# configuration
+#
+
+include ../version_info
+
+LIB_STATIC = libseccomp.a
+LIB_SHARED = libseccomp.so.$(VERSION_RELEASE)
+
+OBJS = library_api.o filter_db.o translator_str.o translator_bpf.o bpf_helper.o
+
+INCFLAGS := $(INCFLAGS) -I../include
+
+#
+# targets
+#
+
+.PHONY: all clean
+
+all: $(LIB_STATIC)
+
+$(LIB_STATIC): $(OBJS)
+ $(ARCHIVE)
+
+clean:
+ $(RM) -f $(OBJS) $(LIB_STATIC) $(LIB_SHARED)
diff --git a/src/bpf_helper.c b/src/bpf_helper.c
new file mode 100644
index 0000000..1b5fb5c
--- /dev/null
+++ b/src/bpf_helper.c
@@ -0,0 +1,89 @@
+/*
+ * Seccomp BPF helper functions
+ *
+ * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ * Author: Will Drewry <wad@chromium.org>
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using prctl(PR_ATTACH_SECCOMP_FILTER).
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "bpf_helper.h"
+
+int bpf_resolve_jumps(struct bpf_labels *labels,
+ struct seccomp_filter_block *filter, size_t count)
+{
+ struct seccomp_filter_block *begin = filter;
+ __u8 insn = count - 1;
+
+ if (count < 1)
+ return -1;
+ /*
+ * Walk it once, backwards, to build the label table and do fixups.
+ * Since backward jumps are disallowed by BPF, this is easy.
+ */
+ filter += insn;
+ for (; filter >= begin; --insn, --filter) {
+ if (filter->code != (BPF_JMP+BPF_JA))
+ continue;
+ switch ((filter->jt<<8)|filter->jf) {
+ case (JUMP_JT<<8)|JUMP_JF:
+ if (labels->labels[filter->k].location == 0xffffffff) {
+ fprintf(stderr, "Unresolved label: '%s'\n",
+ labels->labels[filter->k].label);
+ return 1;
+ }
+ filter->k = labels->labels[filter->k].location -
+ (insn + 1);
+ filter->jt = 0;
+ filter->jf = 0;
+ continue;
+ case (LABEL_JT<<8)|LABEL_JF:
+ if (labels->labels[filter->k].location != 0xffffffff) {
+ fprintf(stderr, "Duplicate label use: '%s'\n",
+ labels->labels[filter->k].label);
+ return 1;
+ }
+ labels->labels[filter->k].location = insn;
+ filter->k = 0; /* fall through */
+ filter->jt = 0;
+ filter->jf = 0;
+ continue;
+ }
+ }
+ return 0;
+}
+
+/* Simple lookup table for labels. */
+__u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label)
+{
+ struct __bpf_label *begin = labels->labels, *end;
+ int id;
+ if (labels->count == 0) {
+ begin->label = label;
+ begin->location = 0xffffffff;
+ labels->count++;
+ return 0;
+ }
+ end = begin + labels->count;
+ for (id = 0; begin < end; ++begin, ++id) {
+ if (!strcmp(label, begin->label))
+ return id;
+ }
+ begin->label = label;
+ begin->location = 0xffffffff;
+ labels->count++;
+ return id;
+}
+
+void seccomp_bpf_print(struct seccomp_filter_block *filter, size_t count)
+{
+ struct seccomp_filter_block *end = filter + count;
+ for ( ; filter < end; ++filter)
+ printf("{ code=%u,jt=%u,jf=%u,k=%u },\n",
+ filter->code, filter->jt, filter->jf, filter->k);
+}
diff --git a/src/bpf_helper.h b/src/bpf_helper.h
new file mode 100644
index 0000000..3599592
--- /dev/null
+++ b/src/bpf_helper.h
@@ -0,0 +1,223 @@
+/*
+ * Example wrapper around BPF macros.
+ *
+ * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ * Author: Will Drewry <wad@chromium.org>
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using prctl(PR_ATTACH_SECCOMP_FILTER).
+ *
+ * No guarantees are provided with respect to the correctness
+ * or functionality of this code.
+ */
+
+#ifndef __BPF_HELPER_H__
+#define __BPF_HELPER_H__
+
+#include <asm/bitsperlong.h> /* for __BITS_PER_LONG */
+#include <linux/filter.h>
+#if 0
+#include <linux/seccomp_filter.h> /* for seccomp_filter_data.arg */
+#else
+/* XXX - needed for early development only */
+#include <seccomp_filter.h>
+#endif
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <stddef.h>
+
+#define BPF_LABELS_MAX 256
+struct bpf_labels {
+ int count;
+ struct __bpf_label {
+ const char *label;
+ __u32 location;
+ } labels[BPF_LABELS_MAX];
+};
+
+int bpf_resolve_jumps(struct bpf_labels *labels,
+ struct seccomp_filter_block *filter, size_t count);
+__u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label);
+void seccomp_bpf_print(struct seccomp_filter_block *filter, size_t count);
+
+#define JUMP_JT 0xff
+#define JUMP_JF 0xff
+#define LABEL_JT 0xfe
+#define LABEL_JF 0xfe
+
+#define ALLOW \
+ BPF_STMT(BPF_RET+BPF_K, 0xFFFFFFFF)
+#define DENY \
+ BPF_STMT(BPF_RET+BPF_K, 0)
+#define JUMP(labels, label) \
+ BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL(labels, label), JUMP_JT, JUMP_JF)
+#define LABEL(labels, label) \
+ BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL(labels, label), LABEL_JT, LABEL_JF)
+#define SYSCALL(nr, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1), \
+ jt
+
+/* Lame, but just an example */
+#define FIND_LABEL(labels, label) seccomp_bpf_label(labels, #label)
+
+#define EXPAND(...) __VA_ARGS__
+/* Map all width-sensitive operations */
+#if __BITS_PER_LONG == 32
+
+#define JEQ(x, jt) JEQ32(x, EXPAND(jt))
+#define JNE(x, jt) JNE32(x, EXPAND(jt))
+#define JGT(x, jt) JGT32(x, EXPAND(jt))
+#define JLT(x, jt) JLT32(x, EXPAND(jt))
+#define JGE(x, jt) JGE32(x, EXPAND(jt))
+#define JLE(x, jt) JLE32(x, EXPAND(jt))
+#define JA(x, jt) JA32(x, EXPAND(jt))
+#define ARG(i) ARG_32(i)
+
+#elif __BITS_PER_LONG == 64
+
+#define JEQ(x, jt) \
+ JEQ64(((union seccomp_filter_arg){.u64 = (x)}).lo32, \
+ ((union seccomp_filter_arg){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JGT(x, jt) \
+ JGT64(((union seccomp_filter_arg){.u64 = (x)}).lo32, \
+ ((union seccomp_filter_arg){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JGE(x, jt) \
+ JGE64(((union seccomp_filter_arg){.u64 = (x)}).lo32, \
+ ((union seccomp_filter_arg){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JNE(x, jt) \
+ JNE64(((union seccomp_filter_arg){.u64 = (x)}).lo32, \
+ ((union seccomp_filter_arg){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JLT(x, jt) \
+ JLT64(((union seccomp_filter_arg){.u64 = (x)}).lo32, \
+ ((union seccomp_filter_arg){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JLE(x, jt) \
+ JLE64(((union seccomp_filter_arg){.u64 = (x)}).lo32, \
+ ((union seccomp_filter_arg){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+
+#define JA(x, jt) \
+ JA64(((union seccomp_filter_arg){.u64 = (x)}).lo32, \
+ ((union seccomp_filter_arg){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define ARG(i) ARG_64(i)
+
+#else
+#error __BITS_PER_LONG value unusable.
+#endif
+
+/* Loads the arg into A */
+#define ARG_32(idx) \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
+ offsetof(struct seccomp_filter_data, args[(idx)].lo32))
+
+/* Loads hi into A and lo in X */
+#define ARG_64(idx) \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
+ offsetof(struct seccomp_filter_data, args[(idx)].lo32)), \
+ BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
+ offsetof(struct seccomp_filter_data, args[(idx)].hi32)), \
+ BPF_STMT(BPF_ST, 1) /* hi -> M[1] */
+
+#define JEQ32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 0, 1), \
+ jt
+
+#define JNE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \
+ jt
+
+/* Checks the lo, then swaps to check the hi. A=lo,X=hi */
+#define JEQ64(lo, hi, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+
+#define JNE64(lo, hi, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 5, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+
+#define JA32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
+ jt
+
+#define JA64(lo, hi, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+
+#define JGE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
+ jt
+
+#define JLT32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
+ jt
+
+/* Shortcut checking if hi > arg.hi. */
+#define JGE64(lo, hi, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+
+#define JLT64(lo, hi, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+
+#define JGT32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
+ jt
+
+#define JLE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
+ jt
+
+/* Check hi > args.hi first, then do the GE checking */
+#define JGT64(lo, hi, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+
+#define JLE64(lo, hi, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 6, 0), \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+
+#define LOAD_SYSCALL_NR \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
+ offsetof(struct seccomp_filter_data, syscall_nr))
+
+#endif /* __BPF_HELPER_H__ */
diff --git a/src/filter_db.c b/src/filter_db.c
new file mode 100644
index 0000000..3e95805
--- /dev/null
+++ b/src/filter_db.c
@@ -0,0 +1,365 @@
+/**
+ * Enhanced Seccomp Filter DB
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <seccomp.h>
+
+#include "filter_db.h"
+
+/**
+ * Free 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 before freeing the list item.
+ *
+ */
+#define _db_list_foreach_free(iter,list) \
+ for (iter = (list); \
+ iter != NULL; \
+ (list) = iter->next, free(iter), iter = (list))
+
+/**
+ * Free a syscall filter argument list
+ * @param list the argument list
+ *
+ * This function frees a syscall argument list.
+ *
+ */
+static void _db_sys_arg_list_free(struct db_syscall_arg_list *list)
+{
+ struct db_syscall_arg_list *a_iter;
+ struct db_syscall_arg_val_list *v_iter;
+
+ _db_list_foreach_free(a_iter, list) {
+ _db_list_foreach_free(v_iter, a_iter->values);
+ }
+}
+
+/**
+ * Intitalize a seccomp filter DB
+ * @param def_action the default filter action
+ *
+ * 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 *seccomp_db_new(enum scmp_flt_action def_action)
+{
+ struct db_filter *db;
+
+ db = malloc(sizeof(*db));
+ if (db) {
+ memset(db, 0, sizeof(*db));
+ db->def_action = def_action;
+ }
+
+ 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 seccomp_db_destroy(struct db_filter *db)
+{
+ struct db_syscall_list *s_iter;
+
+ if (db == NULL)
+ return;
+
+ _db_list_foreach_free(s_iter, db->sys_allow)
+ _db_sys_arg_list_free(s_iter->args);
+ _db_list_foreach_free(s_iter, db->sys_deny)
+ _db_sys_arg_list_free(s_iter->args);
+}
+
+/**
+ * Add a syscall filter
+ * @param db the seccomp filter db
+ * @param action the filter action
+ * @param syscall the syscall number
+ * @param override override existing rules
+ *
+ * This function adds a new syscall filter to the seccomp filter DB, and if
+ * the override argument is true, any existing matching syscall rules are
+ * reset/replaced. Returns zero on success, negative values on failure.
+ *
+ */
+int seccomp_db_add_syscall(struct db_filter *db,
+ enum scmp_flt_action action, unsigned int syscall,
+ unsigned int override)
+{
+ struct db_syscall_list *sys;
+ struct db_syscall_list *sys_prev = NULL;
+ struct db_syscall_list *sys_new;
+
+ assert(db != NULL);
+
+ /* check the opposite action list first to prevent problems later */
+ sys = (action == SCMP_ACT_ALLOW ? db->sys_deny : db->sys_allow);
+ while (sys != NULL && sys->num < syscall)
+ sys = sys->next;
+ if (sys != NULL && sys->num == syscall)
+ return -EEXIST;
+
+ /* add the filter to the correct list if it isn't already present */
+ sys = (action == SCMP_ACT_ALLOW ? db->sys_allow : db->sys_deny);
+ while (sys != NULL && sys->num < syscall) {
+ sys_prev = sys;
+ sys = sys->next;
+ }
+ if (sys == NULL || sys->num != syscall) {
+ sys_new = malloc(sizeof(*sys_new));
+ if (sys_new == NULL)
+ return -ENOMEM;
+ memset(sys_new, 0, sizeof(*sys_new));
+ sys_new->num = syscall;
+ if (sys_prev == NULL) {
+ if (action == SCMP_ACT_ALLOW)
+ db->sys_allow = sys_new;
+ else
+ db->sys_deny = sys_new;
+ } else {
+ sys_new->next = sys_prev->next;
+ sys_prev->next = sys_new;
+ }
+ } else if (override) {
+ /* if the syscall is already present in the filter with the
+ * correct action we don't change it unless override is true */
+ _db_sys_arg_list_free(sys->args);
+ sys->args = NULL;
+ }
+
+ return 0;
+}
+
+/**
+ * Add a syscall filter with an argument filter
+ * @param db the seccomp filter db
+ * @param action the filter action
+ * @param syscall the syscall number
+ * @param arg the argument number
+ * @param datum the argument value
+ * @param override override existing rules
+ *
+ * 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). If override is true, then the
+ * argument filter rule is added regardless of what is already present.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+int seccomp_db_add_syscall_arg(struct db_filter *db,
+ enum scmp_flt_action action,
+ unsigned int syscall,
+ unsigned int arg,
+ enum scmp_compare op, unsigned long datum,
+ unsigned int override)
+{
+ int rc;
+ struct db_syscall_list *sys;
+ struct db_syscall_list *sys_prev = NULL;
+ struct db_syscall_list *sys_new = NULL;
+ struct db_syscall_arg_list *s_arg;
+ struct db_syscall_arg_list *s_arg_prev = NULL;
+ struct db_syscall_arg_list *s_arg_new = NULL;
+ struct db_syscall_arg_val_list *a_val;
+ struct db_syscall_arg_val_list *a_val_prev=NULL;
+ struct db_syscall_arg_val_list *a_val_new=NULL;
+
+ assert(db != NULL);
+
+ /* check the opposite action list first to prevent problems later */
+ sys = (action == SCMP_ACT_ALLOW ? db->sys_deny : db->sys_allow);
+ while (sys != NULL && sys->num < syscall)
+ sys = sys->next;
+ if (sys != NULL && sys->num == syscall)
+ return -EEXIST;
+
+ /* add the filter to the correct list if it isn't already present */
+
+ /* find the syscall */
+ sys = (action == SCMP_ACT_ALLOW ? db->sys_allow : db->sys_deny);
+ while (sys != NULL && sys->num < syscall) {
+ sys_prev = sys;
+ sys = sys->next;
+ }
+ if (sys == NULL || sys->num != syscall) {
+ sys_new = malloc(sizeof(*sys_new));
+ if (sys_new == NULL) {
+ rc = -ENOMEM;
+ goto db_add_syscall_args_failure;
+ }
+ memset(sys_new, 0, sizeof(*sys_new));
+ sys_new->num = syscall;
+ sys = sys_new;
+ } else if (!override && sys->args == NULL) {
+ /* if override is false, we don't want to restrict a syscall
+ * only (no arguments specified) filter so fail out */
+ rc = -EEXIST;
+ goto db_add_syscall_args_failure;
+ }
+ /* find the argument */
+ s_arg = sys->args;
+ while (s_arg != NULL && s_arg->num < arg) {
+ s_arg_prev = s_arg;
+ s_arg = s_arg->next;
+ }
+ if (s_arg == NULL || s_arg->num != arg) {
+ /* new argument filter */
+ s_arg_new = malloc(sizeof(*s_arg_new));
+ if (s_arg_new == NULL) {
+ rc = -ENOMEM;
+ goto db_add_syscall_args_failure;
+ }
+ memset(s_arg_new, 0, sizeof(*s_arg_new));
+ s_arg_new->num = arg;
+ a_val = malloc(sizeof(*a_val));
+ if (a_val == NULL) {
+ rc = -ENOMEM;
+ goto db_add_syscall_args_failure;
+ }
+ memset(a_val, 0, sizeof(*a_val));
+ a_val->op = op;
+ a_val->datum = datum;
+ s_arg_new->values = a_val;
+ s_arg = s_arg_new;
+ } else {
+ /* existing argument filter */
+ a_val = s_arg->values;
+ while (a_val != NULL && a_val->datum != datum) {
+ a_val_prev = a_val;
+ a_val = a_val->next;
+ }
+ if (a_val == NULL) {
+ /* new argument value */
+ a_val_new = malloc(sizeof(*a_val_new));
+ if (a_val_new == NULL) {
+ rc = -ENOMEM;
+ goto db_add_syscall_args_failure;
+ }
+ memset(a_val_new, 0, sizeof(*a_val_new));
+ a_val_new->op = op;
+ a_val_new->datum = datum;
+ } else
+ /* filter already exists, just return */
+ return 0;
+ }
+
+ /* if necessary, add the new filter pieces to the filter db */
+ if (a_val_new != NULL) {
+ if (a_val_prev == NULL)
+ s_arg->values = a_val_new;
+ else
+ a_val_prev->next = a_val_new;
+ }
+ if (s_arg_new != NULL) {
+ if (s_arg_prev == NULL) {
+ sys->args = s_arg_new;
+ } else {
+ s_arg_new->next = s_arg_prev->next;
+ s_arg_prev->next = s_arg_new;
+ }
+ }
+ if (sys_new != NULL) {
+ if (sys_prev == NULL) {
+ if (action == SCMP_ACT_ALLOW)
+ db->sys_allow = sys_new;
+ else
+ db->sys_deny = sys_new;
+ } else {
+ sys_new->next = sys_prev->next;
+ sys_prev->next = sys_new;
+ }
+ }
+
+ return 0;
+
+db_add_syscall_args_failure:
+ if (a_val_new)
+ free(a_val_new);
+ if (s_arg_new)
+ free(s_arg_new);
+ if (sys_new)
+ free(sys_new);
+ return rc;
+}
+
+/**
+ * Find a syscall filter in the DB
+ * @param db the seccomp filter DB
+ * @param action the matching filter action
+ * @param syscall the syscall number
+ *
+ * This function searches the filter DB using the given action and syscall
+ * number and returns a pointer to the syscall filter or NULL if no matching
+ * syscall filter exists.
+ *
+ */
+struct db_syscall_list *seccomp_db_find_syscall(const struct db_filter *db,
+ enum scmp_flt_action action,
+ unsigned int syscall)
+{
+ struct db_syscall_list *iter;
+
+ assert(db != NULL);
+
+ iter = (action == SCMP_ACT_ALLOW ? db->sys_allow : db->sys_deny);
+ while (iter != NULL && iter->num < syscall)
+ iter = iter->next;
+ if (iter != NULL && iter->num == syscall)
+ return iter;
+
+ return NULL;
+}
+
+/**
+ * Find a syscall filter in the DB
+ * @param db the seccomp filter DB
+ * @param syscall the syscall number
+ *
+ * This function searches the filter DB for all possible actions using the
+ * given syscall number and returns a pointer to the syscall filter or NULL if
+ * no matching syscall filter exists.
+ *
+ */
+struct db_syscall_list *seccomp_db_find_syscall_all(const struct db_filter *db,
+ unsigned int syscall)
+{
+ struct db_syscall_list *iter;
+
+ assert(db != NULL);
+
+ iter = seccomp_db_find_syscall(db, SCMP_ACT_ALLOW, syscall);
+ if (iter != NULL)
+ return iter;
+ return seccomp_db_find_syscall(db, SCMP_ACT_DENY, syscall);
+}
diff --git a/src/filter_db.h b/src/filter_db.h
new file mode 100644
index 0000000..ca168be
--- /dev/null
+++ b/src/filter_db.h
@@ -0,0 +1,98 @@
+/**
+ * Enhanced Seccomp Filter DB
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _FILTER_DB_H
+#define _FILTER_DB_H
+
+#include <seccomp.h>
+
+/* XXX - need to provide doxygen comments for the types here */
+
+struct db_syscall_arg_val_list {
+ /* comparison operator */
+ enum scmp_compare op;
+ /* syscall argument value */
+ /* XXX - this could change, just need something big enough to hold any
+ * syscall argument */
+ unsigned long datum;
+
+ struct db_syscall_arg_val_list *next;
+};
+
+struct db_syscall_arg_list {
+ /* argument number (a0 = 0, a1 = 1, etc.) */
+ unsigned int num;
+ /* list of permissible values, kept as an unsorted single-linked list */
+ struct db_syscall_arg_val_list *values;
+
+ struct db_syscall_arg_list *next;
+};
+
+struct db_syscall_list {
+ /* native syscall number */
+ unsigned int num;
+ /* list of args, kept as a sorted single-linked list (optional) */
+ struct db_syscall_arg_list *args;
+
+ struct db_syscall_list *next;
+};
+
+struct db_filter {
+ /* action to take if we don't match an explicit allow/deny */
+ enum scmp_flt_action def_action;
+
+ /* syscall filters, kept as a sorted single-linked list */
+ struct db_syscall_list *sys_allow;
+ struct db_syscall_list *sys_deny;
+};
+
+/**
+ * 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)
+
+struct db_filter *seccomp_db_new(enum scmp_flt_action def_action);
+void seccomp_db_destroy(struct db_filter *db);
+
+int seccomp_db_add_syscall(struct db_filter *db,
+ enum scmp_flt_action action, unsigned int syscall,
+ unsigned int override);
+int seccomp_db_add_syscall_arg(struct db_filter *db,
+ enum scmp_flt_action action,
+ unsigned int syscall,
+ unsigned int arg,
+ enum scmp_compare op, unsigned long datum,
+ unsigned int override);
+
+struct db_syscall_list *seccomp_db_find_syscall(const struct db_filter *db,
+ enum scmp_flt_action action,
+ unsigned int syscall);
+struct db_syscall_list *seccomp_db_find_syscall_all(const struct db_filter *db,
+ unsigned int syscall);
+
+#endif \ No newline at end of file
diff --git a/src/library_api.c b/src/library_api.c
new file mode 100644
index 0000000..9141044
--- /dev/null
+++ b/src/library_api.c
@@ -0,0 +1,192 @@
+/**
+ * Seccomp Library API
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/prctl.h>
+
+#include <seccomp.h>
+
+#include "filter_db.h"
+#include "translator_str.h"
+#include "translator_bpf.h"
+
+/* XXX - we need a way to handle things like socketcall() so devs don't have
+ * to worry about underlying arch/platform oddities */
+
+/* the underlying code supports multiple simultaneous seccomp filters, but in
+ * practice we really only need one per-process right now, and this is it */
+static struct db_filter *filter = NULL;
+
+/**
+ * Initialize or reset the filter state
+ * @param def_action the default filter action
+ *
+ * This function initializes or resets the internal seccomp filter state and
+ * should be called before any other functions in this library to ensure the
+ * filter state is initialized. This function does not reset any seccomp
+ * filters already loaded into the kernel. Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int seccomp_reset(enum scmp_flt_action def_action)
+{
+ if (filter != NULL)
+ seccomp_db_destroy(filter);
+ filter = seccomp_db_new(def_action);
+
+ return (filter ? 0 : -ENOMEM);
+}
+
+/**
+ * Destroys the filter state and releases any resources
+ *
+ * This functions destroys the internal 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 function seccomp_reset() must be called before the filter can be
+ * reconfigured after calling this function.
+ *
+ */
+void seccomp_release(void)
+{
+ if (filter == NULL)
+ return;
+
+ seccomp_db_destroy(filter);
+ filter = NULL;
+}
+
+/**
+ * Enables the currently configured seccomp filter
+ *
+ * This function loads the currently configured seccomp filter 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_enable(void)
+{
+ struct seccomp_fprog *fprog;
+
+ if (filter == NULL)
+ return -EFAULT;
+
+ fprog = seccomp_bpf_generate(filter);
+ if (fprog == NULL)
+ return -ENOMEM;
+ if (prctl(PR_ATTACH_SECCOMP_FILTER, fprog) < 0)
+ return errno;
+
+ return 0;
+}
+
+/**
+ * Add a syscall to the existing filter
+ * @param action the filter action
+ * @param syscall the syscall number
+ *
+ * This function adds a new syscall to the seccomp filter. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int seccomp_add_syscall(enum scmp_flt_action action, int syscall)
+{
+ if (filter == NULL)
+ return -EFAULT;
+
+ /* XXX - negative syscall values are going to be considered "special",
+ * e.g. all the socketcall() syscalls on x86 will be represented
+ * with negative syscall numbers - we need a thin shim layer
+ * here to convert these pseudo syscalls into real filters (check
+ * the a0 value, etc.) */
+
+ return seccomp_db_add_syscall(filter, action, syscall, 0);
+}
+
+/**
+ * Add a syscall and argument value to the existing filter
+ * @param action the filter action
+ * @param syscall the syscall number
+ * @param arg the argument number
+ * @param datum the argument value
+ *
+ * This function adds a new syscall/argument/value to the seccomp filter.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+int seccomp_add_syscall_arg(enum scmp_flt_action action, int syscall,
+ unsigned int arg,
+ enum scmp_compare op, unsigned long datum)
+{
+ if (filter == NULL)
+ return -EFAULT;
+
+ /* XXX - we should cap the maximum syscall argument? is there one? */
+
+ /* XXX - see note in seccomp_add_syscall() about negative syscall
+ * numbers */
+
+ return seccomp_db_add_syscall_arg(filter, action, syscall,
+ arg, op, datum, 0);
+}
+
+/**
+ * Generate seccomp pseudo filter code
+ * @param fd the destination fd
+ *
+ * This function generates seccomp pseudo filter code and writes it to the
+ * given fd. Returns zero on success, negative values on failure.
+ *
+ */
+int seccomp_gen_pfc(int fd)
+{
+ if (filter == NULL)
+ return -EFAULT;
+
+ return seccomp_str_generate(filter, fd);
+}
+
+/**
+ * Generate seccomp Berkley Packet Filter code
+ * @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_gen_bpf(int fd)
+{
+ struct seccomp_fprog *fprog;
+
+ if (filter == NULL)
+ return -EFAULT;
+
+ fprog = seccomp_bpf_generate(filter);
+ if (fprog == NULL)
+ return -ENOMEM;
+ if (write(fd, fprog->filter, fprog->len * sizeof(fprog->filter[0])) < 0)
+ return errno;
+
+ return 0;
+}
diff --git a/src/translator_bpf.c b/src/translator_bpf.c
new file mode 100644
index 0000000..d2029ef
--- /dev/null
+++ b/src/translator_bpf.c
@@ -0,0 +1,407 @@
+/**
+ * Seccomp BPF Translator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX - this file is a quick n' dirty hack that hasn't really been verified,
+ * it is almost certainly broken; even if it does work, it needs some
+ * serious cleanup */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <seccomp.h>
+
+#include "translator_bpf.h"
+#include "bpf_helper.h"
+#include "filter_db.h"
+
+#if 1
+/* XXX - provide our own macros for the following BPF statements, we probably
+ * want to just fixup the stuff in bpf_helper.h */
+#define _JUMP(labels, label) \
+ BPF_JUMP(BPF_JMP+BPF_JA, _FIND_LABEL(labels, label), JUMP_JT, JUMP_JF)
+#define _LABEL(labels, label) \
+ BPF_JUMP(BPF_JMP+BPF_JA, _FIND_LABEL(labels, label), LABEL_JT, LABEL_JF)
+#define _FIND_LABEL(labels, label) seccomp_bpf_label(labels, label)
+#define _SYSCALL(nr, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 1, 0), \
+ jt
+#endif
+
+/* allocation increment size */
+#define BPF_INCR (128 * sizeof(struct seccomp_filter_block))
+
+struct bpf_filter {
+ struct seccomp_fprog *prog;
+ size_t alloc_len;
+ struct bpf_labels lbls;
+};
+
+#define _bpf_blk_len(x) \
+ (sizeof(x) / sizeof(x[0]))
+
+#define _bpf_next(x) \
+ ((x)->prog->filter[(x)->prog->len])
+
+/**
+ * Append a new block of instructions to the BPF
+ * @param x pointer to a bpf_filter struct
+ * @param y new instruction block
+ */
+#define _bpf_append(x,y) \
+ do { \
+ memcpy(&_bpf_next(x), &(y), sizeof(y)); \
+ (x)->prog->len += _bpf_blk_len(y); \
+ } while (0)
+
+/**
+ * Grow the maximum BPF filter program size
+ * @param bpf the bpf_filter struct
+ * @param len the requested length
+ *
+ * This functions checks to see if the BPF filter program space needs to be
+ * expanded to meet the requested size and realloc's the space if needed.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int _seccomp_bpf_grow(struct bpf_filter *bpf, size_t len)
+{
+ void *buf;
+ size_t buf_len = bpf->alloc_len + (BPF_INCR > len ? BPF_INCR : len);
+
+ if (bpf->prog->len + len <= bpf->alloc_len)
+ return 0;
+
+ /* XXX - check to make sure the size isn't getting too large */
+ /* XXX - is there a size limit? */
+
+ buf = realloc(bpf->prog->filter, buf_len);
+ if (buf == NULL) {
+ free(bpf->prog->filter);
+ bpf->prog->filter = NULL;
+ bpf->prog->len = 0;
+ bpf->alloc_len = 0;
+ return -ENOMEM;
+ }
+ bpf->prog->filter = buf;
+ bpf->alloc_len = buf_len;
+ return 0;
+}
+
+/**
+ * Append BPF instructions to the main BPF program
+ * @param bpf the bpf_filter struct
+ * @param blk the new BPF instruction block
+ * @param blk_len length of the new BPF instruction block
+ *
+ * This function appends the given set of BPF instructions to the main BPF
+ * program, growing the allocated size if necessary. Returns zero on success,
+ * negative values on error.
+ *
+ */
+static int _seccomp_bpf_append(struct bpf_filter *bpf,
+ const struct seccomp_filter_block *blk,
+ size_t blk_len)
+{
+ int rc = _seccomp_bpf_grow(bpf, blk_len);
+ if (rc < 0)
+ return rc;
+ _bpf_append(bpf, blk);
+ return 0;
+}
+
+/**
+ * Generate BPF for the syscall argument
+ * @param act the filter action
+ * @param arg the syscall argument
+ * @param bpf the bpf_filter struct
+ *
+ * This function generates BPF for the given syscall argument and action.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int _seccomp_pbf_syscall_arg(enum scmp_flt_action act,
+ struct db_syscall_arg_list *arg,
+ struct bpf_filter *bpf)
+{
+ int rc;
+ struct db_syscall_arg_val_list *v_iter;
+
+ /* load the argument */
+ {
+ struct seccomp_filter_block blk[] = {
+ ARG(arg->num),
+ };
+ rc = _seccomp_bpf_append(bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ }
+
+ /* check against our argument value list */
+ db_list_foreach(v_iter, arg->values) {
+ if (act == SCMP_ACT_ALLOW) {
+ if (v_iter->op == SCMP_CMP_NE) {
+ struct seccomp_filter_block blk[] = {
+ JNE(v_iter->datum, ALLOW),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_LT) {
+ struct seccomp_filter_block blk[] = {
+ JLT(v_iter->datum, ALLOW),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_LE) {
+ struct seccomp_filter_block blk[] = {
+ JLE(v_iter->datum, ALLOW),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_EQ) {
+ struct seccomp_filter_block blk[] = {
+ JEQ(v_iter->datum, ALLOW),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_GE) {
+ struct seccomp_filter_block blk[] = {
+ JGE(v_iter->datum, ALLOW),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_GT) {
+ struct seccomp_filter_block blk[] = {
+ JGT(v_iter->datum, ALLOW),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else
+ return -EFAULT;
+ } else {
+ if (v_iter->op == SCMP_CMP_NE) {
+ struct seccomp_filter_block blk[] = {
+ JNE(v_iter->datum, DENY),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_LT) {
+ struct seccomp_filter_block blk[] = {
+ JLT(v_iter->datum, DENY),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_LE) {
+ struct seccomp_filter_block blk[] = {
+ JLE(v_iter->datum, DENY),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_EQ) {
+ struct seccomp_filter_block blk[] = {
+ JEQ(v_iter->datum, DENY),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_GE) {
+ struct seccomp_filter_block blk[] = {
+ JGE(v_iter->datum, DENY),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else if (v_iter->op == SCMP_CMP_GT) {
+ struct seccomp_filter_block blk[] = {
+ JGT(v_iter->datum, DENY),
+ };
+ rc = _seccomp_bpf_append(bpf, blk,
+ _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Generate BPF for a syscall filter
+ * @param act the filter action
+ * @param sys the system call filter
+ * @param bpf the bpf_filter struct
+ *
+ * This function generates BPF for the given syscall filter and action.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int _seccomp_bpf_syscall(enum scmp_flt_action act,
+ const struct db_syscall_list *sys,
+ struct bpf_filter *bpf)
+{
+ int rc;
+ char lbl_end[256]; /* XXX - ungh */
+ struct db_syscall_arg_list *a_iter;
+
+ /* XXX - not the current limit on labels in bpf_helper.{c,h} */
+ snprintf(lbl_end, 256, "syscall_%d_end", sys->num); /* XXX - ungh^2 */
+
+ if (sys->args == NULL) {
+ if (act == SCMP_ACT_ALLOW) {
+ struct seccomp_filter_block blk[] = {
+ _SYSCALL(sys->num, _JUMP(&bpf->lbls, lbl_end)),
+ ALLOW,
+ _LABEL(&bpf->lbls, lbl_end),
+ };
+ rc = _seccomp_bpf_append(bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ } else {
+ struct seccomp_filter_block blk[] = {
+ _SYSCALL(sys->num, _JUMP(&bpf->lbls, lbl_end)),
+ DENY,
+ _LABEL(&bpf->lbls, lbl_end),
+ };
+ rc = _seccomp_bpf_append(bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ }
+ } else {
+ {
+ struct seccomp_filter_block blk[] = {
+ _SYSCALL(sys->num, _JUMP(&bpf->lbls, lbl_end)),
+ };
+ rc = _seccomp_bpf_append(bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ }
+
+ /* iterate over the arguments */
+ db_list_foreach(a_iter, sys->args) {
+ rc = _seccomp_pbf_syscall_arg(act, a_iter, bpf);
+ if (rc < 0)
+ return rc;
+ }
+
+ {
+ struct seccomp_filter_block blk[] = {
+ _LABEL(&bpf->lbls, lbl_end),
+ };
+ rc = _seccomp_bpf_append(bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Generate a BPF representation of the filter DB
+ * @param db the seccomp filter DB
+ *
+ * This function generates a BPF representation of the given filter DB.
+ * Returns a pointer to a valid seccomp_fprog on success, NULL on failure.
+ *
+ */
+struct seccomp_fprog *seccomp_bpf_generate(const struct db_filter *db)
+{
+ int rc;
+ struct bpf_filter bpf;
+ struct db_syscall_list *iter;
+
+ memset(&bpf, 0, sizeof(bpf));
+
+ bpf.prog = malloc(sizeof(*bpf.prog));
+ if (bpf.prog == NULL)
+ return NULL;
+ memset(&bpf.prog, 0, sizeof(*bpf.prog));
+
+ /* XXX - assume we can get away with LOAD_SYSCALL_NR just at the top,
+ * which may be wrong */
+ /* load the syscall */
+ {
+ struct seccomp_filter_block blk[] = {
+ LOAD_SYSCALL_NR,
+ };
+ rc = _seccomp_bpf_append(&bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ goto bpf_generate_failure;
+ }
+
+ db_list_foreach(iter, db->sys_deny)
+ _seccomp_bpf_syscall(SCMP_ACT_DENY, iter, &bpf);
+ db_list_foreach(iter, db->sys_deny)
+ _seccomp_bpf_syscall(SCMP_ACT_ALLOW, iter, &bpf);
+
+ /* default action */
+ if (db->def_action == SCMP_ACT_ALLOW) {
+ struct seccomp_filter_block blk[] = {
+ ALLOW,
+ };
+ rc = _seccomp_bpf_append(&bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ goto bpf_generate_failure;
+ } else {
+ struct seccomp_filter_block blk[] = {
+ DENY,
+ };
+ rc = _seccomp_bpf_append(&bpf, blk, _bpf_blk_len(blk));
+ if (rc == 0)
+ goto bpf_generate_failure;
+ }
+
+ /* resolve the labels/jumps */
+ rc = bpf_resolve_jumps(&bpf.lbls,
+ bpf.prog->filter,
+ _bpf_blk_len(bpf.prog->filter));
+ if (rc != 0)
+ goto bpf_generate_failure;
+
+ return bpf.prog;
+
+bpf_generate_failure:
+ free(bpf.prog);
+ return NULL;
+} \ No newline at end of file
diff --git a/src/translator_bpf.h b/src/translator_bpf.h
new file mode 100644
index 0000000..6a34e1b
--- /dev/null
+++ b/src/translator_bpf.h
@@ -0,0 +1,36 @@
+/**
+ * Seccomp BPF Translator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TRANSLATOR_BPF_H
+#define _TRANSLATOR_BPF_H
+
+#if 0
+#include <linux/seccomp_filter.h>
+#else
+/* XXX - needed for early development only */
+#include <seccomp_filter.h>
+#endif
+
+#include "filter_db.h"
+
+struct seccomp_fprog *seccomp_bpf_generate(const struct db_filter *db);
+
+#endif
diff --git a/src/translator_str.c b/src/translator_str.c
new file mode 100644
index 0000000..0a63954
--- /dev/null
+++ b/src/translator_str.c
@@ -0,0 +1,141 @@
+/**
+ * Seccomp String Translator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <seccomp.h>
+
+#include "filter_db.h"
+#include "translator_str.h"
+
+/* XXX - we should check the fprintf() return values */
+
+/**
+ * Display a string representation of the filter action
+ * @param action the action
+ */
+#define _str_action(action) \
+ ((action) == SCMP_ACT_ALLOW ? "ALLOW" : "DENY")
+
+/**
+ * Generate pseudo filter code for a syscall
+ * @param act the filter action
+ * @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 fd. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+static int _seccomp_str_syscall(enum scmp_flt_action act,
+ const struct db_syscall_list *sys, FILE *fds)
+{
+ unsigned int sys_num = sys->num;
+ struct db_syscall_arg_list *a_iter;
+ struct db_syscall_arg_val_list *v_iter;
+ char *op_str;
+
+ char op_str_ne[] = "!=";
+ char op_str_lt[] = "<";
+ char op_str_le[] = "<=";
+ char op_str_eq[] = "==";
+ char op_str_ge[] = ">=";
+ char op_str_gt[] = ">";
+ char op_str_un[] = "??";
+
+ fprintf(fds, "# filter code for syscall #%d\n", sys_num);
+ fprintf(fds, " if (syscall != %d) goto syscall_%d_end;\n",
+ sys_num, sys_num);
+ if (sys->args != NULL) {
+ db_list_foreach(a_iter, sys->args) {
+ db_list_foreach(v_iter, a_iter->values) {
+ switch (v_iter->op) {
+ case SCMP_CMP_NE:
+ op_str = op_str_ne;
+ break;
+ case SCMP_CMP_LT:
+ op_str = op_str_lt;
+ break;
+ case SCMP_CMP_LE:
+ op_str = op_str_le;
+ break;
+ case SCMP_CMP_EQ:
+ op_str = op_str_eq;
+ break;
+ case SCMP_CMP_GE:
+ op_str = op_str_ge;
+ break;
+ case SCMP_CMP_GT:
+ op_str = op_str_gt;
+ break;
+ default:
+ op_str = op_str_un;
+ }
+ fprintf(fds, " if (a%d %s 0x%lx) action %s;\n",
+ a_iter->num,
+ op_str,
+ v_iter->datum,
+ _str_action(act));
+ }
+ }
+ } else
+ fprintf(fds, " action %s;\n", _str_action(act));
+ fprintf(fds, " syscall_%d_end:\n", sys_num);
+
+ return 0;
+}
+
+/**
+ * Generate a pseudo filter code string representation
+ * @param db the seccomp filter DB
+ * @param fd the fd to send the output
+ *
+ * This function generates a pseudo filter code representation of the given
+ * filter DB and writes it to the given fd. Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int seccomp_str_generate(const struct db_filter *db, int fd)
+{
+ FILE *fds;
+ struct db_syscall_list *iter;
+
+ fds = fdopen(fd, "a+");
+ if (fds == NULL)
+ return errno;
+
+ fprintf(fds, "# filter pseudo code start\n");
+ fprintf(fds, "#\n");
+ db_list_foreach(iter, db->sys_deny)
+ _seccomp_str_syscall(SCMP_ACT_DENY, iter, fds);
+ db_list_foreach(iter, db->sys_allow)
+ _seccomp_str_syscall(SCMP_ACT_ALLOW, iter, fds);
+ fprintf(fds, "# default action\n");
+ fprintf(fds, " action %s;\n", _str_action(db->def_action));
+ fprintf(fds, "#\n");
+ fprintf(fds, "# filter pseudo code end\n");
+
+ fflush(fds);
+ return 0;
+}
diff --git a/src/translator_str.h b/src/translator_str.h
new file mode 100644
index 0000000..bdedd9a
--- /dev/null
+++ b/src/translator_str.h
@@ -0,0 +1,29 @@
+/**
+ * Seccomp String Translator
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TRANSLATOR_STR_H
+#define _TRANSLATOR_STR_H
+
+#include "filter_db.h"
+
+int seccomp_str_generate(const struct db_filter *db, int fd);
+
+#endif \ No newline at end of file
diff --git a/tests/01-basic.c b/tests/01-basic.c
new file mode 100644
index 0000000..e401a5c
--- /dev/null
+++ b/tests/01-basic.c
@@ -0,0 +1,37 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <seccomp.h>
+
+int main(int argc, char *argv[])
+{
+ int rc;
+
+ rc = seccomp_reset(SCMP_ACT_ALLOW);
+ if (rc != 0)
+ return rc;
+
+ seccomp_release();
+ return rc;
+} \ No newline at end of file
diff --git a/tests/02-basic-pfc.c b/tests/02-basic-pfc.c
new file mode 100644
index 0000000..8e49e74
--- /dev/null
+++ b/tests/02-basic-pfc.c
@@ -0,0 +1,61 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <pmoore@redhat.com>
+ */
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <seccomp.h>
+
+int main(int argc, char *argv[])
+{
+ int rc;
+
+ rc = seccomp_reset(SCMP_ACT_DENY);
+ if (rc != 0)
+ return rc;
+
+
+ rc = seccomp_add_syscall(SCMP_ACT_ALLOW, SCMP_SYS(read));
+ if (rc != 0)
+ return rc;
+ rc = seccomp_add_syscall_arg(SCMP_ACT_ALLOW, SCMP_SYS(write),
+ 0, SCMP_CMP_EQ, 1 /* stdout */);
+ if (rc != 0)
+ return rc;
+ rc = seccomp_add_syscall_arg(SCMP_ACT_ALLOW, SCMP_SYS(write),
+ 0, SCMP_CMP_EQ, 2 /* stderr */);
+ if (rc != 0)
+ return rc;
+ rc = seccomp_add_syscall(SCMP_ACT_ALLOW, SCMP_SYS(close));
+ if (rc != 0)
+ return rc;
+ rc = seccomp_add_syscall(SCMP_ACT_DENY, SCMP_SYS(open));
+ if (rc != 0)
+ return rc;
+
+ rc = seccomp_gen_pfc(STDOUT_FILENO);
+ if (rc != 0)
+ return rc;
+
+ seccomp_release();
+ return rc;
+} \ No newline at end of file
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..a6a4da2
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,61 @@
+#
+# Enhanced Seccomp Library Makefile
+#
+# Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <pmoore@redhat.com>
+#
+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# macros
+#
+
+#
+# macros
+#
+
+include ../macros.mk
+
+#
+# configuration
+#
+
+include ../version_info
+
+INCFLAGS := $(INCFLAGS) -I../include
+LDFLAGS := ../src/libseccomp.a
+
+TESTS = 01-basic \
+ 02-basic-pfc
+
+#
+# targets
+#
+
+.PHONY: clean
+
+all: $(TESTS)
+
+# XXX - find a better way to do this using $(TESTS)
+
+01-basic: 01-basic.c
+ $(COMPILE_EXEC)
+
+02-basic-pfc: 02-basic-pfc.c
+ $(COMPILE_EXEC)
+
+clean:
+ $(RM) -f $(TESTS)
diff --git a/version_info b/version_info
new file mode 100644
index 0000000..5598adc
--- /dev/null
+++ b/version_info
@@ -0,0 +1,6 @@
+#
+# version_info - version information for the various netlabel tool components
+#
+
+# release
+VERSION_RELEASE=X.XX