Project import
diff --git a/minijail/.clang-format b/minijail/.clang-format
new file mode 100644
index 0000000..a3ef233
--- /dev/null
+++ b/minijail/.clang-format
@@ -0,0 +1,6 @@
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Linux
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
diff --git a/minijail/Android.mk b/minijail/Android.mk
new file mode 100644
index 0000000..d3fadcc
--- /dev/null
+++ b/minijail/Android.mk
@@ -0,0 +1,315 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+
+# Common variables.
+# =========================================================
+libminijailSrcFiles := \
+	bpf.c \
+	libminijail.c \
+	signal_handler.c \
+	syscall_filter.c \
+	util.c
+
+hostUnittestSrcFiles := \
+	linux-x86/libconstants.gen.c \
+	linux-x86/libsyscalls.gen.c
+
+minijailCommonCFlags := -DHAVE_SECUREBITS_H -Wall -Werror
+minijailCommonLibraries := libcap
+
+# Android devices running kernel version < 3.8 are not required to
+# support seccomp. Brillo devices must support seccomp regardless of
+# kernel version.
+# TODO: remove when no longer supporting kernel versions < 3.8.
+ifndef BRILLO
+minijailCommonCFlags += -DUSE_SECCOMP_SOFTFAIL
+endif
+
+
+# Static library for generated code.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libminijail_generated
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+generated_sources_dir := $(local-generated-sources-dir)
+
+my_gen := $(generated_sources_dir)/$(TARGET_ARCH)/libsyscalls.c
+# We need the quotes so the shell script treats the following as one argument.
+my_cc := "$(lastword $(CLANG)) \
+    $(addprefix -I ,$(TARGET_C_INCLUDES)) \
+    $(addprefix -isystem ,$(TARGET_C_SYSTEM_INCLUDES)) \
+    $(CLANG_TARGET_GLOBAL_CFLAGS)"
+$(my_gen): PRIVATE_CC := $(my_cc)
+$(my_gen): PRIVATE_CUSTOM_TOOL = $< $(PRIVATE_CC) $@
+$(my_gen): $(LOCAL_PATH)/gen_syscalls.sh
+	$(transform-generated-source)
+$(call include-depfile,$(my_gen).d,$(my_gen))
+LOCAL_GENERATED_SOURCES_$(TARGET_ARCH) += $(my_gen)
+
+my_gen := $(generated_sources_dir)/$(TARGET_ARCH)/libconstants.c
+$(my_gen): PRIVATE_CC := $(my_cc)
+$(my_gen): PRIVATE_CUSTOM_TOOL = $< $(PRIVATE_CC) $@
+$(my_gen): $(LOCAL_PATH)/gen_constants.sh
+	$(transform-generated-source)
+$(call include-depfile,$(my_gen).d,$(my_gen))
+LOCAL_GENERATED_SOURCES_$(TARGET_ARCH) += $(my_gen)
+
+# For processes running in 32-bit compat mode on 64-bit processors.
+ifdef TARGET_2ND_ARCH
+my_gen := $(generated_sources_dir)/$(TARGET_2ND_ARCH)/libsyscalls.c
+my_cc := "$(lastword $(CLANG)) \
+    $(addprefix -I ,$($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_C_INCLUDES)) \
+    $(addprefix -isystem ,$($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_C_SYSTEM_INCLUDES)) \
+    $($(TARGET_2ND_ARCH_VAR_PREFIX)CLANG_TARGET_GLOBAL_CFLAGS)"
+$(my_gen): PRIVATE_CC := $(my_cc)
+$(my_gen): PRIVATE_CUSTOM_TOOL = $< $(PRIVATE_CC) $@
+$(my_gen): $(LOCAL_PATH)/gen_syscalls.sh
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES_$(TARGET_2ND_ARCH) += $(my_gen)
+
+my_gen := $(generated_sources_dir)/$(TARGET_2ND_ARCH)/libconstants.c
+$(my_gen): PRIVATE_CC := $(my_cc)
+$(my_gen): PRIVATE_CUSTOM_TOOL = $< $(PRIVATE_CC) $@
+$(my_gen): $(LOCAL_PATH)/gen_constants.sh
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES_$(TARGET_2ND_ARCH) += $(my_gen)
+endif
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+include $(BUILD_STATIC_LIBRARY)
+
+
+# libminijail shared library for target.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libminijail
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := $(libminijailSrcFiles)
+
+LOCAL_STATIC_LIBRARIES := libminijail_generated
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+
+# Example ASan-ified libminijail shared library for target.
+# Commented out since it's only needed for local debugging.
+# =========================================================
+# include $(CLEAR_VARS)
+# LOCAL_MODULE := libminijail_asan
+# LOCAL_MODULE_TAGS := optional
+#
+# LOCAL_CFLAGS := $(minijailCommonCFlags)
+# LOCAL_CLANG := true
+# LOCAL_SANITIZE := address
+# LOCAL_MODULE_RELATIVE_PATH := asan
+# LOCAL_SRC_FILES := $(libminijailSrcFiles)
+#
+# LOCAL_STATIC_LIBRARIES := libminijail_generated
+# LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+# LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+# include $(BUILD_SHARED_LIBRARY)
+
+
+# libminijail static library for target.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libminijail
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := $(libminijailSrcFiles)
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libminijail_generated $(minijailCommonLibraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+
+# libminijail native unit tests. Run with:
+# adb shell /data/nativetest/libminijail_unittest/libminijail_unittest
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libminijail_unittest
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	bpf.c \
+	libminijail.c \
+	libminijail_unittest.c \
+	signal_handler.c \
+	syscall_filter.c \
+	util.c \
+
+LOCAL_STATIC_LIBRARIES := libminijail_generated
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+include $(BUILD_NATIVE_TEST)
+
+
+# libminijail native unit tests using gtest. Run with:
+# adb shell /data/nativetest/libminijail_unittest_gtest/libminijail_unittest_gtest
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libminijail_unittest_gtest
+
+LOCAL_CFLAGS := $(minijailCommonCFlags) -Wno-writable-strings
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	bpf.c \
+	libminijail.c \
+	signal_handler.c \
+	syscall_filter.c \
+	util.c \
+	libminijail_unittest.cpp \
+
+LOCAL_STATIC_LIBRARIES := libminijail_generated
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+include $(BUILD_NATIVE_TEST)
+
+
+# libminijail native unit tests for the host. Run with:
+# out/host/linux-x86/nativetest(64)/libminijail_unittest/libminijail_unittest
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libminijail_unittest
+LOCAL_MODULE_HOST_OS := linux
+
+LOCAL_CFLAGS := $(minijailCommonCFlags) -DPRELOADPATH=\"/invalid\"
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	bpf.c \
+	libminijail.c \
+	libminijail_unittest.c \
+	signal_handler.c \
+	syscall_filter.c \
+	util.c \
+	$(hostUnittestSrcFiles)
+
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+include $(BUILD_HOST_NATIVE_TEST)
+
+
+# Syscall filtering native unit tests. Run with:
+# adb shell /data/nativetest/syscall_filter_unittest/syscall_filter_unittest
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := syscall_filter_unittest
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	bpf.c \
+	syscall_filter.c \
+	syscall_filter_unittest.c \
+	util.c \
+
+LOCAL_STATIC_LIBRARIES := libminijail_generated
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+include $(BUILD_NATIVE_TEST)
+
+
+# Syscall filtering native unit tests using gtest. Run with:
+# adb shell /data/nativetest/syscall_filter_unittest_gtest/syscall_filter_unittest_gtest
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := syscall_filter_unittest_gtest
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	bpf.c \
+	syscall_filter.c \
+	util.c \
+	syscall_filter_unittest.cpp \
+
+LOCAL_STATIC_LIBRARIES := libminijail_generated
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+include $(BUILD_NATIVE_TEST)
+
+
+# Syscall filtering native unit tests for the host. Run with:
+# out/host/linux-x86/nativetest(64)/syscall_filter_unittest/syscall_filter_unittest
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := syscall_filter_unittest
+LOCAL_MODULE_HOST_OS := linux
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	bpf.c \
+	syscall_filter.c \
+	syscall_filter_unittest.c \
+	util.c \
+	$(hostUnittestSrcFiles)
+
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
+include $(BUILD_HOST_NATIVE_TEST)
+
+
+# libminijail_test executable for brillo_Minijail test.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libminijail_test
+
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	test/libminijail_test.cpp
+
+LOCAL_SHARED_LIBRARIES := libbase libminijail
+include $(BUILD_EXECUTABLE)
+
+
+# libminijail usage example.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := drop_privs
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(minijailCommonCFlags)
+LOCAL_CLANG := true
+# Don't build with ASan, but leave commented out for easy local debugging.
+# LOCAL_SANITIZE := address
+LOCAL_SRC_FILES := \
+	examples/drop_privs.cpp
+
+LOCAL_SHARED_LIBRARIES := libbase libminijail
+include $(BUILD_EXECUTABLE)
+
+
+# minijail0 executable.
+# This is not currently used on Brillo/Android,
+# but it's convenient to be able to build it.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := minijail0
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := \
+	$(minijailCommonCFlags) -Wno-missing-field-initializers \
+	-DPRELOADPATH=\"/invalidminijailpreload.so\"
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := \
+	elfparse.c \
+	minijail0.c \
+
+LOCAL_STATIC_LIBRARIES := libminijail_generated
+LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries) libminijail
+include $(BUILD_EXECUTABLE)
diff --git a/minijail/CPPLINT.cfg b/minijail/CPPLINT.cfg
new file mode 100644
index 0000000..51ff339
--- /dev/null
+++ b/minijail/CPPLINT.cfg
@@ -0,0 +1 @@
+exclude_files=.*
diff --git a/minijail/MODULE_LICENSE_BSD b/minijail/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/minijail/MODULE_LICENSE_BSD
diff --git a/minijail/Makefile b/minijail/Makefile
new file mode 100644
index 0000000..25e6494
--- /dev/null
+++ b/minijail/Makefile
@@ -0,0 +1,79 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
+
+LIBDIR ?= lib
+PRELOADNAME = libminijailpreload.so
+PRELOADPATH = \"/$(LIBDIR)/$(PRELOADNAME)\"
+CPPFLAGS += -DPRELOADPATH="$(PRELOADPATH)"
+
+ifneq ($(HAVE_SECUREBITS_H),no)
+CPPFLAGS += -DHAVE_SECUREBITS_H
+endif
+ifneq ($(USE_seccomp),yes)
+CPPFLAGS += -DUSE_SECCOMP_SOFTFAIL
+endif
+
+all: CC_BINARY(minijail0) CC_LIBRARY(libminijail.so) \
+		CC_LIBRARY(libminijailpreload.so)
+
+# TODO(jorgelo): convert to TEST().
+tests: CC_BINARY(libminijail_unittest) CC_BINARY(syscall_filter_unittest)
+
+CC_BINARY(minijail0): LDLIBS += -lcap -ldl
+CC_BINARY(minijail0): libconstants.gen.o libsyscalls.gen.o libminijail.o \
+		syscall_filter.o signal_handler.o bpf.o util.o elfparse.o minijail0.o
+clean: CLEAN(minijail0)
+
+CC_LIBRARY(libminijail.so): LDLIBS += -lcap
+CC_LIBRARY(libminijail.so): libminijail.o syscall_filter.o signal_handler.o \
+    bpf.o util.o libconstants.gen.o libsyscalls.gen.o
+clean: CLEAN(libminijail.so)
+
+CC_BINARY(libminijail_unittest): LDLIBS += -lcap
+CC_BINARY(libminijail_unittest): libminijail_unittest.o libminijail.o \
+		syscall_filter.o signal_handler.o bpf.o util.o libconstants.gen.o \
+		libsyscalls.gen.o
+clean: CLEAN(libminijail_unittest)
+
+CC_LIBRARY(libminijailpreload.so): LDLIBS += -lcap -ldl
+CC_LIBRARY(libminijailpreload.so): libminijailpreload.o libminijail.o \
+		libconstants.gen.o libsyscalls.gen.o syscall_filter.o signal_handler.o \
+		bpf.o util.o
+clean: CLEAN(libminijailpreload.so)
+
+CC_BINARY(syscall_filter_unittest): syscall_filter_unittest.o syscall_filter.o \
+		bpf.o util.o libconstants.gen.o libsyscalls.gen.o
+clean: CLEAN(syscall_filter_unittest)
+
+libsyscalls.gen.o: CPPFLAGS += -I$(SRC)
+
+libsyscalls.gen.o.depends: libsyscalls.gen.c
+
+# Only regenerate libsyscalls.gen.c if the Makefile or header changes.
+# NOTE! This will not detect if the file is not appropriate for the target.
+# TODO(jorgelo): fix generation when 'CC' env variable is not set.
+libsyscalls.gen.c: $(SRC)/Makefile $(SRC)/libsyscalls.h
+	@printf "Generating target-arch specific $@... "
+	$(QUIET)$(SRC)/gen_syscalls.sh $@
+	@printf "done.\n"
+clean: CLEAN(libsyscalls.gen.c)
+
+$(eval $(call add_object_rules,libsyscalls.gen.o,CC,c,CFLAGS))
+
+libconstants.gen.o: CPPFLAGS += -I$(SRC)
+
+libconstants.gen.o.depends: libconstants.gen.c
+
+# Only regenerate libconstants.gen.c if the Makefile or header changes.
+# NOTE! This will not detect if the file is not appropriate for the target.
+# TODO(jorgelo): fix generation when 'CC' env variable is not set.
+libconstants.gen.c: $(SRC)/Makefile $(SRC)/libconstants.h
+	@printf "Generating target-arch specific $@... "
+	$(QUIET)$(SRC)/gen_constants.sh $@
+	@printf "done.\n"
+clean: CLEAN(libconstants.gen.c)
+
+$(eval $(call add_object_rules,libconstants.gen.o,CC,c,CFLAGS))
diff --git a/minijail/NOTICE b/minijail/NOTICE
new file mode 100644
index 0000000..b9e779f
--- /dev/null
+++ b/minijail/NOTICE
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/minijail/OWNERS b/minijail/OWNERS
new file mode 100644
index 0000000..1b8effe
--- /dev/null
+++ b/minijail/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+jorgelo@chromium.org
+wad@chromium.org
diff --git a/minijail/PRESUBMIT.cfg b/minijail/PRESUBMIT.cfg
new file mode 100644
index 0000000..17f9b03
--- /dev/null
+++ b/minijail/PRESUBMIT.cfg
@@ -0,0 +1,4 @@
+[Hook Overrides]
+
+# We are using Linux-style indentation with tabs
+tab_check: false
diff --git a/minijail/arch.h b/minijail/arch.h
new file mode 100644
index 0000000..652f072
--- /dev/null
+++ b/minijail/arch.h
@@ -0,0 +1,65 @@
+/* arch.h
+ * Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * ARCH_NR #define's.
+ */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include <linux/audit.h>
+
+#if defined(__i386__)
+#  define ARCH_NR AUDIT_ARCH_I386
+#elif defined(__x86_64__)
+#  define ARCH_NR AUDIT_ARCH_X86_64
+#elif defined(__arm__)
+/*
+ * <linux/audit.h> includes <linux/elf-em.h>, which does not define EM_ARM.
+ * <linux/elf.h> only includes <asm/elf.h> if we're in the kernel.
+ */
+#  ifndef EM_ARM
+#    define EM_ARM 40
+#  endif
+#  define ARCH_NR AUDIT_ARCH_ARM
+#elif defined(__aarch64__)
+#  define ARCH_NR AUDIT_ARCH_AARCH64
+#elif defined(__hppa__)
+#  define ARCH_NR AUDIT_ARCH_PARISC
+#elif defined(__ia64__)
+#  define ARCH_NR AUDIT_ARCH_IA64
+#elif defined(__mips__)
+#  if defined(__mips64)
+#    if defined(__MIPSEB__)
+#      define ARCH_NR AUDIT_ARCH_MIPS64
+#    else
+#      define ARCH_NR AUDIT_ARCH_MIPSEL64
+#    endif
+#  else
+#    if defined(__MIPSEB__)
+#      define ARCH_NR AUDIT_ARCH_MIPS
+#    else
+#      define ARCH_NR AUDIT_ARCH_MIPSEL
+#    endif
+#  endif
+#elif defined(__powerpc64__)
+#  define ARCH_NR AUDIT_ARCH_PPC64
+#elif defined(__powerpc__)
+#  define ARCH_NR AUDIT_ARCH_PPC
+#elif defined(__s390x__)
+#  define ARCH_NR AUDIT_ARCH_S390X
+#elif defined(__s390__)
+#  define ARCH_NR AUDIT_ARCH_S390
+#elif defined(__sparc__)
+#  if defined(__arch64__)
+#    define AUDIT_ARCH_SPARC64
+#  else
+#    define AUDIT_ARCH_SPARC
+#  endif
+#else
+#  error "AUDIT_ARCH value unavailable"
+#endif
+
+#endif /* ARCH_H */
diff --git a/minijail/bpf.c b/minijail/bpf.c
new file mode 100644
index 0000000..20f2ed0
--- /dev/null
+++ b/minijail/bpf.c
@@ -0,0 +1,273 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bpf.h"
+
+/* Architecture validation. */
+size_t bpf_validate_arch(struct sock_filter *filter)
+{
+	struct sock_filter *curr_block = filter;
+	set_bpf_stmt(curr_block++, BPF_LD+BPF_W+BPF_ABS, arch_nr);
+	set_bpf_jump(curr_block++,
+			BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, SKIP, NEXT);
+	set_bpf_ret_kill(curr_block++);
+	return curr_block - filter;
+}
+
+/* Syscall number eval functions. */
+size_t bpf_allow_syscall(struct sock_filter *filter, int nr)
+{
+	struct sock_filter *curr_block = filter;
+	set_bpf_jump(curr_block++, BPF_JMP+BPF_JEQ+BPF_K, nr, NEXT, SKIP);
+	set_bpf_stmt(curr_block++, BPF_RET+BPF_K, SECCOMP_RET_ALLOW);
+	return curr_block - filter;
+}
+
+size_t bpf_allow_syscall_args(struct sock_filter *filter,
+		int nr, unsigned int id)
+{
+	struct sock_filter *curr_block = filter;
+	set_bpf_jump(curr_block++, BPF_JMP+BPF_JEQ+BPF_K, nr, NEXT, SKIP);
+	set_bpf_jump_lbl(curr_block++, id);
+	return curr_block - filter;
+}
+
+/* Size-aware arg loaders. */
+#if defined(BITS32)
+size_t bpf_load_arg(struct sock_filter *filter, int argidx)
+{
+	set_bpf_stmt(filter, BPF_LD+BPF_W+BPF_ABS, LO_ARG(argidx));
+	return 1U;
+}
+#elif defined(BITS64)
+size_t bpf_load_arg(struct sock_filter *filter, int argidx)
+{
+	struct sock_filter *curr_block = filter;
+	set_bpf_stmt(curr_block++, BPF_LD+BPF_W+BPF_ABS, LO_ARG(argidx));
+	set_bpf_stmt(curr_block++, BPF_ST, 0); /* lo -> M[0] */
+	set_bpf_stmt(curr_block++, BPF_LD+BPF_W+BPF_ABS, HI_ARG(argidx));
+	set_bpf_stmt(curr_block++, BPF_ST, 1); /* hi -> M[1] */
+	return curr_block - filter;
+}
+#endif
+
+/* Size-aware equality comparison. */
+size_t bpf_comp_jeq32(struct sock_filter *filter, unsigned long c,
+		unsigned char jt, unsigned char jf)
+{
+	unsigned int lo = (unsigned int)(c & 0xFFFFFFFF);
+	set_bpf_jump(filter, BPF_JMP+BPF_JEQ+BPF_K, lo, jt, jf);
+	return 1U;
+}
+
+/*
+ * On 64 bits, we have to do two 32-bit comparisons.
+ * We jump true when *both* comparisons are true.
+ */
+#if defined(BITS64)
+size_t bpf_comp_jeq64(struct sock_filter *filter, uint64_t c,
+		unsigned char jt, unsigned char jf)
+{
+	unsigned int lo = (unsigned int)(c & 0xFFFFFFFF);
+	unsigned int hi = (unsigned int)(c >> 32);
+
+	struct sock_filter *curr_block = filter;
+
+	/* bpf_load_arg leaves |hi| in A */
+	curr_block += bpf_comp_jeq32(curr_block, hi, NEXT, SKIPN(2) + jf);
+	set_bpf_stmt(curr_block++, BPF_LD+BPF_MEM, 0); /* swap in |lo| */
+	curr_block += bpf_comp_jeq32(curr_block, lo, jt, jf);
+
+	return curr_block - filter;
+}
+#endif
+
+/* Size-aware bitwise AND. */
+size_t bpf_comp_jset32(struct sock_filter *filter, unsigned long mask,
+		unsigned char jt, unsigned char jf)
+{
+	unsigned int mask_lo = (unsigned int)(mask & 0xFFFFFFFF);
+	set_bpf_jump(filter, BPF_JMP+BPF_JSET+BPF_K, mask_lo, jt, jf);
+	return 1U;
+}
+
+/*
+ * On 64 bits, we have to do two 32-bit bitwise ANDs.
+ * We jump true when *either* bitwise AND is true (non-zero).
+ */
+#if defined(BITS64)
+size_t bpf_comp_jset64(struct sock_filter *filter, uint64_t mask,
+		unsigned char jt, unsigned char jf)
+{
+	unsigned int mask_lo = (unsigned int)(mask & 0xFFFFFFFF);
+	unsigned int mask_hi = (unsigned int)(mask >> 32);
+
+	struct sock_filter *curr_block = filter;
+
+	/* bpf_load_arg leaves |hi| in A */
+	curr_block += bpf_comp_jset32(curr_block, mask_hi, SKIPN(2) + jt, NEXT);
+	set_bpf_stmt(curr_block++, BPF_LD+BPF_MEM, 0); /* swap in |lo| */
+	curr_block += bpf_comp_jset32(curr_block, mask_lo, jt, jf);
+
+	return curr_block - filter;
+}
+#endif
+
+size_t bpf_arg_comp(struct sock_filter **pfilter,
+		int op, int argidx, unsigned long c, unsigned int label_id)
+{
+	struct sock_filter *filter = calloc(BPF_ARG_COMP_LEN + 1,
+			sizeof(struct sock_filter));
+	struct sock_filter *curr_block = filter;
+	size_t (*comp_function)(struct sock_filter *filter, unsigned long k,
+				unsigned char jt, unsigned char jf);
+	int flip = 0;
+
+	/* Load arg */
+	curr_block += bpf_load_arg(curr_block, argidx);
+
+	/* Jump type */
+	switch (op) {
+	case EQ:
+		comp_function = bpf_comp_jeq;
+		flip = 0;
+		break;
+	case NE:
+		comp_function = bpf_comp_jeq;
+		flip = 1;
+		break;
+	case SET:
+		comp_function = bpf_comp_jset;
+		flip = 0;
+		break;
+	default:
+		*pfilter = NULL;
+		return 0;
+	}
+
+	/*
+	 * It's easier for the rest of the code to have the true branch
+	 * skip and the false branch fall through.
+	 */
+	unsigned char jt = flip ? NEXT : SKIP;
+	unsigned char jf = flip ? SKIP : NEXT;
+	curr_block += comp_function(curr_block, c, jt, jf);
+	curr_block += set_bpf_jump_lbl(curr_block, label_id);
+
+	*pfilter = filter;
+	return curr_block - filter;
+}
+
+void dump_bpf_filter(struct sock_filter *filter, unsigned short len)
+{
+	int i = 0;
+
+	printf("len == %d\n", len);
+	printf("filter:\n");
+	for (i = 0; i < len; i++) {
+		printf("%d: \t{ code=%#x, jt=%u, jf=%u, k=%#x \t}\n",
+			i, filter[i].code, filter[i].jt, filter[i].jf, filter[i].k);
+	}
+}
+
+void dump_bpf_prog(struct sock_fprog *fprog)
+{
+	struct sock_filter *filter = fprog->filter;
+	unsigned short len = fprog->len;
+	dump_bpf_filter(filter, len);
+}
+
+int bpf_resolve_jumps(struct bpf_labels *labels,
+		struct sock_filter *filter, size_t count)
+{
+	struct sock_filter *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.
+	 */
+	for (filter += insn; 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. */
+int bpf_label_id(struct bpf_labels *labels, const char *label)
+{
+	struct __bpf_label *begin = labels->labels, *end;
+	int id;
+	if (labels->count == 0) {
+		begin->label = strndup(label, MAX_BPF_LABEL_LEN);
+		if (!begin->label) {
+			return -1;
+		}
+		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 = strndup(label, MAX_BPF_LABEL_LEN);
+	if (!begin->label) {
+		return -1;
+	}
+	begin->location = 0xffffffff;
+	labels->count++;
+	return id;
+}
+
+/* Free label strings. */
+void free_label_strings(struct bpf_labels *labels)
+{
+	if (labels->count == 0)
+		return;
+
+	struct __bpf_label *begin = labels->labels, *end;
+
+	end = begin + labels->count;
+	for (; begin < end; ++begin) {
+		if (begin->label)
+			free((void*)(begin->label));
+	}
+
+	labels->count = 0;
+}
diff --git a/minijail/bpf.h b/minijail/bpf.h
new file mode 100644
index 0000000..e4897e2
--- /dev/null
+++ b/minijail/bpf.h
@@ -0,0 +1,200 @@
+/* bpf.h
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Berkeley Packet Filter functions.
+ */
+
+#ifndef BPF_H
+#define BPF_H
+
+#include <asm/bitsperlong.h>   /* for __BITS_PER_LONG */
+#include <endian.h>
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <stddef.h>
+#include <sys/user.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "arch.h"
+
+#if __BITS_PER_LONG == 32 || defined(__ILP32__)
+#define BITS32
+#elif __BITS_PER_LONG == 64
+#define BITS64
+#endif
+
+/* Constants for comparison operators. */
+#define MIN_OPERATOR 128
+enum {
+	EQ = MIN_OPERATOR,
+	NE,
+	LT,
+	LE,
+	GT,
+	GE,
+	SET
+};
+
+/*
+ * BPF return values and data structures,
+ * since they're not yet in the kernel.
+ */
+#define SECCOMP_RET_KILL	0x00000000U /* kill the task immediately */
+#define SECCOMP_RET_TRAP	0x00030000U /* return SIGSYS */
+#define SECCOMP_RET_ERRNO	0x00050000U /* return -1 and set errno */
+#define SECCOMP_RET_ALLOW	0x7fff0000U /* allow */
+
+#define SECCOMP_RET_DATA	0x0000ffffU /* mask for return value */
+
+struct seccomp_data {
+	int nr;
+	__u32 arch;
+	__u64 instruction_pointer;
+	__u64 args[6];
+};
+
+#define syscall_nr (offsetof(struct seccomp_data, nr))
+#define arch_nr (offsetof(struct seccomp_data, arch))
+
+/* Size-dependent defines. */
+#if defined(BITS32)
+/*
+ * On 32 bits, comparisons take 2 instructions: 1 for loading the argument,
+ * 1 for the actual comparison.
+ */
+#define BPF_LOAD_ARG_LEN	1U
+#define BPF_COMP_LEN		1U
+#define BPF_ARG_COMP_LEN (BPF_LOAD_ARG_LEN + BPF_COMP_LEN)
+
+#define bpf_comp_jeq bpf_comp_jeq32
+#define bpf_comp_jset bpf_comp_jset32
+
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+
+#elif defined(BITS64)
+/*
+ * On 64 bits, comparisons take 7 instructions: 4 for loading the argument,
+ * and 3 for the actual comparison.
+ */
+#define BPF_LOAD_ARG_LEN	4U
+#define BPF_COMP_LEN		3U
+#define BPF_ARG_COMP_LEN (BPF_LOAD_ARG_LEN + BPF_COMP_LEN)
+
+#define bpf_comp_jeq bpf_comp_jeq64
+#define bpf_comp_jset bpf_comp_jset64
+
+/* Ensure that we load the logically correct offset. */
+#if defined(__LITTLE_ENDIAN__) || __BYTE_ORDER == __LITTLE_ENDIAN
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
+#else
+#error "Unsupported endianness"
+#endif
+
+#else
+#error "Unknown bit width"
+
+#endif
+
+/* Common jump targets. */
+#define NEXT 0
+#define SKIP 1
+#define SKIPN(_n) (_n)
+
+/* Support for labels in BPF programs. */
+#define JUMP_JT 0xff
+#define JUMP_JF 0xff
+#define LABEL_JT 0xfe
+#define LABEL_JF 0xfe
+
+#define MAX_BPF_LABEL_LEN 32
+
+#define BPF_LABELS_MAX 256
+struct bpf_labels {
+	int count;
+	struct __bpf_label {
+		const char *label;
+		unsigned int location;
+	} labels[BPF_LABELS_MAX];
+};
+
+/* BPF instruction manipulation functions and macros. */
+static inline size_t set_bpf_instr(struct sock_filter *instr,
+				   unsigned short code, unsigned int k,
+				   unsigned char jt, unsigned char jf)
+{
+	instr->code = code;
+	instr->k = k;
+	instr->jt = jt;
+	instr->jf = jf;
+	return 1U;
+}
+
+#define set_bpf_stmt(_block, _code, _k) \
+	set_bpf_instr((_block), (_code), (_k), 0, 0)
+
+#define set_bpf_jump(_block, _code, _k, _jt, _jf) \
+	set_bpf_instr((_block), (_code), (_k), (_jt), (_jf))
+
+#define set_bpf_lbl(_block, _lbl_id) \
+	set_bpf_jump((_block), BPF_JMP+BPF_JA, (_lbl_id), \
+			LABEL_JT, LABEL_JF)
+
+#define set_bpf_jump_lbl(_block, _lbl_id) \
+	set_bpf_jump((_block), BPF_JMP+BPF_JA, (_lbl_id), \
+			JUMP_JT, JUMP_JF)
+
+#define set_bpf_ret_kill(_block) \
+	set_bpf_stmt((_block), BPF_RET+BPF_K, SECCOMP_RET_KILL)
+
+#define set_bpf_ret_trap(_block) \
+	set_bpf_stmt((_block), BPF_RET+BPF_K, SECCOMP_RET_TRAP)
+
+#define set_bpf_ret_errno(_block, _errno) \
+	set_bpf_stmt((_block), BPF_RET+BPF_K, \
+		SECCOMP_RET_ERRNO | ((_errno) & SECCOMP_RET_DATA))
+
+#define set_bpf_ret_allow(_block) \
+	set_bpf_stmt((_block), BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
+
+#define bpf_load_syscall_nr(_filter) \
+	set_bpf_stmt((_filter), BPF_LD+BPF_W+BPF_ABS, syscall_nr)
+
+/* BPF label functions. */
+int bpf_resolve_jumps(struct bpf_labels *labels,
+		struct sock_filter *filter, size_t count);
+int bpf_label_id(struct bpf_labels *labels, const char *label);
+void free_label_strings(struct bpf_labels *labels);
+
+/* BPF helper functions. */
+size_t bpf_load_arg(struct sock_filter *filter, int argidx);
+size_t bpf_comp_jeq(struct sock_filter *filter, unsigned long c,
+		unsigned char jt, unsigned char jf);
+size_t bpf_comp_jset(struct sock_filter *filter, unsigned long mask,
+		unsigned char jt, unsigned char jf);
+
+/* Functions called by syscall_filter.c */
+#define ARCH_VALIDATION_LEN 3U
+#define ALLOW_SYSCALL_LEN 2U
+
+size_t bpf_arg_comp(struct sock_filter **pfilter,
+		int op, int argidx, unsigned long c, unsigned int label_id);
+size_t bpf_validate_arch(struct sock_filter *filter);
+size_t bpf_allow_syscall(struct sock_filter *filter, int nr);
+size_t bpf_allow_syscall_args(struct sock_filter *filter,
+		int nr, unsigned int id);
+
+/* Debug functions. */
+void dump_bpf_prog(struct sock_fprog *fprog);
+void dump_bpf_filter(struct sock_filter *filter, unsigned short len);
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#endif /* BPF_H */
diff --git a/minijail/common.mk b/minijail/common.mk
new file mode 100644
index 0000000..4e47f2a
--- /dev/null
+++ b/minijail/common.mk
@@ -0,0 +1,941 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# If this file is part of another source distribution, it's license may be
+# stored in LICENSE.makefile or LICENSE.common.mk.
+#
+# NOTE NOTE NOTE
+#  The authoritative common.mk is located in:
+#    https://chromium.googlesource.com/chromiumos/platform2/+/master/common-mk
+#  Please make all changes there, then copy into place in other repos.
+# NOTE NOTE NOTE
+#
+# This file provides a common architecture for building C/C++ source trees.
+# It uses recursive makefile inclusion to create a single make process which
+# can be built in the source tree or with the build artifacts placed elsewhere.
+#
+# It is fully parallelizable for all targets, including static archives.
+#
+# To use:
+# 1. Place common.mk in your top source level
+# 2. In your top-level Makefile, place "include common.mk" at the top
+# 3. In all subdirectories, create a 'module.mk' file that starts with:
+#      include common.mk
+#    And then contains the remainder of your targets.
+# 4. All build targets should look like:
+#    relative/path/target: relative/path/obj.o
+#
+# See existing makefiles for rule examples.
+#
+# Exported macros:
+#   - cc_binary, cxx_binary provide standard compilation steps for binaries
+#   - cxx_library, cc_library provide standard compilation steps for
+#     shared objects.
+#   All of the above optionally take an argument for extra flags.
+#   - update_archive creates/updates a given .a target
+#
+# Instead of using the build macros, most users can just use wrapped targets:
+#   - CXX_BINARY, CC_BINARY, CC_STATIC_BINARY, CXX_STATIC_BINARY
+#   - CXX_LIBRARY, CC_LIBRARY, CC_STATIC_LIBRARY, CXX_STATIC_LIBRARY
+#   - E.g., CXX_BINARY(mahbinary): foo.o
+#   - object.depends targets may be used when a prerequisite is required for an
+#     object file. Because object files result in multiple build artifacts to
+#     handle PIC and PIE weirdness. E.g.
+#       foo.o.depends: generated/dbus.h
+#   - TEST(binary) or TEST(CXX_BINARY(binary)) may be used as a prerequisite
+#     for the tests target to trigger an automated test run.
+#   - CLEAN(file_or_dir) dependency can be added to 'clean'.
+#
+# If source code is being generated, rules will need to be registered for
+# compiling the objects.  This can be done by adding one of the following
+# to the Makefile:
+#   - For C source files
+#   $(eval $(call add_object_rules,sub/dir/gen_a.o sub/dir/b.o,CC,c,CFLAGS))
+#   - For C++ source files
+#   $(eval $(call add_object_rules,sub/dir/gen_a.o sub/dir/b.o,CXX,cc,CXXFLAGS))
+#
+# Exported targets meant to have prerequisites added to:
+#  - all - Your desired targets should be given
+#  - tests - Any TEST(test_binary) targets should be given
+#  - FORCE - force the given target to run regardless of changes
+#            In most cases, using .PHONY is preferred.
+#
+# Possible command line variables:
+#   - COLOR=[0|1] to set ANSI color output (default: 1)
+#   - VERBOSE=[0|1] to hide/show commands (default: 0)
+#   - MODE=[opt|dbg|profiling] (default: opt)
+#          opt - Enable optimizations for release builds
+#          dbg - Turn down optimization for debugging
+#          profiling - Turn off optimization and turn on profiling/coverage
+#                      support.
+#   - ARCH=[x86|arm|supported qemu name] (default: from portage or uname -m)
+#   - SPLITDEBUG=[0|1] splits debug info in target.debug (default: 0)
+#        If NOSTRIP=1, SPLITDEBUG will never strip the final emitted objects.
+#   - NOSTRIP=[0|1] determines if binaries are stripped. (default: 1)
+#        NOSTRIP=0 and MODE=opt will also drop -g from the CFLAGS.
+#   - VALGRIND=[0|1] runs tests under valgrind (default: 0)
+#   - OUT=/path/to/builddir puts all output in given path (default: $PWD)
+#   - VALGRIND_ARGS="" supplies extra memcheck arguments
+#
+# Per-target(-ish) variable:
+#   - NEEDS_ROOT=[0|1] allows a TEST() target to run with root.
+#     Default is 0 unless it is running under QEmu.
+#   - NEEDS_MOUNTS=[0|1] allows a TEST() target running on QEmu to get
+#     setup mounts in the $(SYSROOT)
+#
+# Caveats:
+# - Directories or files with spaces in them DO NOT get along with GNU Make.
+#   If you need them, all uses of dir/notdir/etc will need to have magic
+#   wrappers.  Proceed at risk to your own sanity.
+# - External CXXFLAGS and CFLAGS should be passed via the environment since
+#   this file does not use 'override' to control them.
+# - Our version of GNU Make doesn't seem to support the 'private' variable
+#   annotation, so you can't tag a variable private on a wrapping target.
+
+# Behavior configuration variables
+SPLITDEBUG ?= 0
+NOSTRIP ?= 1
+VALGRIND ?= 0
+COLOR ?= 1
+VERBOSE ?= 0
+MODE ?= opt
+CXXEXCEPTIONS ?= 0
+ARCH ?= $(shell uname -m)
+
+# Put objects in a separate tree based on makefile locations
+# This means you can build a tree without touching it:
+#   make -C $SRCDIR  # will create ./build-$(MODE)
+# Or
+#   make -C $SRCDIR OUT=$PWD
+# This variable is extended on subdir calls and doesn't need to be re-called.
+OUT ?= $(PWD)/
+
+# Make OUT now so we can use realpath.
+$(shell mkdir -p "$(OUT)")
+
+# TODO(wad) Relative paths are resolved against SRC and not the calling dir.
+# Ensure a command-line supplied OUT has a slash
+override OUT := $(realpath $(OUT))/
+
+# SRC is not meant to be set by the end user, but during make call relocation.
+# $(PWD) != $(CURDIR) all the time.
+export SRC ?= $(CURDIR)
+
+# If BASE_VER is not set, read the libchrome revision number from
+# common-mk/BASE_VER file.
+ifeq ($(strip $(BASE_VER)),)
+BASE_VER := $(shell cat $(SRC)/../common-mk/BASE_VER)
+endif
+$(info Using BASE_VER=$(BASE_VER))
+
+# Re-start in the $(OUT) directory if we're not there.
+# We may be invoked using -C or bare and we need to ensure behavior
+# is consistent so we check both PWD vs OUT and PWD vs CURDIR.
+override RELOCATE_BUILD := 0
+ifneq (${PWD}/,${OUT})
+override RELOCATE_BUILD := 1
+endif
+# Make sure we're running with no builtin targets. They cause
+# leakage and mayhem!
+ifneq (${PWD},${CURDIR})
+override RELOCATE_BUILD := 1
+# If we're run from the build dir, don't let it get cleaned up later.
+ifeq (${PWD}/,${OUT})
+$(shell touch "$(PWD)/.dont_delete_on_clean")
+endif
+endif  # ifneq (${PWD},${CURDIR}
+
+# "Relocate" if we need to restart without implicit rules.
+ifeq ($(subst r,,$(MAKEFLAGS)),$(MAKEFLAGS))
+override RELOCATE_BUILD := 1
+endif
+
+ifeq (${RELOCATE_BUILD},1)
+# By default, silence build output. Reused below as well.
+QUIET = @
+ifeq ($(VERBOSE),1)
+  QUIET=
+endif
+
+# This target will override all targets, including prerequisites. To avoid
+# calling $(MAKE) once per prereq on the given CMDGOAL, we guard it with a local
+# variable.
+RUN_ONCE := 0
+MAKECMDGOALS ?= all
+# Keep the rules split as newer make does not allow them to be declared
+# on the same line.  But the way :: rules work, the _all here will also
+# invoke the %:: rule while retaining "_all" as the default.
+_all::
+%::
+	$(if $(filter 0,$(RUN_ONCE)), \
+	  cd "$(OUT)" && \
+	  $(MAKE) -r -I "$(SRC)" -f "$(CURDIR)/Makefile" \
+	    SRC="$(CURDIR)" OUT="$(OUT)" $(foreach g,$(MAKECMDGOALS),"$(g)"),)
+	$(eval RUN_ONCE := 1)
+pass-to-subcall := 1
+endif
+
+ifeq ($(pass-to-subcall),)
+
+# Only call MODULE if we're in a submodule
+MODULES_LIST := $(filter-out Makefile %.d,$(MAKEFILE_LIST))
+ifeq ($(words $(filter-out Makefile common.mk %.d $(SRC)/Makefile \
+                           $(SRC)/common.mk,$(MAKEFILE_LIST))),0)
+
+# All the top-level defines outside of module.mk.
+
+#
+# Helper macros
+#
+
+# Create the directory if it doesn't yet exist.
+define auto_mkdir
+  $(if $(wildcard $(dir $1)),$2,$(QUIET)mkdir -p "$(dir $1)")
+endef
+
+# Creates the actual archive with an index.
+# The target $@ must end with .pic.a or .pie.a.
+define update_archive
+  $(call auto_mkdir,$(TARGET_OR_MEMBER))
+  $(QUIET)# Create the archive in one step to avoid parallel use accessing it
+  $(QUIET)# before all the symbols are present.
+  @$(ECHO) "AR		$(subst \
+$(SRC)/,,$(^:.o=$(suffix $(basename $(TARGET_OR_MEMBER))).o)) \
+-> $(subst $(SRC)/,,$(TARGET_OR_MEMBER))"
+  $(QUIET)$(AR) rcs $(TARGET_OR_MEMBER) \
+          $(subst $(SRC)/,,$(^:.o=$(suffix $(basename $(TARGET_OR_MEMBER))).o))
+endef
+
+# Default compile from objects using pre-requisites but filters out
+# subdirs and .d files.
+define cc_binary
+  $(call COMPILE_BINARY_implementation,CC,$(CFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+
+define cxx_binary
+  $(call COMPILE_BINARY_implementation,CXX,$(CXXFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+
+# Default compile from objects using pre-requisites but filters out
+# subdirs and .d files.
+define cc_library
+  $(call COMPILE_LIBRARY_implementation,CC,$(CFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+define cxx_library
+  $(call COMPILE_LIBRARY_implementation,CXX,$(CXXFLAGS) $(1),$(EXTRA_FLAGS))
+endef
+
+# Deletes files silently if they exist. Meant for use in any local
+# clean targets.
+define silent_rm
+  $(if $(wildcard $(1)),
+  $(QUIET)($(ECHO) -n '$(COLOR_RED)CLEANFILE$(COLOR_RESET)		' && \
+    $(ECHO) '$(subst $(OUT)/,,$(wildcard $(1)))' && \
+    $(RM) $(1) 2>/dev/null) || true,)
+endef
+define silent_rmdir
+  $(if $(wildcard $(1)),
+    $(if $(wildcard $(1)/*),
+  $(QUIET)# $(1) not empty [$(wildcard $(1)/*)]. Not deleting.,
+  $(QUIET)($(ECHO) -n '$(COLOR_RED)CLEANDIR$(COLOR_RESET)		' && \
+    $(ECHO) '$(subst $(OUT)/,,$(wildcard $(1)))' && \
+    $(RMDIR) $(1) 2>/dev/null) || true),)
+endef
+
+#
+# Default variable values
+#
+
+# Only override toolchain vars if they are from make.
+CROSS_COMPILE ?=
+define override_var
+ifneq ($(filter undefined default,$(origin $1)),)
+$1 = $(CROSS_COMPILE)$2
+endif
+endef
+$(eval $(call override_var,AR,ar))
+$(eval $(call override_var,CC,gcc))
+$(eval $(call override_var,CXX,g++))
+$(eval $(call override_var,OBJCOPY,objcopy))
+$(eval $(call override_var,PKG_CONFIG,pkg-config))
+$(eval $(call override_var,RANLIB,ranlib))
+$(eval $(call override_var,STRIP,strip))
+
+RMDIR ?= rmdir
+ECHO = /bin/echo -e
+
+ifeq ($(lastword $(subst /, ,$(CC))),clang)
+CDRIVER = clang
+else
+CDRIVER = gcc
+endif
+
+ifeq ($(lastword $(subst /, ,$(CXX))),clang++)
+CXXDRIVER = clang
+else
+CXXDRIVER = gcc
+endif
+
+# Internal macro to support check_XXX macros below.
+# Usage: $(call check_compile, [code], [compiler], [code_type], [c_flags],
+#               [extra_c_flags], [library_flags], [success_ret], [fail_ret])
+# Return: [success_ret] if compile succeeded, otherwise [fail_ret]
+check_compile = $(shell printf '%b\n' $(1) | \
+  $($(2)) $($(4)) -x $(3) $(LDFLAGS) $(5) - $(6) -o /dev/null > /dev/null 2>&1 \
+  && echo "$(7)" || echo "$(8)")
+
+# Helper macro to check whether a test program will compile with the specified
+# compiler flags.
+# Usage: $(call check_compile_cc, [code], [flags], [alternate_flags])
+# Return: [flags] if compile succeeded, otherwise [alternate_flags]
+check_compile_cc = $(call check_compile,$(1),CC,c,CFLAGS,$(2),,$(2),$(3))
+check_compile_cxx = $(call check_compile,$(1),CXX,c++,CXXFLAGS,$(2),,$(2),$(3))
+
+# Helper macro to check whether a test program will compile with the specified
+# libraries.
+# Usage: $(call check_compile_cc, [code], [library_flags], [alternate_flags])
+# Return: [library_flags] if compile succeeded, otherwise [alternate_flags]
+check_libs_cc = $(call check_compile,$(1),CC,c,CFLAGS,,$(2),$(2),$(3))
+check_libs_cxx = $(call check_compile,$(1),CXX,c++,CXXFLAGS,,$(2),$(2),$(3))
+
+# Helper macro to check whether the compiler accepts the specified flags.
+# Usage: $(call check_compile_cc, [flags], [alternate_flags])
+# Return: [flags] if compile succeeded, otherwise [alternate_flags]
+check_cc = $(call check_compile_cc,'int main() { return 0; }',$(1),$(2))
+check_cxx = $(call check_compile_cxx,'int main() { return 0; }',$(1),$(2))
+
+# Choose the stack protector flags based on whats supported by the compiler.
+SSP_CFLAGS := $(call check_cc,-fstack-protector-strong)
+ifeq ($(SSP_CFLAGS),)
+ SSP_CFLAGS := $(call check_cc,-fstack-protector-all)
+endif
+
+# To update these from an including Makefile:
+#  CXXFLAGS += -mahflag  # Append to the list
+#  CXXFLAGS := -mahflag $(CXXFLAGS) # Prepend to the list
+#  CXXFLAGS := $(filter-out badflag,$(CXXFLAGS)) # Filter out a value
+# The same goes for CFLAGS.
+COMMON_CFLAGS-gcc := -fvisibility=internal -ggdb3 -Wa,--noexecstack
+COMMON_CFLAGS-clang := -fvisibility=hidden -ggdb
+COMMON_CFLAGS := -Wall -Werror -fno-strict-aliasing $(SSP_CFLAGS) -O1 -Wformat=2
+CXXFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CXXDRIVER))
+CFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CDRIVER))
+CPPFLAGS += -D_FORTIFY_SOURCE=2
+
+# Enable large file support.
+CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+
+# Disable exceptions based on the CXXEXCEPTIONS setting.
+ifeq ($(CXXEXCEPTIONS),0)
+  CXXFLAGS := $(CXXFLAGS) -fno-exceptions -fno-unwind-tables \
+    -fno-asynchronous-unwind-tables
+endif
+
+ifeq ($(MODE),opt)
+  # Up the optimizations.
+  CFLAGS := $(filter-out -O1,$(CFLAGS)) -O2
+  CXXFLAGS := $(filter-out -O1,$(CXXFLAGS)) -O2
+  # Only drop -g* if symbols aren't desired.
+  ifeq ($(NOSTRIP),0)
+    # TODO: do we want -fomit-frame-pointer on x86?
+    CFLAGS := $(filter-out -ggdb3,$(CFLAGS))
+    CXXFLAGS := $(filter-out -ggdb3,$(CXXFLAGS))
+  endif
+endif
+
+ifeq ($(MODE),profiling)
+  CFLAGS := $(CFLAGS) -O0 -g  --coverage
+  CXXFLAGS := $(CXXFLAGS) -O0 -g  --coverage
+  LDFLAGS := $(LDFLAGS) --coverage
+endif
+
+LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,noexecstack -Wl,-z,now
+
+# Fancy helpers for color if a prompt is defined
+ifeq ($(COLOR),1)
+COLOR_RESET = \x1b[0m
+COLOR_GREEN = \x1b[32;01m
+COLOR_RED = \x1b[31;01m
+COLOR_YELLOW = \x1b[33;01m
+endif
+
+# By default, silence build output.
+QUIET = @
+ifeq ($(VERBOSE),1)
+  QUIET=
+endif
+
+#
+# Implementation macros for compile helpers above
+#
+
+# Useful for dealing with pie-broken toolchains.
+# Call make with PIE=0 to disable default PIE use.
+OBJ_PIE_FLAG = -fPIE
+COMPILE_PIE_FLAG = -pie
+ifeq ($(PIE),0)
+  OBJ_PIE_FLAG =
+  COMPILE_PIE_FLAG =
+endif
+
+# Favor member targets first for CXX_BINARY(%) magic.
+# And strip out nested members if possible.
+LP := (
+RP := )
+TARGET_OR_MEMBER = $(lastword $(subst $(LP), ,$(subst $(RP),,$(or $%,$@))))
+
+# Default compile from objects using pre-requisites but filters out
+# all non-.o files.
+define COMPILE_BINARY_implementation
+  @$(ECHO) "LD$(1)		$(subst $(PWD)/,,$(TARGET_OR_MEMBER))"
+  $(call auto_mkdir,$(TARGET_OR_MEMBER))
+  $(QUIET)$($(1)) $(COMPILE_PIE_FLAGS) -o $(TARGET_OR_MEMBER) \
+    $(2) $(LDFLAGS) \
+    $(filter %.o %.a,$(^:.o=.pie.o)) \
+    $(foreach so,$(filter %.so,$^),-L$(dir $(so)) \
+                            -l$(patsubst lib%,%,$(basename $(notdir $(so))))) \
+    $(LDLIBS)
+  $(call conditional_strip)
+  @$(ECHO) -n "BIN		"
+  @$(ECHO) "$(COLOR_GREEN)$(subst $(PWD)/,,$(TARGET_OR_MEMBER))$(COLOR_RESET)"
+  @$(ECHO) "	$(COLOR_YELLOW)-----$(COLOR_RESET)"
+endef
+
+# TODO: add version support extracted from PV environment variable
+#ifeq ($(PV),9999)
+#$(warning PV=$(PV). If shared object versions matter, please force PV=.)
+#endif
+# Then add -Wl,-soname,$@.$(PV) ?
+
+# Default compile from objects using pre-requisites but filters out
+# all non-.o values. (Remember to add -L$(OUT) -llib)
+COMMA := ,
+define COMPILE_LIBRARY_implementation
+  @$(ECHO) "SHARED$(1)	$(subst $(PWD)/,,$(TARGET_OR_MEMBER))"
+  $(call auto_mkdir,$(TARGET_OR_MEMBER))
+  $(QUIET)$($(1)) -shared -Wl,-E -o $(TARGET_OR_MEMBER) \
+    $(2) $(LDFLAGS) \
+    $(if $(filter %.a,$^),-Wl$(COMMA)--whole-archive,) \
+    $(filter %.o ,$(^:.o=.pic.o)) \
+    $(foreach a,$(filter %.a,$^),-L$(dir $(a)) \
+                            -l$(patsubst lib%,%,$(basename $(notdir $(a))))) \
+    $(foreach so,$(filter %.so,$^),-L$(dir $(so)) \
+                            -l$(patsubst lib%,%,$(basename $(notdir $(so))))) \
+    $(LDLIBS)
+  $(call conditional_strip)
+  @$(ECHO) -n "LIB		$(COLOR_GREEN)"
+  @$(ECHO) "$(subst $(PWD)/,,$(TARGET_OR_MEMBER))$(COLOR_RESET)"
+  @$(ECHO) "	$(COLOR_YELLOW)-----$(COLOR_RESET)"
+endef
+
+define conditional_strip
+  $(if $(filter 0,$(NOSTRIP)),$(call strip_artifact))
+endef
+
+define strip_artifact
+  @$(ECHO) "STRIP		$(subst $(OUT)/,,$(TARGET_OR_MEMBER))"
+  $(if $(filter 1,$(SPLITDEBUG)), @$(ECHO) -n "DEBUG	"; \
+    $(ECHO) "$(COLOR_YELLOW)\
+$(subst $(OUT)/,,$(TARGET_OR_MEMBER)).debug$(COLOR_RESET)")
+  $(if $(filter 1,$(SPLITDEBUG)), \
+    $(QUIET)$(OBJCOPY) --only-keep-debug "$(TARGET_OR_MEMBER)" \
+      "$(TARGET_OR_MEMBER).debug")
+  $(if $(filter-out dbg,$(MODE)),$(QUIET)$(STRIP) --strip-unneeded \
+    "$(TARGET_OR_MEMBER)",)
+endef
+
+#
+# Global pattern rules
+#
+
+# Below, the archive member syntax is abused to create fancier
+# syntactic sugar for recipe authors that avoids needed to know
+# subcall options.  The downside is that make attempts to look
+# into the phony archives for timestamps. This will cause the final
+# target to be rebuilt/linked on _every_ call to make even when nothing
+# has changed.  Until a better way presents itself, we have helpers that
+# do the stat check on make's behalf.  Dodgy but simple.
+define old_or_no_timestamp
+  $(if $(realpath $%),,$(1))
+  $(if $(shell find $^ -cnewer "$%" 2>/dev/null),$(1))
+endef
+
+define check_deps
+  $(if $(filter 0,$(words $^)),\
+    $(error Missing dependencies or declaration of $@($%)),)
+endef
+
+# Build a cxx target magically
+CXX_BINARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call cxx_binary))
+clean: CLEAN(CXX_BINARY*)
+
+CC_BINARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call cc_binary))
+clean: CLEAN(CC_BINARY*)
+
+CXX_STATIC_BINARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call cxx_binary,-static))
+clean: CLEAN(CXX_STATIC_BINARY*)
+
+CC_STATIC_BINARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call cc_binary,-static))
+clean: CLEAN(CC_STATIC_BINARY*)
+
+CXX_LIBRARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call cxx_library))
+clean: CLEAN(CXX_LIBRARY*)
+
+CXX_LIBARY(%):
+	$(error Typo alert! LIBARY != LIBRARY)
+
+CC_LIBRARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call cc_library))
+clean: CLEAN(CC_LIBRARY*)
+
+CC_LIBARY(%):
+	$(error Typo alert! LIBARY != LIBRARY)
+
+CXX_STATIC_LIBRARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call update_archive))
+clean: CLEAN(CXX_STATIC_LIBRARY*)
+
+CXX_STATIC_LIBARY(%):
+	$(error Typo alert! LIBARY != LIBRARY)
+
+CC_STATIC_LIBRARY(%):
+	$(call check_deps)
+	$(call old_or_no_timestamp,$(call update_archive))
+clean: CLEAN(CC_STATIC_LIBRARY*)
+
+CC_STATIC_LIBARY(%):
+	$(error Typo alert! LIBARY != LIBRARY)
+
+
+TEST(%): % qemu_chroot_install
+	$(call TEST_implementation)
+.PHONY: TEST
+
+# multiple targets with a wildcard need to share an directory.
+# Don't use this directly it just makes sure the directory is removed _after_
+# the files are.
+CLEANFILE(%):
+	$(call silent_rm,$(TARGET_OR_MEMBER))
+.PHONY: CLEANFILE
+
+CLEAN(%): CLEANFILE(%)
+	$(QUIET)# CLEAN($%) meta-target called
+	$(if $(filter-out $(PWD)/,$(dir $(abspath $(TARGET_OR_MEMBER)))), \
+	  $(call silent_rmdir,$(dir $(abspath $(TARGET_OR_MEMBER)))),\
+	  $(QUIET)# Not deleting $(dir $(abspath $(TARGET_OR_MEMBER))) yet.)
+.PHONY: CLEAN
+
+#
+# Top-level objects and pattern rules
+#
+
+# All objects for .c files at the top level
+C_OBJECTS = $(patsubst $(SRC)/%.c,%.o,$(wildcard $(SRC)/*.c))
+
+
+# All objects for .cxx files at the top level
+CXX_OBJECTS = $(patsubst $(SRC)/%.cc,%.o,$(wildcard $(SRC)/*.cc))
+
+# Note, the catch-all pattern rules don't work in subdirectories because
+# we're building from the $(OUT) directory. At the top-level (here) they will
+# work, but we go ahead and match using the module form.  Then we can place a
+# generic pattern rule to capture leakage from the main Makefile. (Later in the
+# file.)
+#
+# The reason target specific pattern rules work well for modules,
+# MODULE_C_OBJECTS, is because it scopes the behavior to the given target which
+# ensures we get a relative directory offset from $(OUT) which otherwise would
+# not match without further magic on a per-subdirectory basis.
+
+# Creates object file rules. Call with eval.
+# $(1) list of .o files
+# $(2) source type (CC or CXX)
+# $(3) source suffix (cc or c)
+# $(4) compiler flag name (CFLAGS or CXXFLAGS)
+# $(5) source dir: _only_ if $(SRC). Leave blank for obj tree.
+define add_object_rules
+$(patsubst %.o,%.pie.o,$(1)): %.pie.o: $(5)%.$(3) %.o.depends
+	$$(call auto_mkdir,$$@)
+	$$(call OBJECT_PATTERN_implementation,$(2),\
+          $$(basename $$@),$$($(4)) $$(CPPFLAGS) $$(OBJ_PIE_FLAG))
+
+$(patsubst %.o,%.pic.o,$(1)): %.pic.o: $(5)%.$(3) %.o.depends
+	$$(call auto_mkdir,$$@)
+	$$(call OBJECT_PATTERN_implementation,$(2),\
+          $$(basename $$@),$$($(4)) $$(CPPFLAGS) -fPIC)
+
+# Placeholder for depends
+$(patsubst %.o,%.o.depends,$(1)):
+	$$(call auto_mkdir,$$@)
+	$$(QUIET)touch "$$@"
+
+$(1): %.o: %.pic.o %.pie.o
+	$$(call auto_mkdir,$$@)
+	$$(QUIET)touch "$$@"
+endef
+
+define OBJECT_PATTERN_implementation
+  @$(ECHO) "$(1)		$(subst $(SRC)/,,$<) -> $(2).o"
+  $(call auto_mkdir,$@)
+  $(QUIET)$($(1)) -c -MD -MF $(2).d $(3) -o $(2).o $<
+  $(QUIET)# Wrap all the deps in $$(wildcard) so a missing header
+  $(QUIET)# won't cause weirdness.  First we remove newlines and \,
+  $(QUIET)# then wrap it.
+  $(QUIET)sed -i -e :j -e '$$!N;s|\\\s*\n| |;tj' \
+    -e 's|^\(.*\s*:\s*\)\(.*\)$$|\1 $$\(wildcard \2\)|' $(2).d
+endef
+
+# Now actually register handlers for C(XX)_OBJECTS.
+$(eval $(call add_object_rules,$(C_OBJECTS),CC,c,CFLAGS,$(SRC)/))
+$(eval $(call add_object_rules,$(CXX_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+
+# Disable default pattern rules to help avoid leakage.
+# These may already be handled by '-r', but let's keep it to be safe.
+%: %.o ;
+%.a: %.o ;
+%.o: %.c ;
+%.o: %.cc ;
+
+# NOTE: A specific rule for archive objects is avoided because parallel
+#       update of the archive causes build flakiness.
+# Instead, just make the objects the prerequisites and use update_archive
+# To use the foo.a(obj.o) functionality, targets would need to specify the
+# explicit object they expect on the prerequisite line.
+
+#
+# Architecture detection and QEMU wrapping
+#
+
+HOST_ARCH ?= $(shell uname -m)
+override ARCH := $(strip $(ARCH))
+override HOST_ARCH := $(strip $(HOST_ARCH))
+# emake will supply "x86" or "arm" for ARCH, but
+# if uname -m runs and you get x86_64, then this subst
+# will break.
+ifeq ($(subst x86,i386,$(ARCH)),i386)
+  QEMU_ARCH := $(subst x86,i386,$(ARCH))  # x86 -> i386
+else ifeq ($(subst amd64,x86_64,$(ARCH)),x86_64)
+  QEMU_ARCH := $(subst amd64,x86_64,$(ARCH))  # amd64 -> x86_64
+else
+  QEMU_ARCH = $(ARCH)
+endif
+override QEMU_ARCH := $(strip $(QEMU_ARCH))
+
+# If we're cross-compiling, try to use qemu for running the tests.
+ifneq ($(QEMU_ARCH),$(HOST_ARCH))
+  ifeq ($(SYSROOT),)
+    $(info SYSROOT not defined. qemu-based testing disabled)
+  else
+    # A SYSROOT is assumed for QEmu use.
+    USE_QEMU ?= 1
+
+    # Allow 64-bit hosts to run 32-bit without qemu.
+    ifeq ($(HOST_ARCH),x86_64)
+      ifeq ($(QEMU_ARCH),i386)
+        USE_QEMU = 0
+      endif
+    endif
+  endif
+else
+  USE_QEMU ?= 0
+endif
+
+# Normally we don't need to run as root or do bind mounts, so only
+# enable it by default when we're using QEMU.
+NEEDS_ROOT ?= $(USE_QEMU)
+NEEDS_MOUNTS ?= $(USE_QEMU)
+
+SYSROOT_OUT = $(OUT)
+ifneq ($(SYSROOT),)
+  SYSROOT_OUT = $(subst $(SYSROOT),,$(OUT))
+else
+  # Default to / when all the empty-sysroot logic is done.
+  SYSROOT = /
+endif
+
+QEMU_NAME = qemu-$(QEMU_ARCH)
+QEMU_PATH = /build/bin/$(QEMU_NAME)
+QEMU_SYSROOT_PATH = $(SYSROOT)$(QEMU_PATH)
+QEMU_SRC_PATH = /usr/bin/$(QEMU_NAME)
+QEMU_BINFMT_PATH = /proc/sys/fs/binfmt_misc/$(QEMU_NAME)
+QEMU_REGISTER_PATH = /proc/sys/fs/binfmt_misc/register
+
+QEMU_MAGIC_arm = ":$(QEMU_NAME):M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/build/bin/qemu-arm:"
+
+
+#
+# Output full configuration at top level
+#
+
+# Don't show on clean
+ifneq ($(MAKECMDGOALS),clean)
+  $(info build configuration:)
+  $(info - OUT=$(OUT))
+  $(info - SRC=$(SRC))
+  $(info - MODE=$(MODE))
+  $(info - SPLITDEBUG=$(SPLITDEBUG))
+  $(info - NOSTRIP=$(NOSTRIP))
+  $(info - VALGRIND=$(VALGRIND))
+  $(info - COLOR=$(COLOR))
+  $(info - CXXEXCEPTIONS=$(CXXEXCEPTIONS))
+  $(info - ARCH=$(ARCH))
+  $(info - QEMU_ARCH=$(QEMU_ARCH))
+  $(info - USE_QEMU=$(USE_QEMU))
+  $(info - NEEDS_ROOT=$(NEEDS_ROOT))
+  $(info - NEEDS_MOUNTS=$(NEEDS_MOUNTS))
+  $(info - SYSROOT=$(SYSROOT))
+  $(info )
+endif
+
+#
+# Standard targets with detection for when they are improperly configured.
+#
+
+# all does not include tests by default
+all:
+	$(QUIET)(test -z "$^" && \
+	$(ECHO) "You must add your targets as 'all' prerequisites") || true
+	$(QUIET)test -n "$^"
+
+# Builds and runs tests for the target arch
+# Run them in parallel
+# After the test have completed, if profiling, run coverage analysis
+tests:
+ifeq ($(MODE),profiling)
+	@$(ECHO) "COVERAGE [$(COLOR_YELLOW)STARTED$(COLOR_RESET)]"
+	$(QUIET)FILES="";						\
+		for GCNO in `find . -name "*.gcno"`; do			\
+			GCDA="$${GCNO%.gcno}.gcda";			\
+			if [ -e $${GCDA} ]; then			\
+				FILES="$${FILES} $${GCDA}";		\
+			fi						\
+		done;							\
+		if [ -n "$${FILES}" ]; then				\
+			gcov -l $${FILES};				\
+			lcov --capture --directory .			\
+				--output-file=lcov-coverage.info;	\
+			genhtml lcov-coverage.info			\
+				--output-directory lcov-html;		\
+		fi
+	@$(ECHO) "COVERAGE [$(COLOR_YELLOW)FINISHED$(COLOR_RESET)]"
+endif
+.PHONY: tests
+
+qemu_chroot_install:
+ifeq ($(USE_QEMU),1)
+	$(QUIET)$(ECHO) "QEMU   Preparing $(QEMU_NAME)"
+	@# Copying strategy
+	@# Compare /usr/bin/qemu inode to /build/$board/build/bin/qemu, if different
+	@# hard link to a temporary file, then rename temp to target. This should
+	@# ensure that once $QEMU_SYSROOT_PATH exists it will always exist, regardless
+	@# of simultaneous test setups.
+	$(QUIET)if [[ ! -e $(QEMU_SYSROOT_PATH) || \
+	    `stat -c %i $(QEMU_SRC_PATH)` != `stat -c %i $(QEMU_SYSROOT_PATH)` \
+	    ]]; then \
+	  $(ROOT_CMD) ln -Tf $(QEMU_SRC_PATH) $(QEMU_SYSROOT_PATH).$$$$; \
+	  $(ROOT_CMD) mv -Tf $(QEMU_SYSROOT_PATH).$$$$ $(QEMU_SYSROOT_PATH); \
+	fi
+
+	@# Prep the binfmt handler. First mount if needed, then unregister any bad
+	@# mappings and then register our mapping.
+	@# There may still be some race conditions here where one script de-registers
+	@# and another script starts executing before it gets re-registered, however
+	@# it should be rare.
+	-$(QUIET)[[ -e $(QEMU_REGISTER_PATH) ]] || \
+	  $(ROOT_CMD) mount binfmt_misc -t binfmt_misc \
+	    /proc/sys/fs/binfmt_misc
+
+	-$(QUIET)if [[ -e $(QEMU_BINFMT_PATH) && \
+	      `awk '$$1 == "interpreter" {print $$NF}' $(QEMU_BINFMT_PATH)` != \
+	      "$(QEMU_PATH)" ]]; then \
+	  echo -1 | $(ROOT_CMD) tee $(QEMU_BINFMT_PATH) >/dev/null; \
+	fi
+
+	-$(if $(QEMU_MAGIC_$(ARCH)),$(QUIET)[[ -e $(QEMU_BINFMT_PATH) ]] || \
+	  echo $(QEMU_MAGIC_$(ARCH)) | $(ROOT_CMD) tee $(QEMU_REGISTER_PATH) \
+	    >/dev/null)
+endif
+.PHONY: qemu_clean qemu_chroot_install
+
+# TODO(wad) Move to -L $(SYSROOT) and fakechroot when qemu-user
+#           doesn't hang traversing /proc from SYSROOT.
+SUDO_CMD = sudo
+UNSHARE_CMD = unshare
+QEMU_CMD =
+ROOT_CMD = $(if $(filter 1,$(NEEDS_ROOT)),$(SUDO_CMD) , )
+MOUNT_CMD = $(if $(filter 1,$(NEEDS_MOUNTS)),$(ROOT_CMD) mount, \#)
+UMOUNT_CMD = $(if $(filter 1,$(NEEDS_MOUNTS)),$(ROOT_CMD) umount, \#)
+QEMU_LDPATH = $(SYSROOT_LDPATH):/lib64:/lib:/usr/lib64:/usr/lib
+ROOT_CMD_LDPATH = $(SYSROOT_LDPATH):$(SYSROOT)/lib64:
+ROOT_CMD_LDPATH := $(ROOT_CMD_LDPATH):$(SYSROOT)/lib:$(SYSROOT)/usr/lib64:
+ROOT_CMD_LDPATH := $(ROOT_CMD_LDPATH):$(SYSROOT)/usr/lib
+ifeq ($(USE_QEMU),1)
+  export QEMU_CMD = \
+   $(SUDO_CMD) chroot $(SYSROOT) $(QEMU_PATH) \
+   -drop-ld-preload \
+   -E LD_LIBRARY_PATH="$(QEMU_LDPATH):$(patsubst $(OUT),,$(LD_DIRS))" \
+   -E HOME="$(HOME)" -E SRC="$(SRC)" --
+  # USE_QEMU conditional function
+  define if_qemu
+    $(1)
+  endef
+else
+  ROOT_CMD = $(if $(filter 1,$(NEEDS_ROOT)),sudo, ) \
+    LD_LIBRARY_PATH="$(ROOT_CMD_LDPATH):$(LD_DIRS)"
+  define if_qemu
+    $(2)
+  endef
+endif
+
+VALGRIND_CMD =
+ifeq ($(VALGRIND),1)
+  VALGRIND_CMD = /usr/bin/valgrind --tool=memcheck $(VALGRIND_ARGS) --
+endif
+
+define TEST_implementation
+  $(QUIET)$(call TEST_setup)
+  $(QUIET)$(call TEST_run)
+  $(QUIET)$(call TEST_teardown)
+  $(QUIET)exit $$(cat $(OUT)$(TARGET_OR_MEMBER).status.test)
+endef
+
+define TEST_setup
+  @$(ECHO) -n "TEST		$(TARGET_OR_MEMBER) "
+  @$(ECHO) "[$(COLOR_YELLOW)SETUP$(COLOR_RESET)]"
+  $(QUIET)# Setup a target-specific results file
+  $(QUIET)(echo > $(OUT)$(TARGET_OR_MEMBER).setup.test)
+  $(QUIET)(echo 1 > $(OUT)$(TARGET_OR_MEMBER).status.test)
+  $(QUIET)(echo > $(OUT)$(TARGET_OR_MEMBER).cleanup.test)
+  $(QUIET)# No setup if we are not using QEMU
+  $(QUIET)# TODO(wad) this is racy until we use a vfs namespace
+  $(call if_qemu,\
+    $(QUIET)(echo "mkdir -p '$(SYSROOT)/proc' '$(SYSROOT)/dev' \
+                            '$(SYSROOT)/mnt/host/source'" \
+             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+  $(call if_qemu,\
+    $(QUIET)(echo "$(MOUNT_CMD) --bind /mnt/host/source \
+             '$(SYSROOT)/mnt/host/source'" \
+             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+  $(call if_qemu,\
+    $(QUIET)(echo "$(MOUNT_CMD) --bind /proc '$(SYSROOT)/proc'" \
+             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+  $(call if_qemu,\
+    $(QUIET)(echo "$(MOUNT_CMD) --bind /dev '$(SYSROOT)/dev'" \
+             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+endef
+
+define TEST_teardown
+  @$(ECHO) -n "TEST		$(TARGET_OR_MEMBER) "
+  @$(ECHO) "[$(COLOR_YELLOW)TEARDOWN$(COLOR_RESET)]"
+  $(call if_qemu, $(QUIET)$(SHELL) "$(OUT)$(TARGET_OR_MEMBER).cleanup.test")
+endef
+
+# Use GTEST_ARGS.[arch] if defined.
+override GTEST_ARGS.real = \
+ $(call if_qemu,$(GTEST_ARGS.qemu.$(QEMU_ARCH)),$(GTEST_ARGS.host.$(HOST_ARCH)))
+
+define TEST_run
+  @$(ECHO) -n "TEST		$(TARGET_OR_MEMBER) "
+  @$(ECHO) "[$(COLOR_GREEN)RUN$(COLOR_RESET)]"
+  $(QUIET)(echo 1 > "$(OUT)$(TARGET_OR_MEMBER).status.test")
+  $(QUIET)(echo $(ROOT_CMD) SRC="$(SRC)" $(QEMU_CMD) $(VALGRIND_CMD) \
+    "$(strip $(call if_qemu, $(SYSROOT_OUT),$(OUT))$(TARGET_OR_MEMBER))" \
+      $(if $(filter-out 0,$(words $(GTEST_ARGS.real))),$(GTEST_ARGS.real),\
+           $(GTEST_ARGS)) >> "$(OUT)$(TARGET_OR_MEMBER).setup.test")
+  -$(QUIET)$(call if_qemu,$(SUDO_CMD) $(UNSHARE_CMD) -m) $(SHELL) \
+      $(OUT)$(TARGET_OR_MEMBER).setup.test \
+  && echo 0 > "$(OUT)$(TARGET_OR_MEMBER).status.test"
+endef
+
+# Recursive list reversal so that we get RMDIR_ON_CLEAN in reverse order.
+define reverse
+$(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1))
+endef
+
+clean: qemu_clean
+clean: CLEAN($(OUT)*.d) CLEAN($(OUT)*.o) CLEAN($(OUT)*.debug)
+clean: CLEAN($(OUT)*.test) CLEAN($(OUT)*.depends)
+clean: CLEAN($(OUT)*.gcno) CLEAN($(OUT)*.gcda) CLEAN($(OUT)*.gcov)
+clean: CLEAN($(OUT)lcov-coverage.info) CLEAN($(OUT)lcov-html)
+
+clean:
+	$(QUIET)# Always delete the containing directory last.
+	$(call silent_rmdir,$(OUT))
+
+FORCE: ;
+# Empty rule for use when no special targets are needed, like large_tests
+NONE:
+
+.PHONY: clean NONE valgrind NONE
+.DEFAULT_GOAL  :=  all
+# Don't let make blow away "intermediates"
+.PRECIOUS: %.pic.o %.pie.o %.a %.pic.a %.pie.a %.test
+
+# Start accruing build info
+OUT_DIRS = $(OUT)
+LD_DIRS = $(OUT)
+SRC_DIRS = $(SRC)
+
+include $(wildcard $(OUT)*.d)
+SUBMODULE_DIRS = $(wildcard $(SRC)/*/module.mk)
+include $(SUBMODULE_DIRS)
+
+
+else  ## In duplicate inclusions of common.mk
+
+# Get the current inclusion directory without a trailing slash
+MODULE := $(patsubst %/,%, \
+           $(dir $(lastword $(filter-out %common.mk,$(MAKEFILE_LIST)))))
+MODULE := $(subst $(SRC)/,,$(MODULE))
+MODULE_NAME := $(subst /,_,$(MODULE))
+#VPATH := $(MODULE):$(VPATH)
+
+
+# Depth first
+$(eval OUT_DIRS += $(OUT)$(MODULE))
+$(eval SRC_DIRS += $(OUT)$(MODULE))
+$(eval LD_DIRS := $(LD_DIRS):$(OUT)$(MODULE))
+
+# Add the defaults from this dir to rm_clean
+clean: CLEAN($(OUT)$(MODULE)/*.d) CLEAN($(OUT)$(MODULE)/*.o)
+clean: CLEAN($(OUT)$(MODULE)/*.debug) CLEAN($(OUT)$(MODULE)/*.test)
+clean: CLEAN($(OUT)$(MODULE)/*.depends)
+clean: CLEAN($(OUT)$(MODULE)/*.gcno) CLEAN($(OUT)$(MODULE)/*.gcda)
+clean: CLEAN($(OUT)$(MODULE)/*.gcov) CLEAN($(OUT)lcov-coverage.info)
+clean: CLEAN($(OUT)lcov-html)
+
+$(info + submodule: $(MODULE_NAME))
+# We must eval otherwise they may be dropped.
+MODULE_C_OBJECTS = $(patsubst $(SRC)/$(MODULE)/%.c,$(MODULE)/%.o,\
+  $(wildcard $(SRC)/$(MODULE)/*.c))
+$(eval $(MODULE_NAME)_C_OBJECTS ?= $(MODULE_C_OBJECTS))
+MODULE_CXX_OBJECTS = $(patsubst $(SRC)/$(MODULE)/%.cc,$(MODULE)/%.o,\
+  $(wildcard $(SRC)/$(MODULE)/*.cc))
+$(eval $(MODULE_NAME)_CXX_OBJECTS ?= $(MODULE_CXX_OBJECTS))
+
+# Note, $(MODULE) is implicit in the path to the %.c.
+# See $(C_OBJECTS) for more details.
+# Register rules for the module objects.
+$(eval $(call add_object_rules,$(MODULE_C_OBJECTS),CC,c,CFLAGS,$(SRC)/))
+$(eval $(call add_object_rules,$(MODULE_CXX_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+
+# Continue recursive inclusion of module.mk files
+SUBMODULE_DIRS = $(wildcard $(SRC)/$(MODULE)/*/module.mk)
+include $(wildcard $(OUT)$(MODULE)/*.d)
+include $(SUBMODULE_DIRS)
+
+endif
+endif  ## pass-to-subcall wrapper for relocating the call directory
diff --git a/minijail/elfparse.c b/minijail/elfparse.c
new file mode 100644
index 0000000..cd032af
--- /dev/null
+++ b/minijail/elfparse.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "elfparse.h"
+
+int is_elf_magic (const uint8_t *buf)
+{
+	return (buf[EI_MAG0] == ELFMAG0) &&
+	       (buf[EI_MAG1] == ELFMAG1) &&
+	       (buf[EI_MAG2] == ELFMAG2) &&
+	       (buf[EI_MAG3] == ELFMAG3);
+}
+
+#define parseElftemplate(bit)                                                \
+ElfType parseElf ## bit(FILE *elf_file, uint8_t *pHead, int little_endian)   \
+{                                                                            \
+	ElfType                      ret          = ELFSTATIC;               \
+	Minijail_Elf ## bit ## _Ehdr *pHeader     = NULL;                    \
+	Minijail_Elf ## bit ## _Phdr pheader      = { 0 };                   \
+	uint32_t                     i            = 0;                       \
+	                                                                     \
+	if (!elf_file || !pHead)                                             \
+		return ELFERROR;                                             \
+	                                                                     \
+	pHeader = (Minijail_Elf ## bit ## _Ehdr *)pHead;                     \
+	if (little_endian) {                                                 \
+		pHeader->e_phoff = le ## bit ## toh(pHeader->e_phoff);       \
+		pHeader->e_phentsize = le16toh(pHeader->e_phentsize);        \
+		pHeader->e_phnum = le16toh(pHeader->e_phnum);                \
+	} else {                                                             \
+		pHeader->e_phoff = be ## bit ## toh(pHeader->e_phoff);       \
+		pHeader->e_phentsize = be16toh(pHeader->e_phentsize);        \
+		pHeader->e_phnum = be16toh(pHeader->e_phnum);                \
+	}                                                                    \
+	if (pHeader->e_phentsize != sizeof(Minijail_Elf ## bit ## _Phdr))    \
+		return ELFERROR;                                             \
+	                                                                     \
+	if (fseek(elf_file, pHeader->e_phoff, SEEK_SET) != 0)                \
+		return ELFERROR;                                             \
+	                                                                     \
+	for (i = 0; i < pHeader->e_phnum; i++) {                             \
+		if (fread(&pheader, sizeof(pheader), 1, elf_file) == 1) {    \
+			if (pheader.p_type == PT_INTERP) {                   \
+				ret = ELFDYNAMIC;                            \
+				break;                                       \
+			}                                                    \
+		} else {                                                     \
+			ret = ELFERROR;                                      \
+			break;                                               \
+		}                                                            \
+	}                                                                    \
+	return ret;                                                          \
+}
+parseElftemplate(64)
+parseElftemplate(32)
+
+/* Public function to determine the linkage of an ELF. */
+ElfType get_elf_linkage(const char *path)
+{
+	ElfType ret = ELFERROR;
+	FILE *elf_file = NULL;
+	uint8_t pHeader[HEADERSIZE] = "";
+
+	elf_file = fopen(path, "r");
+	if (elf_file) {
+		if (fread(pHeader, 1, HEADERSIZE, elf_file) == HEADERSIZE) {
+			if (is_elf_magic(pHeader)) {
+				if ((pHeader[EI_DATA] == ELFDATA2LSB) &&
+				    (pHeader[EI_CLASS] == ELFCLASS64)) {
+					/* 64-bit little endian. */
+					ret = parseElf64(elf_file, pHeader, 1);
+				} else if ((pHeader[EI_DATA] == ELFDATA2MSB) &&
+					  (pHeader[EI_CLASS] == ELFCLASS64)) {
+					/* 64-bit big endian. */
+					ret = parseElf64(elf_file, pHeader, 0);
+				} else if ((pHeader[EI_DATA] == ELFDATA2LSB) &&
+					  (pHeader[EI_CLASS] == ELFCLASS32)) {
+					/* 32-bit little endian. */
+					ret = parseElf32(elf_file, pHeader, 1);
+				} else if ((pHeader[EI_DATA] == ELFDATA2MSB) &&
+					  (pHeader[EI_CLASS] == ELFCLASS32)) {
+					/* 32-bit big endian. */
+					ret = parseElf32(elf_file, pHeader, 0);
+				}
+			} else {
+				/*
+				 * The binary is not an ELF. We assume it's a
+				 * script. We should parse the #! line and
+				 * check the interpreter to guard against
+				 * static interpreters escaping the sandbox.
+				 * As Minijail is only called from the rootfs
+				 * it was deemed not necessary to check this.
+				 * So we will just let execve(2) decide if this
+				 * is valid.
+				 */
+				ret = ELFDYNAMIC;
+			}
+		} else {
+			/*
+			 * The file is smaller than |HEADERSIZE| bytes.
+			 * We assume it's a short script. See above for
+			 * reasoning on scripts.
+			 */
+			ret = ELFDYNAMIC;
+		}
+		fclose(elf_file);
+	}
+	return ret;
+}
diff --git a/minijail/elfparse.h b/minijail/elfparse.h
new file mode 100644
index 0000000..599eb11
--- /dev/null
+++ b/minijail/elfparse.h
@@ -0,0 +1,105 @@
+/* elfparse.h
+ * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Elf parsing.
+ */
+
+#ifndef _ELFPARSE_H_
+#define _ELFPARSE_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <elf.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <endian.h>
+#include <string.h>
+
+/*
+ * These structs come from elf.h
+ * The version in elf.h do not pack these structs so
+ * portability could be an issue.
+ * The compiler could mess with aligmment depending on arch
+ * so I'm redefining them here and packing them to 1-byte alignment.
+ */
+#if !defined(EI_NIDENT)
+#define EI_NIDENT (16)
+#endif
+#pragma pack(push)
+#pragma pack(1)
+typedef struct
+{
+	unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+	Elf32_Half    e_type;             /* Object file type */
+	Elf32_Half    e_machine;          /* Architecture */
+	Elf32_Word    e_version;          /* Object file version */
+	Elf32_Addr    e_entry;            /* Entry point virtual address */
+	Elf32_Off     e_phoff;            /* Program header table file offset */
+	Elf32_Off     e_shoff;            /* Section header table file offset */
+	Elf32_Word    e_flags;            /* Processor-specific flags */
+	Elf32_Half    e_ehsize;           /* ELF header size in bytes */
+	Elf32_Half    e_phentsize;        /* Program header table entry size */
+	Elf32_Half    e_phnum;            /* Program header table entry count */
+	Elf32_Half    e_shentsize;        /* Section header table entry size */
+	Elf32_Half    e_shnum;            /* Section header table entry count */
+	Elf32_Half    e_shstrndx;         /* Section header string table index */
+} Minijail_Elf32_Ehdr;
+
+typedef struct
+{
+	unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+	Elf64_Half    e_type;             /* Object file type */
+	Elf64_Half    e_machine;          /* Architecture */
+	Elf64_Word    e_version;          /* Object file version */
+	Elf64_Addr    e_entry;            /* Entry point virtual address */
+	Elf64_Off     e_phoff;            /* Program header table file offset */
+	Elf64_Off     e_shoff;            /* Section header table file offset */
+	Elf64_Word    e_flags;            /* Processor-specific flags */
+	Elf64_Half    e_ehsize;           /* ELF header size in bytes */
+	Elf64_Half    e_phentsize;        /* Program header table entry size */
+	Elf64_Half    e_phnum;            /* Program header table entry count */
+	Elf64_Half    e_shentsize;        /* Section header table entry size */
+	Elf64_Half    e_shnum;            /* Section header table entry count */
+	Elf64_Half    e_shstrndx;         /* Section header string table index */
+} Minijail_Elf64_Ehdr;
+
+typedef struct
+{
+	Elf32_Word      p_type;           /* Segment type */
+	Elf32_Off       p_offset;         /* Segment file offset */
+	Elf32_Addr      p_vaddr;          /* Segment virtual address */
+	Elf32_Addr      p_paddr;          /* Segment physical address */
+	Elf32_Word      p_filesz;         /* Segment size in file */
+	Elf32_Word      p_memsz;          /* Segment size in memory */
+	Elf32_Word      p_flags;          /* Segment flags */
+	Elf32_Word      p_align;          /* Segment alignment */
+} Minijail_Elf32_Phdr;
+
+typedef struct
+{
+	Elf64_Word      p_type;           /* Segment type */
+	Elf64_Word      p_flags;          /* Segment flags */
+	Elf64_Off       p_offset;         /* Segment file offset */
+	Elf64_Addr      p_vaddr;          /* Segment virtual address */
+	Elf64_Addr      p_paddr;          /* Segment physical address */
+	Elf64_Xword     p_filesz;         /* Segment size in file */
+	Elf64_Xword     p_memsz;          /* Segment size in memory */
+	Elf64_Xword     p_align;          /* Segment alignment */
+} Minijail_Elf64_Phdr;
+#pragma pack(pop)
+/* End of definitions from elf.h */
+
+enum ElfTypeEnum { ELFERROR=0, ELFSTATIC=1, ELFDYNAMIC=2 };
+typedef enum ElfTypeEnum ElfType;
+
+/*
+ * This is the initial amount of the ELF file we try and read.
+ * It is the same value that the kernel uses (BINPRM_BUF_SIZE).
+ */
+#define HEADERSIZE  128
+
+ElfType get_elf_linkage(const char *path);
+
+#endif /* _ELFPARSE_H_ */
diff --git a/minijail/examples/drop_privs.cpp b/minijail/examples/drop_privs.cpp
new file mode 100644
index 0000000..d2b0e17
--- /dev/null
+++ b/minijail/examples/drop_privs.cpp
@@ -0,0 +1,73 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <sys/types.h>
+#include <sys/capability.h>
+#include <unistd.h>
+
+#include <libminijail.h>
+
+#include <android-base/logging.h>
+
+gid_t groups[] = { 1001, 1002 };
+
+void log_resugid() {
+    uid_t ruid, euid, suid;
+    gid_t rgid, egid, sgid;
+    getresuid(&ruid, &euid, &suid);
+    getresgid(&rgid, &egid, &sgid);
+
+    LOG(INFO) << "ruid " << ruid << " euid " << euid << " suid " << suid;
+    LOG(INFO) << "rgid " << rgid << " egid " << egid << " sgid " << sgid;
+
+    int nsupp_groups = getgroups(0, NULL);
+    if (nsupp_groups < 0) {
+        PLOG(FATAL) << "getgroups(0)";
+    }
+    if (nsupp_groups == 0) {
+        LOG(INFO) << "no supplemental groups";
+        return;
+    }
+
+    gid_t *list = (gid_t*)calloc((size_t)nsupp_groups, sizeof(gid_t));
+    nsupp_groups = getgroups(nsupp_groups, list);
+    if (nsupp_groups < 0) {
+        PLOG(FATAL) << "getgroups(nsupp_groups)";
+    }
+    for (size_t i = 0; i < (size_t)nsupp_groups; i++) {
+        LOG(INFO) << "supp gid " << i + 1 << " " << list[i];
+    }
+    free(list);
+}
+
+int main(void) {
+    log_resugid();
+    minijail *j = minijail_new();
+    minijail_change_user(j, "system");
+    minijail_change_group(j, "system");
+    minijail_set_supplementary_gids(j, sizeof(groups) / sizeof(groups[0]), groups);
+    // minijail_use_caps(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
+    // minijail_use_seccomp_filter(j);
+    // minijail_log_seccomp_filter_failures(j);
+    // minijail_parse_seccomp_filters(j, "/data/filter.policy");
+    minijail_enter(j);
+    log_resugid();
+    minijail_destroy(j);
+    // minijail *j2 = minijail_new();
+    // minijail_change_uid(j2, 5000);
+    // minijail_change_gid(j2, 5000);
+    // minijail_enter(j2);
+    // log_resugid();
+    return 0;
+}
diff --git a/minijail/gen_constants.sh b/minijail/gen_constants.sh
new file mode 100755
index 0000000..0f330b9
--- /dev/null
+++ b/minijail/gen_constants.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Generates a header file with a named constant table made up of "name", value
+# entries by including several build target header files and emitting the list
+# of defines.  Use of the preprocessor is needed to recursively include all
+# relevant headers.
+
+set -e
+
+if [ $# -ne 1 ] && [ $# -ne 2 ]; then
+  echo "Usage: $(basename "$0") OUTFILE"
+  echo "Usage: $(basename "$0") CC OUTFILE"
+  exit 1
+fi
+
+if [ $# -eq 2 ]; then
+  CC="$1"
+  shift
+fi
+OUTFILE="$1"
+
+INCLUDES='
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/prctl.h>
+#include <linux/sched.h>
+#include <stddef.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>'
+
+# Generate a dependency file which helps the build tool to see when it
+# should regenerate ${OUTFILE}.
+echo "${INCLUDES}" | ${CC} - -E -M -MF "${OUTFILE}.d.tmp"
+# Correct the output filename.
+(echo "${OUTFILE}: \\" ; sed -e 's/^-\.o://' -e 's/^-://' "${OUTFILE}.d.tmp") \
+  > "${OUTFILE}.d"
+rm "${OUTFILE}.d.tmp"
+
+# sed expression which extracts constants and converts them from:
+#   #define AT_FDWCD foo
+# to:
+# #ifdef AT_FDCWD
+#   { "AT_FDWCD", AT_FDCWD },
+# endif
+SED_MULTILINE='s@#define ([[:upper:]][[:upper:]0-9_]*).*@#ifdef \1\
+  { "\1", (unsigned long) \1 },\
+#endif  // \1@'
+
+# Passes the previous list of #includes to the C preprocessor and prints out
+# all #defines whose name is all-caps.  Excludes a few symbols that are known
+# macro functions that don't evaluate to a constant.
+cat <<-EOF > "${OUTFILE}"
+/* GENERATED BY MAKEFILE */
+$INCLUDES
+
+#include "libconstants.h"
+const struct constant_entry constant_table[] = {
+$(echo "$INCLUDES" | \
+  ${CC} -dD - -E | \
+  grep -E '^#define [[:upper:]][[:upper:]0-9_]*(\s)+[[:alnum:]]' | \
+  grep -Ev '(SIGRTMAX|SIGRTMIN|SIG_|NULL)' | \
+  sort -u | \
+  sed -Ee "${SED_MULTILINE}")
+  { NULL, 0 },
+};
+EOF
diff --git a/minijail/gen_syscalls.sh b/minijail/gen_syscalls.sh
new file mode 100755
index 0000000..f31031b
--- /dev/null
+++ b/minijail/gen_syscalls.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Generates a header file with a system call table made up of "name",
+# syscall_nr entries by including the build target <asm/unistd.h> and
+# emitting the list of defines.  Use of the compiler is needed to
+# dereference the actual provider of syscall definitions.
+#   E.g., asm/unistd_32.h or asm/unistd_64.h, etc.
+
+set -e
+
+if [ $# -ne 1 ] && [ $# -ne 2 ]; then
+  echo "Usage: $(basename "$0") OUTFILE"
+  echo "Usage: $(basename "$0") CC OUTFILE"
+  exit 1
+fi
+
+if [ $# -eq 2 ]; then
+  CC="$1"
+  shift
+fi
+OUTFILE="$1"
+
+# Generate a dependency file which helps the build tool to see when it
+# should regenerate ${OUTFILE}.
+echo '#include <asm/unistd.h>' | ${CC} - -E -M -MF "${OUTFILE}.d.tmp"
+# Correct the output filename.
+(echo "${OUTFILE}: \\" ; sed -e 's/^-\.o://' -e 's/^-://' "${OUTFILE}.d.tmp") \
+  > "${OUTFILE}.d"
+rm "${OUTFILE}.d.tmp"
+
+# sed expression which extracts system calls that are
+# defined via asm/unistd.h.  It converts them from:
+#  #define __NR_read foo
+# to:
+# #ifdef __NR_read
+#  { "read", __NR_read },
+# #endif
+SED_MULTILINE='s/#define __(ARM_)?(NR_)([[:lower:]0-9_]*) (.*)$/#ifdef __\1\2\3\
+{ "\1\3", __\1\2\3 },\
+#endif/g p;'
+
+cat <<-EOF > "${OUTFILE}"
+/* GENERATED BY MAKEFILE */
+#include <stddef.h>
+#include <asm/unistd.h>
+#include "libsyscalls.h"
+const struct syscall_entry syscall_table[] = {
+$(echo '#include <asm/unistd.h>' | \
+  ${CC} -dD - -E | sed -Ene "${SED_MULTILINE}")
+  { NULL, -1 },
+};
+EOF
diff --git a/minijail/libconstants.h b/minijail/libconstants.h
new file mode 100644
index 0000000..c289955
--- /dev/null
+++ b/minijail/libconstants.h
@@ -0,0 +1,15 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef MINIJAIL_LIBCONSTANTS_H_
+#define MINIJAIL_LIBCONSTANTS_H_
+
+struct constant_entry {
+	const char *name;
+	unsigned long value;
+};
+
+extern const struct constant_entry constant_table[];
+
+#endif  /* MINIJAIL_LIBCONSTANTS_H_ */
diff --git a/minijail/libminijail-private.h b/minijail/libminijail-private.h
new file mode 100644
index 0000000..926559f
--- /dev/null
+++ b/minijail/libminijail-private.h
@@ -0,0 +1,94 @@
+/* libminijail-private.h
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Values shared between libminijailpreload and libminijail, but not visible to
+ * the outside world.
+ */
+
+#ifndef LIBMINIJAIL_PRIVATE_H
+#define LIBMINIJAIL_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Explicitly declare exported functions so that -fvisibility tricks
+ * can be used for testing and minimal symbol leakage occurs.
+ */
+#define API __attribute__ ((visibility("default")))
+
+static const char *kFdEnvVar = "__MINIJAIL_FD";
+static const char *kLdPreloadEnvVar = "LD_PRELOAD";
+
+struct minijail;
+
+/* minijail_size: returns the size (in bytes) of @j if marshalled
+ * @j jail to compute size of
+ *
+ * Returns 0 on error.
+ */
+extern size_t minijail_size(const struct minijail *j);
+
+/* minijail_marshal: serializes @j to @buf
+ * @j    minijail to serialize
+ * @buf  buffer to serialize to
+ * @size size of @buf
+ *
+ * Returns 0 on success.
+ *
+ * Writes |j| to |buf| such that it can be reparsed by the same
+ * library on the same architecture.  This is meant to be used
+ * by minijail0.c and libminijailpreload.c.  minijail flags that
+ * require minijail_run() will be excluded.
+ *
+ * The marshalled data is not robust to differences between the child
+ * and parent process (personality, etc).
+ */
+extern int minijail_marshal(const struct minijail *j,
+                            char *buf,
+                            size_t size);
+
+/* minijail_unmarshal: initializes @j from @serialized
+ * @j          minijail to initialize
+ * @serialized serialized jail buffer
+ * @length     length of buffer
+ *
+ * Returns 0 on success.
+ */
+extern int minijail_unmarshal(struct minijail *j,
+                              char *serialized,
+                              size_t length);
+
+/* minijail_from_fd: builds @j from @fd
+ * @j  minijail to initialize
+ * @fd fd to initialize from
+ *
+ * Returns 0 on success.
+ */
+extern int minijail_from_fd(int fd, struct minijail *j);
+
+/* minijail_to_fd: sends @j over @fd
+ * @j  minijail to send
+ * @fd fd to send over
+ *
+ * Returns 0 on success.
+ */
+extern int minijail_to_fd(struct minijail *j, int fd);
+
+/* minijail_preexec: strips @j of all options handled by minijail_enter()
+ * @j jail to strip
+ */
+extern void minijail_preexec(struct minijail *j);
+
+/* minijail_preenter: strips @j of all options handled by minijail_run()
+ * @j jail to strip
+ */
+extern void minijail_preenter(struct minijail *j);
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#endif /* !LIBMINIJAIL_PRIVATE_H */
diff --git a/minijail/libminijail.c b/minijail/libminijail.c
new file mode 100644
index 0000000..8f63b85
--- /dev/null
+++ b/minijail/libminijail.c
@@ -0,0 +1,2166 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#define _BSD_SOURCE
+#define _DEFAULT_SOURCE
+#define _GNU_SOURCE
+
+#include <asm/unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <linux/capability.h>
+#include <pwd.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/capability.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "libminijail.h"
+#include "libminijail-private.h"
+
+#include "signal_handler.h"
+#include "syscall_filter.h"
+#include "util.h"
+
+#ifdef HAVE_SECUREBITS_H
+# include <linux/securebits.h>
+#else
+# define SECURE_ALL_BITS	0x55
+# define SECURE_ALL_LOCKS	(SECURE_ALL_BITS << 1)
+#endif
+/* For kernels < 4.3. */
+#define OLD_SECURE_ALL_BITS	0x15
+#define OLD_SECURE_ALL_LOCKS	(OLD_SECURE_ALL_BITS << 1)
+
+/*
+ * Assert the value of SECURE_ALL_BITS at compile-time.
+ * Brillo devices are currently compiled against 4.4 kernel headers. Kernel 4.3
+ * added a new securebit.
+ * When a new securebit is added, the new SECURE_ALL_BITS mask will return EPERM
+ * when used on older kernels. The compile-time assert will catch this situation
+ * at compile time.
+ */
+#ifdef __BRILLO__
+_Static_assert(SECURE_ALL_BITS == 0x55, "SECURE_ALL_BITS == 0x55.");
+#endif
+
+/* Until these are reliably available in linux/prctl.h. */
+#ifndef PR_SET_SECCOMP
+# define PR_SET_SECCOMP 22
+#endif
+
+#ifndef PR_ALT_SYSCALL
+# define PR_ALT_SYSCALL 0x43724f53
+#endif
+
+/* For seccomp_filter using BPF. */
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+#endif
+#ifndef SECCOMP_MODE_FILTER
+# define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
+#endif
+
+/* New cgroup namespace might not be in linux-headers yet. */
+#ifndef CLONE_NEWCGROUP
+# define CLONE_NEWCGROUP 0x02000000
+#endif
+
+#define MAX_CGROUPS 10 /* 10 different controllers supported by Linux. */
+
+struct mountpoint {
+	char *src;
+	char *dest;
+	char *type;
+	char *data;
+	int has_data;
+	unsigned long flags;
+	struct mountpoint *next;
+};
+
+struct minijail {
+	/*
+	 * WARNING: if you add a flag here you need to make sure it's
+	 * accounted for in minijail_pre{enter|exec}() below.
+	 */
+	struct {
+		int uid:1;
+		int gid:1;
+		int usergroups:1;
+		int suppl_gids:1;
+		int use_caps:1;
+		int capbset_drop:1;
+		int vfs:1;
+		int enter_vfs:1;
+		int skip_remount_private:1;
+		int pids:1;
+		int ipc:1;
+		int net:1;
+		int enter_net:1;
+		int ns_cgroups:1;
+		int userns:1;
+		int seccomp:1;
+		int remount_proc_ro:1;
+		int no_new_privs:1;
+		int seccomp_filter:1;
+		int log_seccomp_filter:1;
+		int chroot:1;
+		int pivot_root:1;
+		int mount_tmp:1;
+		int do_init:1;
+		int pid_file:1;
+		int cgroups:1;
+		int alt_syscall:1;
+		int reset_signal_mask:1;
+	} flags;
+	uid_t uid;
+	gid_t gid;
+	gid_t usergid;
+	char *user;
+	size_t suppl_gid_count;
+	gid_t *suppl_gid_list;
+	uint64_t caps;
+	uint64_t cap_bset;
+	pid_t initpid;
+	int mountns_fd;
+	int netns_fd;
+	char *chrootdir;
+	char *pid_file_path;
+	char *uidmap;
+	char *gidmap;
+	size_t filter_len;
+	struct sock_fprog *filter_prog;
+	char *alt_syscall_table;
+	struct mountpoint *mounts_head;
+	struct mountpoint *mounts_tail;
+	size_t mounts_count;
+	char *cgroups[MAX_CGROUPS];
+	size_t cgroup_count;
+};
+
+/*
+ * Strip out flags meant for the parent.
+ * We keep things that are not inherited across execve(2) (e.g. capabilities),
+ * or are easier to set after execve(2) (e.g. seccomp filters).
+ */
+void minijail_preenter(struct minijail *j)
+{
+	j->flags.vfs = 0;
+	j->flags.enter_vfs = 0;
+	j->flags.skip_remount_private = 0;
+	j->flags.remount_proc_ro = 0;
+	j->flags.pids = 0;
+	j->flags.do_init = 0;
+	j->flags.pid_file = 0;
+	j->flags.cgroups = 0;
+}
+
+/*
+ * Strip out flags meant for the child.
+ * We keep things that are inherited across execve(2).
+ */
+void minijail_preexec(struct minijail *j)
+{
+	int vfs = j->flags.vfs;
+	int enter_vfs = j->flags.enter_vfs;
+	int skip_remount_private = j->flags.skip_remount_private;
+	int remount_proc_ro = j->flags.remount_proc_ro;
+	int userns = j->flags.userns;
+	if (j->user)
+		free(j->user);
+	j->user = NULL;
+	if (j->suppl_gid_list)
+		free(j->suppl_gid_list);
+	j->suppl_gid_list = NULL;
+	memset(&j->flags, 0, sizeof(j->flags));
+	/* Now restore anything we meant to keep. */
+	j->flags.vfs = vfs;
+	j->flags.enter_vfs = enter_vfs;
+	j->flags.skip_remount_private = skip_remount_private;
+	j->flags.remount_proc_ro = remount_proc_ro;
+	j->flags.userns = userns;
+	/* Note, |pids| will already have been used before this call. */
+}
+
+/* Minijail API. */
+
+struct minijail API *minijail_new(void)
+{
+	return calloc(1, sizeof(struct minijail));
+}
+
+void API minijail_change_uid(struct minijail *j, uid_t uid)
+{
+	if (uid == 0)
+		die("useless change to uid 0");
+	j->uid = uid;
+	j->flags.uid = 1;
+}
+
+void API minijail_change_gid(struct minijail *j, gid_t gid)
+{
+	if (gid == 0)
+		die("useless change to gid 0");
+	j->gid = gid;
+	j->flags.gid = 1;
+}
+
+void API minijail_set_supplementary_gids(struct minijail *j, size_t size,
+					 const gid_t *list)
+{
+	size_t i;
+
+	if (j->flags.usergroups)
+		die("cannot inherit *and* set supplementary groups");
+
+	if (size == 0) {
+		/* Clear supplementary groups. */
+		j->suppl_gid_list = NULL;
+		j->suppl_gid_count = 0;
+		j->flags.suppl_gids = 1;
+		return;
+	}
+
+	/* Copy the gid_t array. */
+	j->suppl_gid_list = calloc(size, sizeof(gid_t));
+	if (!j->suppl_gid_list) {
+		die("failed to allocate internal supplementary group array");
+	}
+	for (i = 0; i < size; i++) {
+		j->suppl_gid_list[i] = list[i];
+	}
+	j->suppl_gid_count = size;
+	j->flags.suppl_gids = 1;
+}
+
+int API minijail_change_user(struct minijail *j, const char *user)
+{
+	char *buf = NULL;
+	struct passwd pw;
+	struct passwd *ppw = NULL;
+	ssize_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
+	if (sz == -1)
+		sz = 65536;	/* your guess is as good as mine... */
+
+	/*
+	 * sysconf(_SC_GETPW_R_SIZE_MAX), under glibc, is documented to return
+	 * the maximum needed size of the buffer, so we don't have to search.
+	 */
+	buf = malloc(sz);
+	if (!buf)
+		return -ENOMEM;
+	getpwnam_r(user, &pw, buf, sz, &ppw);
+	/*
+	 * We're safe to free the buffer here. The strings inside |pw| point
+	 * inside |buf|, but we don't use any of them; this leaves the pointers
+	 * dangling but it's safe. |ppw| points at |pw| if getpwnam_r(3)
+	 * succeeded.
+	 */
+	free(buf);
+	/* getpwnam_r(3) does *not* set errno when |ppw| is NULL. */
+	if (!ppw)
+		return -1;
+	minijail_change_uid(j, ppw->pw_uid);
+	j->user = strdup(user);
+	if (!j->user)
+		return -ENOMEM;
+	j->usergid = ppw->pw_gid;
+	return 0;
+}
+
+int API minijail_change_group(struct minijail *j, const char *group)
+{
+	char *buf = NULL;
+	struct group gr;
+	struct group *pgr = NULL;
+	ssize_t sz = sysconf(_SC_GETGR_R_SIZE_MAX);
+	if (sz == -1)
+		sz = 65536;	/* and mine is as good as yours, really */
+
+	/*
+	 * sysconf(_SC_GETGR_R_SIZE_MAX), under glibc, is documented to return
+	 * the maximum needed size of the buffer, so we don't have to search.
+	 */
+	buf = malloc(sz);
+	if (!buf)
+		return -ENOMEM;
+	getgrnam_r(group, &gr, buf, sz, &pgr);
+	/*
+	 * We're safe to free the buffer here. The strings inside gr point
+	 * inside buf, but we don't use any of them; this leaves the pointers
+	 * dangling but it's safe. pgr points at gr if getgrnam_r succeeded.
+	 */
+	free(buf);
+	/* getgrnam_r(3) does *not* set errno when |pgr| is NULL. */
+	if (!pgr)
+		return -1;
+	minijail_change_gid(j, pgr->gr_gid);
+	return 0;
+}
+
+void API minijail_use_seccomp(struct minijail *j)
+{
+	j->flags.seccomp = 1;
+}
+
+void API minijail_no_new_privs(struct minijail *j)
+{
+	j->flags.no_new_privs = 1;
+}
+
+void API minijail_use_seccomp_filter(struct minijail *j)
+{
+	j->flags.seccomp_filter = 1;
+}
+
+void API minijail_log_seccomp_filter_failures(struct minijail *j)
+{
+	j->flags.log_seccomp_filter = 1;
+}
+
+void API minijail_use_caps(struct minijail *j, uint64_t capmask)
+{
+	/*
+	 * 'minijail_use_caps' configures a runtime-capabilities-only
+	 * environment, including a bounding set matching the thread's runtime
+	 * (permitted|inheritable|effective) sets.
+	 * Therefore, it will override any existing bounding set configurations
+	 * since the latter would allow gaining extra runtime capabilities from
+	 * file capabilities.
+	 */
+	if (j->flags.capbset_drop) {
+		warn("overriding bounding set configuration");
+		j->cap_bset = 0;
+		j->flags.capbset_drop = 0;
+	}
+	j->caps = capmask;
+	j->flags.use_caps = 1;
+}
+
+void API minijail_capbset_drop(struct minijail *j, uint64_t capmask)
+{
+	if (j->flags.use_caps) {
+		/*
+		 * 'minijail_use_caps' will have already configured a capability
+		 * bounding set matching the (permitted|inheritable|effective)
+		 * sets. Abort if the user tries to configure a separate
+		 * bounding set. 'minijail_capbset_drop' and 'minijail_use_caps'
+		 * are mutually exclusive.
+		 */
+		die("runtime capabilities already configured, can't drop "
+		    "bounding set separately");
+	}
+	j->cap_bset = capmask;
+	j->flags.capbset_drop = 1;
+}
+
+void API minijail_reset_signal_mask(struct minijail *j)
+{
+	j->flags.reset_signal_mask = 1;
+}
+
+void API minijail_namespace_vfs(struct minijail *j)
+{
+	j->flags.vfs = 1;
+}
+
+void API minijail_namespace_enter_vfs(struct minijail *j, const char *ns_path)
+{
+	int ns_fd = open(ns_path, O_RDONLY | O_CLOEXEC);
+	if (ns_fd < 0) {
+		pdie("failed to open namespace '%s'", ns_path);
+	}
+	j->mountns_fd = ns_fd;
+	j->flags.enter_vfs = 1;
+}
+
+void API minijail_skip_remount_private(struct minijail *j)
+{
+	j->flags.skip_remount_private = 1;
+}
+
+void API minijail_namespace_pids(struct minijail *j)
+{
+	j->flags.vfs = 1;
+	j->flags.remount_proc_ro = 1;
+	j->flags.pids = 1;
+	j->flags.do_init = 1;
+}
+
+void API minijail_namespace_ipc(struct minijail *j)
+{
+	j->flags.ipc = 1;
+}
+
+void API minijail_namespace_net(struct minijail *j)
+{
+	j->flags.net = 1;
+}
+
+void API minijail_namespace_enter_net(struct minijail *j, const char *ns_path)
+{
+	int ns_fd = open(ns_path, O_RDONLY | O_CLOEXEC);
+	if (ns_fd < 0) {
+		pdie("failed to open namespace '%s'", ns_path);
+	}
+	j->netns_fd = ns_fd;
+	j->flags.enter_net = 1;
+}
+
+void API minijail_namespace_cgroups(struct minijail *j)
+{
+	j->flags.ns_cgroups = 1;
+}
+
+void API minijail_remount_proc_readonly(struct minijail *j)
+{
+	j->flags.vfs = 1;
+	j->flags.remount_proc_ro = 1;
+}
+
+void API minijail_namespace_user(struct minijail *j)
+{
+	j->flags.userns = 1;
+}
+
+int API minijail_uidmap(struct minijail *j, const char *uidmap)
+{
+	j->uidmap = strdup(uidmap);
+	if (!j->uidmap)
+		return -ENOMEM;
+	char *ch;
+	for (ch = j->uidmap; *ch; ch++) {
+		if (*ch == ',')
+			*ch = '\n';
+	}
+	return 0;
+}
+
+int API minijail_gidmap(struct minijail *j, const char *gidmap)
+{
+	j->gidmap = strdup(gidmap);
+	if (!j->gidmap)
+		return -ENOMEM;
+	char *ch;
+	for (ch = j->gidmap; *ch; ch++) {
+		if (*ch == ',')
+			*ch = '\n';
+	}
+	return 0;
+}
+
+void API minijail_inherit_usergroups(struct minijail *j)
+{
+	j->flags.usergroups = 1;
+}
+
+void API minijail_run_as_init(struct minijail *j)
+{
+	/*
+	 * Since the jailed program will become 'init' in the new PID namespace,
+	 * Minijail does not need to fork an 'init' process.
+	 */
+	j->flags.do_init = 0;
+}
+
+int API minijail_enter_chroot(struct minijail *j, const char *dir)
+{
+	if (j->chrootdir)
+		return -EINVAL;
+	j->chrootdir = strdup(dir);
+	if (!j->chrootdir)
+		return -ENOMEM;
+	j->flags.chroot = 1;
+	return 0;
+}
+
+int API minijail_enter_pivot_root(struct minijail *j, const char *dir)
+{
+	if (j->chrootdir)
+		return -EINVAL;
+	j->chrootdir = strdup(dir);
+	if (!j->chrootdir)
+		return -ENOMEM;
+	j->flags.pivot_root = 1;
+	return 0;
+}
+
+char API *minijail_get_original_path(struct minijail *j,
+				     const char *path_inside_chroot)
+{
+	struct mountpoint *b;
+
+	b = j->mounts_head;
+	while (b) {
+		/*
+		 * If |path_inside_chroot| is the exact destination of a
+		 * mount, then the original path is exactly the source of
+		 * the mount.
+		 *  for example: "-b /some/path/exe,/chroot/path/exe"
+		 *    mount source = /some/path/exe, mount dest =
+		 *    /chroot/path/exe Then when getting the original path of
+		 *    "/chroot/path/exe", the source of that mount,
+		 *    "/some/path/exe" is what should be returned.
+		 */
+		if (!strcmp(b->dest, path_inside_chroot))
+			return strdup(b->src);
+
+		/*
+		 * If |path_inside_chroot| is within the destination path of a
+		 * mount, take the suffix of the chroot path relative to the
+		 * mount destination path, and append it to the mount source
+		 * path.
+		 */
+		if (!strncmp(b->dest, path_inside_chroot, strlen(b->dest))) {
+			const char *relative_path =
+				path_inside_chroot + strlen(b->dest);
+			return path_join(b->src, relative_path);
+		}
+		b = b->next;
+	}
+
+	/* If there is a chroot path, append |path_inside_chroot| to that. */
+	if (j->chrootdir)
+		return path_join(j->chrootdir, path_inside_chroot);
+
+	/* No chroot, so the path outside is the same as it is inside. */
+	return strdup(path_inside_chroot);
+}
+
+void API minijail_mount_tmp(struct minijail *j)
+{
+	j->flags.mount_tmp = 1;
+}
+
+int API minijail_write_pid_file(struct minijail *j, const char *path)
+{
+	j->pid_file_path = strdup(path);
+	if (!j->pid_file_path)
+		return -ENOMEM;
+	j->flags.pid_file = 1;
+	return 0;
+}
+
+int API minijail_add_to_cgroup(struct minijail *j, const char *path)
+{
+	if (j->cgroup_count >= MAX_CGROUPS)
+		return -ENOMEM;
+	j->cgroups[j->cgroup_count] = strdup(path);
+	if (!j->cgroups[j->cgroup_count])
+		return -ENOMEM;
+	j->cgroup_count++;
+	j->flags.cgroups = 1;
+	return 0;
+}
+
+int API minijail_mount_with_data(struct minijail *j, const char *src,
+				 const char *dest, const char *type,
+				 unsigned long flags, const char *data)
+{
+	struct mountpoint *m;
+
+	if (*dest != '/')
+		return -EINVAL;
+	m = calloc(1, sizeof(*m));
+	if (!m)
+		return -ENOMEM;
+	m->dest = strdup(dest);
+	if (!m->dest)
+		goto error;
+	m->src = strdup(src);
+	if (!m->src)
+		goto error;
+	m->type = strdup(type);
+	if (!m->type)
+		goto error;
+	if (data) {
+		m->data = strdup(data);
+		if (!m->data)
+			goto error;
+		m->has_data = 1;
+	}
+	m->flags = flags;
+
+	info("mount %s -> %s type '%s'", src, dest, type);
+
+	/*
+	 * Force vfs namespacing so the mounts don't leak out into the
+	 * containing vfs namespace.
+	 */
+	minijail_namespace_vfs(j);
+
+	if (j->mounts_tail)
+		j->mounts_tail->next = m;
+	else
+		j->mounts_head = m;
+	j->mounts_tail = m;
+	j->mounts_count++;
+
+	return 0;
+
+error:
+	free(m->type);
+	free(m->src);
+	free(m->dest);
+	free(m);
+	return -ENOMEM;
+}
+
+int API minijail_mount(struct minijail *j, const char *src, const char *dest,
+		       const char *type, unsigned long flags)
+{
+	return minijail_mount_with_data(j, src, dest, type, flags, NULL);
+}
+
+int API minijail_bind(struct minijail *j, const char *src, const char *dest,
+		      int writeable)
+{
+	unsigned long flags = MS_BIND;
+
+	if (!writeable)
+		flags |= MS_RDONLY;
+
+	return minijail_mount(j, src, dest, "", flags);
+}
+
+static int seccomp_should_parse_filters(struct minijail *j)
+{
+	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL)) {
+		/*
+		 * |errno| will be set to EINVAL when seccomp has not been
+		 * compiled into the kernel. On certain platforms and kernel
+		 * versions this is not a fatal failure. In that case, and only
+		 * in that case, disable seccomp and skip loading the filters.
+		 */
+		if ((errno == EINVAL) && seccomp_can_softfail()) {
+			warn("not loading seccomp filters,"
+			     " seccomp not supported");
+			j->flags.seccomp_filter = 0;
+			j->flags.log_seccomp_filter = 0;
+			j->filter_len = 0;
+			j->filter_prog = NULL;
+			j->flags.no_new_privs = 0;
+			return 0;
+		}
+		/*
+		 * If |errno| != EINVAL or seccomp_can_softfail() is false,
+		 * we can proceed. Worst case scenario minijail_enter() will
+		 * abort() if seccomp fails.
+		 */
+	}
+	return 1;
+}
+
+static int parse_seccomp_filters(struct minijail *j, FILE *policy_file)
+{
+	struct sock_fprog *fprog = malloc(sizeof(struct sock_fprog));
+	if (compile_filter(policy_file, fprog, j->flags.log_seccomp_filter)) {
+		free(fprog);
+		return -1;
+	}
+
+	j->filter_len = fprog->len;
+	j->filter_prog = fprog;
+	return 0;
+}
+
+void API minijail_parse_seccomp_filters(struct minijail *j, const char *path)
+{
+	if (!seccomp_should_parse_filters(j))
+		return;
+
+	FILE *file = fopen(path, "r");
+	if (!file) {
+		pdie("failed to open seccomp filter file '%s'", path);
+	}
+
+	if (parse_seccomp_filters(j, file) != 0) {
+		die("failed to compile seccomp filter BPF program in '%s'",
+		    path);
+	}
+	fclose(file);
+}
+
+void API minijail_parse_seccomp_filters_from_fd(struct minijail *j, int fd)
+{
+	if (!seccomp_should_parse_filters(j))
+		return;
+
+	FILE *file = fdopen(fd, "r");
+	if (!file) {
+		pdie("failed to associate stream with fd %d", fd);
+	}
+
+	if (parse_seccomp_filters(j, file) != 0) {
+		die("failed to compile seccomp filter BPF program from fd %d",
+		    fd);
+	}
+	fclose(file);
+}
+
+int API minijail_use_alt_syscall(struct minijail *j, const char *table)
+{
+	j->alt_syscall_table = strdup(table);
+	if (!j->alt_syscall_table)
+		return -ENOMEM;
+	j->flags.alt_syscall = 1;
+	return 0;
+}
+
+struct marshal_state {
+	size_t available;
+	size_t total;
+	char *buf;
+};
+
+void marshal_state_init(struct marshal_state *state, char *buf,
+			size_t available)
+{
+	state->available = available;
+	state->buf = buf;
+	state->total = 0;
+}
+
+void marshal_append(struct marshal_state *state, void *src, size_t length)
+{
+	size_t copy_len = MIN(state->available, length);
+
+	/* Up to |available| will be written. */
+	if (copy_len) {
+		memcpy(state->buf, src, copy_len);
+		state->buf += copy_len;
+		state->available -= copy_len;
+	}
+	/* |total| will contain the expected length. */
+	state->total += length;
+}
+
+void marshal_mount(struct marshal_state *state, const struct mountpoint *m)
+{
+	marshal_append(state, m->src, strlen(m->src) + 1);
+	marshal_append(state, m->dest, strlen(m->dest) + 1);
+	marshal_append(state, m->type, strlen(m->type) + 1);
+	marshal_append(state, (char *)&m->has_data, sizeof(m->has_data));
+	if (m->has_data)
+		marshal_append(state, m->data, strlen(m->data) + 1);
+	marshal_append(state, (char *)&m->flags, sizeof(m->flags));
+}
+
+void minijail_marshal_helper(struct marshal_state *state,
+			     const struct minijail *j)
+{
+	struct mountpoint *m = NULL;
+	size_t i;
+
+	marshal_append(state, (char *)j, sizeof(*j));
+	if (j->user)
+		marshal_append(state, j->user, strlen(j->user) + 1);
+	if (j->suppl_gid_list) {
+		marshal_append(state, j->suppl_gid_list,
+			       j->suppl_gid_count * sizeof(gid_t));
+	}
+	if (j->chrootdir)
+		marshal_append(state, j->chrootdir, strlen(j->chrootdir) + 1);
+	if (j->alt_syscall_table) {
+		marshal_append(state, j->alt_syscall_table,
+			       strlen(j->alt_syscall_table) + 1);
+	}
+	if (j->flags.seccomp_filter && j->filter_prog) {
+		struct sock_fprog *fp = j->filter_prog;
+		marshal_append(state, (char *)fp->filter,
+			       fp->len * sizeof(struct sock_filter));
+	}
+	for (m = j->mounts_head; m; m = m->next) {
+		marshal_mount(state, m);
+	}
+	for (i = 0; i < j->cgroup_count; ++i)
+		marshal_append(state, j->cgroups[i], strlen(j->cgroups[i]) + 1);
+}
+
+size_t API minijail_size(const struct minijail *j)
+{
+	struct marshal_state state;
+	marshal_state_init(&state, NULL, 0);
+	minijail_marshal_helper(&state, j);
+	return state.total;
+}
+
+int minijail_marshal(const struct minijail *j, char *buf, size_t available)
+{
+	struct marshal_state state;
+	marshal_state_init(&state, buf, available);
+	minijail_marshal_helper(&state, j);
+	return (state.total > available);
+}
+
+int minijail_unmarshal(struct minijail *j, char *serialized, size_t length)
+{
+	size_t i;
+	size_t count;
+	int ret = -EINVAL;
+
+	if (length < sizeof(*j))
+		goto out;
+	memcpy((void *)j, serialized, sizeof(*j));
+	serialized += sizeof(*j);
+	length -= sizeof(*j);
+
+	/* Potentially stale pointers not used as signals. */
+	j->pid_file_path = NULL;
+	j->uidmap = NULL;
+	j->gidmap = NULL;
+	j->mounts_head = NULL;
+	j->mounts_tail = NULL;
+	j->filter_prog = NULL;
+
+	if (j->user) {		/* stale pointer */
+		char *user = consumestr(&serialized, &length);
+		if (!user)
+			goto clear_pointers;
+		j->user = strdup(user);
+		if (!j->user)
+			goto clear_pointers;
+	}
+
+	if (j->suppl_gid_list) {	/* stale pointer */
+		if (j->suppl_gid_count > NGROUPS_MAX) {
+			goto bad_gid_list;
+		}
+		size_t gid_list_size = j->suppl_gid_count * sizeof(gid_t);
+		void *gid_list_bytes =
+		    consumebytes(gid_list_size, &serialized, &length);
+		if (!gid_list_bytes)
+			goto bad_gid_list;
+
+		j->suppl_gid_list = calloc(j->suppl_gid_count, sizeof(gid_t));
+		if (!j->suppl_gid_list)
+			goto bad_gid_list;
+
+		memcpy(j->suppl_gid_list, gid_list_bytes, gid_list_size);
+	}
+
+	if (j->chrootdir) {	/* stale pointer */
+		char *chrootdir = consumestr(&serialized, &length);
+		if (!chrootdir)
+			goto bad_chrootdir;
+		j->chrootdir = strdup(chrootdir);
+		if (!j->chrootdir)
+			goto bad_chrootdir;
+	}
+
+	if (j->alt_syscall_table) {	/* stale pointer */
+		char *alt_syscall_table = consumestr(&serialized, &length);
+		if (!alt_syscall_table)
+			goto bad_syscall_table;
+		j->alt_syscall_table = strdup(alt_syscall_table);
+		if (!j->alt_syscall_table)
+			goto bad_syscall_table;
+	}
+
+	if (j->flags.seccomp_filter && j->filter_len > 0) {
+		size_t ninstrs = j->filter_len;
+		if (ninstrs > (SIZE_MAX / sizeof(struct sock_filter)) ||
+		    ninstrs > USHRT_MAX)
+			goto bad_filters;
+
+		size_t program_len = ninstrs * sizeof(struct sock_filter);
+		void *program = consumebytes(program_len, &serialized, &length);
+		if (!program)
+			goto bad_filters;
+
+		j->filter_prog = malloc(sizeof(struct sock_fprog));
+		if (!j->filter_prog)
+			goto bad_filters;
+
+		j->filter_prog->len = ninstrs;
+		j->filter_prog->filter = malloc(program_len);
+		if (!j->filter_prog->filter)
+			goto bad_filter_prog_instrs;
+
+		memcpy(j->filter_prog->filter, program, program_len);
+	}
+
+	count = j->mounts_count;
+	j->mounts_count = 0;
+	for (i = 0; i < count; ++i) {
+		unsigned long *flags;
+		int *has_data;
+		const char *dest;
+		const char *type;
+		const char *data = NULL;
+		const char *src = consumestr(&serialized, &length);
+		if (!src)
+			goto bad_mounts;
+		dest = consumestr(&serialized, &length);
+		if (!dest)
+			goto bad_mounts;
+		type = consumestr(&serialized, &length);
+		if (!type)
+			goto bad_mounts;
+		has_data = consumebytes(sizeof(*has_data), &serialized,
+					&length);
+		if (!has_data)
+			goto bad_mounts;
+		if (*has_data) {
+			data = consumestr(&serialized, &length);
+			if (!data)
+				goto bad_mounts;
+		}
+		flags = consumebytes(sizeof(*flags), &serialized, &length);
+		if (!flags)
+			goto bad_mounts;
+		if (minijail_mount_with_data(j, src, dest, type, *flags, data))
+			goto bad_mounts;
+	}
+
+	count = j->cgroup_count;
+	j->cgroup_count = 0;
+	for (i = 0; i < count; ++i) {
+		char *cgroup = consumestr(&serialized, &length);
+		if (!cgroup)
+			goto bad_cgroups;
+		j->cgroups[i] = strdup(cgroup);
+		if (!j->cgroups[i])
+			goto bad_cgroups;
+		++j->cgroup_count;
+	}
+
+	return 0;
+
+bad_cgroups:
+	while (j->mounts_head) {
+		struct mountpoint *m = j->mounts_head;
+		j->mounts_head = j->mounts_head->next;
+		free(m->data);
+		free(m->type);
+		free(m->dest);
+		free(m->src);
+		free(m);
+	}
+	for (i = 0; i < j->cgroup_count; ++i)
+		free(j->cgroups[i]);
+bad_mounts:
+	if (j->flags.seccomp_filter && j->filter_len > 0) {
+		free(j->filter_prog->filter);
+		free(j->filter_prog);
+	}
+bad_filter_prog_instrs:
+	if (j->filter_prog)
+		free(j->filter_prog);
+bad_filters:
+	if (j->alt_syscall_table)
+		free(j->alt_syscall_table);
+bad_syscall_table:
+	if (j->chrootdir)
+		free(j->chrootdir);
+bad_chrootdir:
+	if (j->suppl_gid_list)
+		free(j->suppl_gid_list);
+bad_gid_list:
+	if (j->user)
+		free(j->user);
+clear_pointers:
+	j->user = NULL;
+	j->suppl_gid_list = NULL;
+	j->chrootdir = NULL;
+	j->alt_syscall_table = NULL;
+	j->cgroup_count = 0;
+out:
+	return ret;
+}
+
+/*
+ * setup_mount_destination: Ensures the mount target exists.
+ * Creates it if needed and possible.
+ */
+static int setup_mount_destination(const char *source, const char *dest,
+				   uid_t uid, uid_t gid)
+{
+	int rc;
+	struct stat st_buf;
+
+	rc = stat(dest, &st_buf);
+	if (rc == 0) /* destination exists */
+		return 0;
+
+	/*
+	 * Try to create the destination.
+	 * Either make a directory or touch a file depending on the source type.
+	 * If the source doesn't exist, assume it is a filesystem type such as
+	 * "tmpfs" and create a directory to mount it on.
+	 */
+	rc = stat(source, &st_buf);
+	if (rc || S_ISDIR(st_buf.st_mode) || S_ISBLK(st_buf.st_mode)) {
+		if (mkdir(dest, 0700))
+			return -errno;
+	} else {
+		int fd = open(dest, O_RDWR | O_CREAT, 0700);
+		if (fd < 0)
+			return -errno;
+		close(fd);
+	}
+	return chown(dest, uid, gid);
+}
+
+/*
+ * mount_one: Applies mounts from @m for @j, recursing as needed.
+ * @j Minijail these mounts are for
+ * @m Head of list of mounts
+ *
+ * Returns 0 for success.
+ */
+static int mount_one(const struct minijail *j, struct mountpoint *m)
+{
+	int ret;
+	char *dest;
+	int remount_ro = 0;
+
+	/* |dest| has a leading "/". */
+	if (asprintf(&dest, "%s%s", j->chrootdir, m->dest) < 0)
+		return -ENOMEM;
+
+	if (setup_mount_destination(m->src, dest, j->uid, j->gid))
+		pdie("creating mount target '%s' failed", dest);
+
+	/*
+	 * R/O bind mounts have to be remounted since 'bind' and 'ro'
+	 * can't both be specified in the original bind mount.
+	 * Remount R/O after the initial mount.
+	 */
+	if ((m->flags & MS_BIND) && (m->flags & MS_RDONLY)) {
+		remount_ro = 1;
+		m->flags &= ~MS_RDONLY;
+	}
+
+	ret = mount(m->src, dest, m->type, m->flags, m->data);
+	if (ret)
+		pdie("mount: %s -> %s", m->src, dest);
+
+	if (remount_ro) {
+		m->flags |= MS_RDONLY;
+		ret = mount(m->src, dest, NULL,
+			    m->flags | MS_REMOUNT, m->data);
+		if (ret)
+			pdie("bind ro: %s -> %s", m->src, dest);
+	}
+
+	free(dest);
+	if (m->next)
+		return mount_one(j, m->next);
+	return ret;
+}
+
+static int enter_chroot(const struct minijail *j)
+{
+	int ret;
+
+	if (j->mounts_head && (ret = mount_one(j, j->mounts_head)))
+		return ret;
+
+	if (chroot(j->chrootdir))
+		return -errno;
+
+	if (chdir("/"))
+		return -errno;
+
+	return 0;
+}
+
+static int enter_pivot_root(const struct minijail *j)
+{
+	int ret, oldroot, newroot;
+
+	if (j->mounts_head && (ret = mount_one(j, j->mounts_head)))
+		return ret;
+
+	/*
+	 * Keep the fd for both old and new root.
+	 * It will be used in fchdir(2) later.
+	 */
+	oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+	if (oldroot < 0)
+		pdie("failed to open / for fchdir");
+	newroot = open(j->chrootdir, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+	if (newroot < 0)
+		pdie("failed to open %s for fchdir", j->chrootdir);
+
+	/*
+	 * To ensure j->chrootdir is the root of a filesystem,
+	 * do a self bind mount.
+	 */
+	if (mount(j->chrootdir, j->chrootdir, "bind", MS_BIND | MS_REC, ""))
+		pdie("failed to bind mount '%s'", j->chrootdir);
+	if (chdir(j->chrootdir))
+		return -errno;
+	if (syscall(SYS_pivot_root, ".", "."))
+		pdie("pivot_root");
+
+	/*
+	 * Now the old root is mounted on top of the new root. Use fchdir(2) to
+	 * change to the old root and unmount it.
+	 */
+	if (fchdir(oldroot))
+		pdie("failed to fchdir to old /");
+
+	/*
+	 * If j->flags.skip_remount_private was enabled for minijail_enter(),
+	 * there could be a shared mount point under |oldroot|. In that case,
+	 * mounts under this shared mount point will be unmounted below, and
+	 * this unmounting will propagate to the original mount namespace
+	 * (because the mount point is shared). To prevent this unexpected
+	 * unmounting, remove these mounts from their peer groups by recursively
+	 * remounting them as MS_PRIVATE.
+	 */
+	if (mount(NULL, ".", NULL, MS_REC | MS_PRIVATE, NULL))
+		pdie("failed to mount(/, private) before umount(/)");
+	/* The old root might be busy, so use lazy unmount. */
+	if (umount2(".", MNT_DETACH))
+		pdie("umount(/)");
+	/* Change back to the new root. */
+	if (fchdir(newroot))
+		return -errno;
+	if (close(oldroot))
+		return -errno;
+	if (close(newroot))
+		return -errno;
+	if (chroot("/"))
+		return -errno;
+	/* Set correct CWD for getcwd(3). */
+	if (chdir("/"))
+		return -errno;
+
+	return 0;
+}
+
+static int mount_tmp(void)
+{
+	return mount("none", "/tmp", "tmpfs", 0, "size=64M,mode=777");
+}
+
+static int remount_proc_readonly(const struct minijail *j)
+{
+	const char *kProcPath = "/proc";
+	const unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
+	/*
+	 * Right now, we're holding a reference to our parent's old mount of
+	 * /proc in our namespace, which means using MS_REMOUNT here would
+	 * mutate our parent's mount as well, even though we're in a VFS
+	 * namespace (!). Instead, remove their mount from our namespace lazily
+	 * (MNT_DETACH) and make our own.
+	 */
+	if (umount2(kProcPath, MNT_DETACH)) {
+		/*
+		 * If we are in a new user namespace, umount(2) will fail.
+		 * See http://man7.org/linux/man-pages/man7/user_namespaces.7.html
+		 */
+		if (j->flags.userns) {
+			info("umount(/proc, MNT_DETACH) failed, "
+			     "this is expected when using user namespaces");
+		} else {
+			return -errno;
+		}
+	}
+	if (mount("", kProcPath, "proc", kSafeFlags | MS_RDONLY, ""))
+		return -errno;
+	return 0;
+}
+
+static void kill_child_and_die(const struct minijail *j, const char *msg)
+{
+	kill(j->initpid, SIGKILL);
+	die("%s", msg);
+}
+
+static void write_pid_file_or_die(const struct minijail *j)
+{
+	if (write_pid_to_path(j->initpid, j->pid_file_path))
+		kill_child_and_die(j, "failed to write pid file");
+}
+
+static void add_to_cgroups_or_die(const struct minijail *j)
+{
+	size_t i;
+
+	for (i = 0; i < j->cgroup_count; ++i) {
+		if (write_pid_to_path(j->initpid, j->cgroups[i]))
+			kill_child_and_die(j, "failed to add to cgroups");
+	}
+}
+
+static void write_ugid_maps_or_die(const struct minijail *j)
+{
+	if (j->uidmap && write_proc_file(j->initpid, j->uidmap, "uid_map") != 0)
+		kill_child_and_die(j, "failed to write uid_map");
+	if (j->gidmap && write_proc_file(j->initpid, j->gidmap, "gid_map") != 0)
+		kill_child_and_die(j, "failed to write gid_map");
+}
+
+static void enter_user_namespace(const struct minijail *j)
+{
+	if (j->uidmap && setresuid(0, 0, 0))
+		pdie("user_namespaces: setresuid(0, 0, 0) failed");
+	if (j->gidmap && setresgid(0, 0, 0))
+		pdie("user_namespaces: setresgid(0, 0, 0) failed");
+}
+
+static void parent_setup_complete(int *pipe_fds)
+{
+	close(pipe_fds[0]);
+	close(pipe_fds[1]);
+}
+
+/*
+ * wait_for_parent_setup: Called by the child process to wait for any
+ * further parent-side setup to complete before continuing.
+ */
+static void wait_for_parent_setup(int *pipe_fds)
+{
+	char buf;
+
+	close(pipe_fds[1]);
+
+	/* Wait for parent to complete setup and close the pipe. */
+	if (read(pipe_fds[0], &buf, 1) != 0)
+		die("failed to sync with parent");
+	close(pipe_fds[0]);
+}
+
+static void drop_ugid(const struct minijail *j)
+{
+	if (j->flags.usergroups && j->flags.suppl_gids) {
+		die("tried to inherit *and* set supplementary groups;"
+		    " can only do one");
+	}
+
+	if (j->flags.usergroups) {
+		if (initgroups(j->user, j->usergid))
+			pdie("initgroups");
+	} else if (j->flags.suppl_gids) {
+		if (setgroups(j->suppl_gid_count, j->suppl_gid_list)) {
+			pdie("setgroups");
+		}
+	} else {
+		/*
+		 * Only attempt to clear supplementary groups if we are changing
+		 * users.
+		 */
+		if ((j->uid || j->gid) && setgroups(0, NULL))
+			pdie("setgroups");
+	}
+
+	if (j->flags.gid && setresgid(j->gid, j->gid, j->gid))
+		pdie("setresgid");
+
+	if (j->flags.uid && setresuid(j->uid, j->uid, j->uid))
+		pdie("setresuid");
+}
+
+/*
+ * We specifically do not use cap_valid() as that only tells us the last
+ * valid cap we were *compiled* against (i.e. what the version of kernel
+ * headers says). If we run on a different kernel version, then it's not
+ * uncommon for that to be less (if an older kernel) or more (if a newer
+ * kernel).
+ * Normally, we suck up the answer via /proc. On Android, not all processes are
+ * guaranteed to be able to access '/proc/sys/kernel/cap_last_cap' so we
+ * programmatically find the value by calling prctl(PR_CAPBSET_READ).
+ */
+static unsigned int get_last_valid_cap()
+{
+	unsigned int last_valid_cap = 0;
+	if (is_android()) {
+		for (; prctl(PR_CAPBSET_READ, last_valid_cap, 0, 0, 0) >= 0;
+		     ++last_valid_cap);
+
+		/* |last_valid_cap| will be the first failing value. */
+		if (last_valid_cap > 0) {
+			last_valid_cap--;
+		}
+	} else {
+		const char cap_file[] = "/proc/sys/kernel/cap_last_cap";
+		FILE *fp = fopen(cap_file, "re");
+		if (fscanf(fp, "%u", &last_valid_cap) != 1)
+			pdie("fscanf(%s)", cap_file);
+		fclose(fp);
+	}
+	return last_valid_cap;
+}
+
+static void drop_capbset(uint64_t keep_mask, unsigned int last_valid_cap)
+{
+	const uint64_t one = 1;
+	unsigned int i;
+	for (i = 0; i < sizeof(keep_mask) * 8 && i <= last_valid_cap; ++i) {
+		if (keep_mask & (one << i))
+			continue;
+		if (prctl(PR_CAPBSET_DROP, i))
+			pdie("could not drop capability from bounding set");
+	}
+}
+
+static void drop_caps(const struct minijail *j, unsigned int last_valid_cap)
+{
+	if (!j->flags.use_caps)
+		return;
+
+	cap_t caps = cap_get_proc();
+	cap_value_t flag[1];
+	const uint64_t one = 1;
+	unsigned int i;
+	if (!caps)
+		die("can't get process caps");
+	if (cap_clear_flag(caps, CAP_INHERITABLE))
+		die("can't clear inheritable caps");
+	if (cap_clear_flag(caps, CAP_EFFECTIVE))
+		die("can't clear effective caps");
+	if (cap_clear_flag(caps, CAP_PERMITTED))
+		die("can't clear permitted caps");
+	for (i = 0; i < sizeof(j->caps) * 8 && i <= last_valid_cap; ++i) {
+		/* Keep CAP_SETPCAP for dropping bounding set bits. */
+		if (i != CAP_SETPCAP && !(j->caps & (one << i)))
+			continue;
+		flag[0] = i;
+		if (cap_set_flag(caps, CAP_EFFECTIVE, 1, flag, CAP_SET))
+			die("can't add effective cap");
+		if (cap_set_flag(caps, CAP_PERMITTED, 1, flag, CAP_SET))
+			die("can't add permitted cap");
+		if (cap_set_flag(caps, CAP_INHERITABLE, 1, flag, CAP_SET))
+			die("can't add inheritable cap");
+	}
+	if (cap_set_proc(caps))
+		die("can't apply initial cleaned capset");
+
+	/*
+	 * Instead of dropping bounding set first, do it here in case
+	 * the caller had a more permissive bounding set which could
+	 * have been used above to raise a capability that wasn't already
+	 * present. This requires CAP_SETPCAP, so we raised/kept it above.
+	 */
+	drop_capbset(j->caps, last_valid_cap);
+
+	/* If CAP_SETPCAP wasn't specifically requested, now we remove it. */
+	if ((j->caps & (one << CAP_SETPCAP)) == 0) {
+		flag[0] = CAP_SETPCAP;
+		if (cap_set_flag(caps, CAP_EFFECTIVE, 1, flag, CAP_CLEAR))
+			die("can't clear effective cap");
+		if (cap_set_flag(caps, CAP_PERMITTED, 1, flag, CAP_CLEAR))
+			die("can't clear permitted cap");
+		if (cap_set_flag(caps, CAP_INHERITABLE, 1, flag, CAP_CLEAR))
+			die("can't clear inheritable cap");
+	}
+
+	if (cap_set_proc(caps))
+		die("can't apply final cleaned capset");
+
+	cap_free(caps);
+}
+
+static void set_seccomp_filter(const struct minijail *j)
+{
+	/*
+	 * Set no_new_privs. See </kernel/seccomp.c> and </kernel/sys.c>
+	 * in the kernel source tree for an explanation of the parameters.
+	 */
+	if (j->flags.no_new_privs) {
+		if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
+			pdie("prctl(PR_SET_NO_NEW_PRIVS)");
+	}
+
+	/*
+	 * Code running with ASan
+	 * (https://github.com/google/sanitizers/wiki/AddressSanitizer)
+	 * will make system calls not included in the syscall filter policy,
+	 * which will likely crash the program. Skip setting seccomp filter in
+	 * that case.
+	 * 'running_with_asan()' has no inputs and is completely defined at
+	 * build time, so this cannot be used by an attacker to skip setting
+	 * seccomp filter.
+	 */
+	if (j->flags.seccomp_filter && running_with_asan()) {
+		warn("running with ASan, not setting seccomp filter");
+		return;
+	}
+
+	/*
+	 * If we're logging seccomp filter failures,
+	 * install the SIGSYS handler first.
+	 */
+	if (j->flags.seccomp_filter && j->flags.log_seccomp_filter) {
+		if (install_sigsys_handler())
+			pdie("install SIGSYS handler");
+		warn("logging seccomp filter failures");
+	}
+
+	/*
+	 * Install the syscall filter.
+	 */
+	if (j->flags.seccomp_filter) {
+		if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,
+			  j->filter_prog)) {
+			if ((errno == EINVAL) && seccomp_can_softfail()) {
+				warn("seccomp not supported");
+				return;
+			}
+			pdie("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
+		}
+	}
+}
+
+void API minijail_enter(const struct minijail *j)
+{
+	/*
+	 * If we're dropping caps, get the last valid cap from /proc now,
+	 * since /proc can be unmounted before drop_caps() is called.
+	 */
+	unsigned int last_valid_cap = 0;
+	if (j->flags.capbset_drop || j->flags.use_caps)
+		last_valid_cap = get_last_valid_cap();
+
+	if (j->flags.pids)
+		die("tried to enter a pid-namespaced jail;"
+		    " try minijail_run()?");
+
+	if (j->flags.usergroups && !j->user)
+		die("usergroup inheritance without username");
+
+	/*
+	 * We can't recover from failures if we've dropped privileges partially,
+	 * so we don't even try. If any of our operations fail, we abort() the
+	 * entire process.
+	 */
+	if (j->flags.enter_vfs && setns(j->mountns_fd, CLONE_NEWNS))
+		pdie("setns(CLONE_NEWNS)");
+
+	if (j->flags.vfs) {
+		if (unshare(CLONE_NEWNS))
+			pdie("unshare(vfs)");
+		/*
+		 * Unless asked not to, remount all filesystems as private.
+		 * If they are shared, new bind mounts will creep out of our
+		 * namespace.
+		 * https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
+		 */
+		if (!j->flags.skip_remount_private) {
+			if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL))
+				pdie("mount(/, private)");
+		}
+	}
+
+	if (j->flags.ipc && unshare(CLONE_NEWIPC)) {
+		pdie("unshare(ipc)");
+	}
+
+	if (j->flags.enter_net) {
+		if (setns(j->netns_fd, CLONE_NEWNET))
+			pdie("setns(CLONE_NEWNET)");
+	} else if (j->flags.net && unshare(CLONE_NEWNET)) {
+		pdie("unshare(net)");
+	}
+
+	if (j->flags.ns_cgroups && unshare(CLONE_NEWCGROUP))
+		pdie("unshare(cgroups)");
+
+	if (j->flags.chroot && enter_chroot(j))
+		pdie("chroot");
+
+	if (j->flags.pivot_root && enter_pivot_root(j))
+		pdie("pivot_root");
+
+	if (j->flags.mount_tmp && mount_tmp())
+		pdie("mount_tmp");
+
+	if (j->flags.remount_proc_ro && remount_proc_readonly(j))
+		pdie("remount");
+
+	/*
+	 * If we're only dropping capabilities from the bounding set, but not
+	 * from the thread's (permitted|inheritable|effective) sets, do it now.
+	 */
+	if (j->flags.capbset_drop) {
+		drop_capbset(j->cap_bset, last_valid_cap);
+	}
+
+	if (j->flags.use_caps) {
+		/*
+		 * POSIX capabilities are a bit tricky. If we drop our
+		 * capability to change uids, our attempt to use setuid()
+		 * below will fail. Hang on to root caps across setuid(), then
+		 * lock securebits.
+		 */
+		if (prctl(PR_SET_KEEPCAPS, 1))
+			pdie("prctl(PR_SET_KEEPCAPS)");
+
+		/*
+		 * Kernels 4.3+ define a new securebit
+		 * (SECURE_NO_CAP_AMBIENT_RAISE), so using the SECURE_ALL_BITS
+		 * and SECURE_ALL_LOCKS masks from newer kernel headers will
+		 * return EPERM on older kernels. Detect this, and retry with
+		 * the right mask for older (2.6.26-4.2) kernels.
+		 */
+		int securebits_ret = prctl(PR_SET_SECUREBITS,
+					   SECURE_ALL_BITS | SECURE_ALL_LOCKS);
+		if (securebits_ret < 0) {
+			if (errno == EPERM) {
+				/* Possibly running on kernel < 4.3. */
+				securebits_ret = prctl(
+				    PR_SET_SECUREBITS,
+				    OLD_SECURE_ALL_BITS | OLD_SECURE_ALL_LOCKS);
+			}
+		}
+		if (securebits_ret < 0)
+			pdie("prctl(PR_SET_SECUREBITS)");
+	}
+
+	if (j->flags.no_new_privs) {
+		/*
+		 * If we're setting no_new_privs, we can drop privileges
+		 * before setting seccomp filter. This way filter policies
+		 * don't need to allow privilege-dropping syscalls.
+		 */
+		drop_ugid(j);
+		drop_caps(j, last_valid_cap);
+		set_seccomp_filter(j);
+	} else {
+		/*
+		 * If we're not setting no_new_privs,
+		 * we need to set seccomp filter *before* dropping privileges.
+		 * WARNING: this means that filter policies *must* allow
+		 * setgroups()/setresgid()/setresuid() for dropping root and
+		 * capget()/capset()/prctl() for dropping caps.
+		 */
+		set_seccomp_filter(j);
+		drop_ugid(j);
+		drop_caps(j, last_valid_cap);
+	}
+
+	/*
+	 * Select the specified alternate syscall table.  The table must not
+	 * block prctl(2) if we're using seccomp as well.
+	 */
+	if (j->flags.alt_syscall) {
+		if (prctl(PR_ALT_SYSCALL, 1, j->alt_syscall_table))
+			pdie("prctl(PR_ALT_SYSCALL)");
+	}
+
+	/*
+	 * seccomp has to come last since it cuts off all the other
+	 * privilege-dropping syscalls :)
+	 */
+	if (j->flags.seccomp && prctl(PR_SET_SECCOMP, 1)) {
+		if ((errno == EINVAL) && seccomp_can_softfail()) {
+			warn("seccomp not supported");
+			return;
+		}
+		pdie("prctl(PR_SET_SECCOMP)");
+	}
+}
+
+/* TODO(wad): will visibility affect this variable? */
+static int init_exitstatus = 0;
+
+void init_term(int __attribute__ ((unused)) sig)
+{
+	_exit(init_exitstatus);
+}
+
+void init(pid_t rootpid)
+{
+	pid_t pid;
+	int status;
+	/* So that we exit with the right status. */
+	signal(SIGTERM, init_term);
+	/* TODO(wad): self jail with seccomp filters here. */
+	while ((pid = wait(&status)) > 0) {
+		/*
+		 * This loop will only end when either there are no processes
+		 * left inside our pid namespace or we get a signal.
+		 */
+		if (pid == rootpid)
+			init_exitstatus = status;
+	}
+	if (!WIFEXITED(init_exitstatus))
+		_exit(MINIJAIL_ERR_INIT);
+	_exit(WEXITSTATUS(init_exitstatus));
+}
+
+int API minijail_from_fd(int fd, struct minijail *j)
+{
+	size_t sz = 0;
+	size_t bytes = read(fd, &sz, sizeof(sz));
+	char *buf;
+	int r;
+	if (sizeof(sz) != bytes)
+		return -EINVAL;
+	if (sz > USHRT_MAX)	/* arbitrary sanity check */
+		return -E2BIG;
+	buf = malloc(sz);
+	if (!buf)
+		return -ENOMEM;
+	bytes = read(fd, buf, sz);
+	if (bytes != sz) {
+		free(buf);
+		return -EINVAL;
+	}
+	r = minijail_unmarshal(j, buf, sz);
+	free(buf);
+	return r;
+}
+
+int API minijail_to_fd(struct minijail *j, int fd)
+{
+	char *buf;
+	size_t sz = minijail_size(j);
+	ssize_t written;
+	int r;
+
+	if (!sz)
+		return -EINVAL;
+	buf = malloc(sz);
+	r = minijail_marshal(j, buf, sz);
+	if (r) {
+		free(buf);
+		return r;
+	}
+	/* Sends [size][minijail]. */
+	written = write(fd, &sz, sizeof(sz));
+	if (written != sizeof(sz)) {
+		free(buf);
+		return -EFAULT;
+	}
+	written = write(fd, buf, sz);
+	if (written < 0 || (size_t) written != sz) {
+		free(buf);
+		return -EFAULT;
+	}
+	free(buf);
+	return 0;
+}
+
+int setup_preload(void)
+{
+#if defined(__ANDROID__)
+	/* Don't use LDPRELOAD on Brillo. */
+	return 0;
+#else
+	char *oldenv = getenv(kLdPreloadEnvVar) ? : "";
+	char *newenv = malloc(strlen(oldenv) + 2 + strlen(PRELOADPATH));
+	if (!newenv)
+		return -ENOMEM;
+
+	/* Only insert a separating space if we have something to separate... */
+	sprintf(newenv, "%s%s%s", oldenv, strlen(oldenv) ? " " : "",
+		PRELOADPATH);
+
+	/* setenv() makes a copy of the string we give it. */
+	setenv(kLdPreloadEnvVar, newenv, 1);
+	free(newenv);
+	return 0;
+#endif
+}
+
+int setup_pipe(int fds[2])
+{
+	int r = pipe(fds);
+	char fd_buf[11];
+	if (r)
+		return r;
+	r = snprintf(fd_buf, sizeof(fd_buf), "%d", fds[0]);
+	if (r <= 0)
+		return -EINVAL;
+	setenv(kFdEnvVar, fd_buf, 1);
+	return 0;
+}
+
+int setup_pipe_end(int fds[2], size_t index)
+{
+	if (index > 1)
+		return -1;
+
+	close(fds[1 - index]);
+	return fds[index];
+}
+
+int setup_and_dupe_pipe_end(int fds[2], size_t index, int fd)
+{
+	if (index > 1)
+		return -1;
+
+	close(fds[1 - index]);
+	/* dup2(2) the corresponding end of the pipe into |fd|. */
+	return dup2(fds[index], fd);
+}
+
+int minijail_run_internal(struct minijail *j, const char *filename,
+			  char *const argv[], pid_t *pchild_pid,
+			  int *pstdin_fd, int *pstdout_fd, int *pstderr_fd,
+			  int use_preload);
+
+int API minijail_run(struct minijail *j, const char *filename,
+		     char *const argv[])
+{
+	return minijail_run_internal(j, filename, argv, NULL, NULL, NULL, NULL,
+				     true);
+}
+
+int API minijail_run_pid(struct minijail *j, const char *filename,
+			 char *const argv[], pid_t *pchild_pid)
+{
+	return minijail_run_internal(j, filename, argv, pchild_pid,
+				     NULL, NULL, NULL, true);
+}
+
+int API minijail_run_pipe(struct minijail *j, const char *filename,
+			  char *const argv[], int *pstdin_fd)
+{
+	return minijail_run_internal(j, filename, argv, NULL, pstdin_fd,
+				     NULL, NULL, true);
+}
+
+int API minijail_run_pid_pipes(struct minijail *j, const char *filename,
+			       char *const argv[], pid_t *pchild_pid,
+			       int *pstdin_fd, int *pstdout_fd, int *pstderr_fd)
+{
+	return minijail_run_internal(j, filename, argv, pchild_pid,
+				     pstdin_fd, pstdout_fd, pstderr_fd, true);
+}
+
+int API minijail_run_no_preload(struct minijail *j, const char *filename,
+				char *const argv[])
+{
+	return minijail_run_internal(j, filename, argv, NULL, NULL, NULL, NULL,
+				     false);
+}
+
+int API minijail_run_pid_pipes_no_preload(struct minijail *j,
+					  const char *filename,
+					  char *const argv[],
+					  pid_t *pchild_pid,
+					  int *pstdin_fd, int *pstdout_fd,
+					  int *pstderr_fd)
+{
+	return minijail_run_internal(j, filename, argv, pchild_pid,
+				     pstdin_fd, pstdout_fd, pstderr_fd, false);
+}
+
+int minijail_run_internal(struct minijail *j, const char *filename,
+			  char *const argv[], pid_t *pchild_pid,
+			  int *pstdin_fd, int *pstdout_fd, int *pstderr_fd,
+			  int use_preload)
+{
+	char *oldenv, *oldenv_copy = NULL;
+	pid_t child_pid;
+	int pipe_fds[2];
+	int stdin_fds[2];
+	int stdout_fds[2];
+	int stderr_fds[2];
+	int child_sync_pipe_fds[2];
+	int sync_child = 0;
+	int ret;
+	/* We need to remember this across the minijail_preexec() call. */
+	int pid_namespace = j->flags.pids;
+	int do_init = j->flags.do_init;
+
+	if (use_preload) {
+		oldenv = getenv(kLdPreloadEnvVar);
+		if (oldenv) {
+			oldenv_copy = strdup(oldenv);
+			if (!oldenv_copy)
+				return -ENOMEM;
+		}
+
+		if (setup_preload())
+			return -EFAULT;
+	}
+
+	if (!use_preload) {
+		if (j->flags.use_caps && j->caps != 0)
+			die("non-empty capabilities are not supported without LD_PRELOAD");
+	}
+
+	/*
+	 * Make the process group ID of this process equal to its PID, so that
+	 * both the Minijail process and the jailed process can be killed
+	 * together.
+	 * Don't fail on EPERM, since setpgid(0, 0) can only EPERM when
+	 * the process is already a process group leader.
+	 */
+	if (setpgid(0 /* use calling PID */, 0 /* make PGID = PID */)) {
+		if (errno != EPERM) {
+			pdie("setpgid(0, 0)");
+		}
+	}
+
+	if (use_preload) {
+		/*
+		 * Before we fork(2) and execve(2) the child process, we need
+		 * to open a pipe(2) to send the minijail configuration over.
+		 */
+		if (setup_pipe(pipe_fds))
+			return -EFAULT;
+	}
+
+	/*
+	 * If we want to write to the child process' standard input,
+	 * create the pipe(2) now.
+	 */
+	if (pstdin_fd) {
+		if (pipe(stdin_fds))
+			return -EFAULT;
+	}
+
+	/*
+	 * If we want to read from the child process' standard output,
+	 * create the pipe(2) now.
+	 */
+	if (pstdout_fd) {
+		if (pipe(stdout_fds))
+			return -EFAULT;
+	}
+
+	/*
+	 * If we want to read from the child process' standard error,
+	 * create the pipe(2) now.
+	 */
+	if (pstderr_fd) {
+		if (pipe(stderr_fds))
+			return -EFAULT;
+	}
+
+	/*
+	 * If we want to set up a new uid/gid map in the user namespace,
+	 * or if we need to add the child process to cgroups, create the pipe(2)
+	 * to sync between parent and child.
+	 */
+	if (j->flags.userns || j->flags.cgroups) {
+		sync_child = 1;
+		if (pipe(child_sync_pipe_fds))
+			return -EFAULT;
+	}
+
+	/*
+	 * Use sys_clone() if and only if we're creating a pid namespace.
+	 *
+	 * tl;dr: WARNING: do not mix pid namespaces and multithreading.
+	 *
+	 * In multithreaded programs, there are a bunch of locks inside libc,
+	 * some of which may be held by other threads at the time that we call
+	 * minijail_run_pid(). If we call fork(), glibc does its level best to
+	 * ensure that we hold all of these locks before it calls clone()
+	 * internally and drop them after clone() returns, but when we call
+	 * sys_clone(2) directly, all that gets bypassed and we end up with a
+	 * child address space where some of libc's important locks are held by
+	 * other threads (which did not get cloned, and hence will never release
+	 * those locks). This is okay so long as we call exec() immediately
+	 * after, but a bunch of seemingly-innocent libc functions like setenv()
+	 * take locks.
+	 *
+	 * Hence, only call sys_clone() if we need to, in order to get at pid
+	 * namespacing. If we follow this path, the child's address space might
+	 * have broken locks; you may only call functions that do not acquire
+	 * any locks.
+	 *
+	 * Unfortunately, fork() acquires every lock it can get its hands on, as
+	 * previously detailed, so this function is highly likely to deadlock
+	 * later on (see "deadlock here") if we're multithreaded.
+	 *
+	 * We might hack around this by having the clone()d child (init of the
+	 * pid namespace) return directly, rather than leaving the clone()d
+	 * process hanging around to be init for the new namespace (and having
+	 * its fork()ed child return in turn), but that process would be
+	 * crippled with its libc locks potentially broken. We might try
+	 * fork()ing in the parent before we clone() to ensure that we own all
+	 * the locks, but then we have to have the forked child hanging around
+	 * consuming resources (and possibly having file descriptors / shared
+	 * memory regions / etc attached). We'd need to keep the child around to
+	 * avoid having its children get reparented to init.
+	 *
+	 * TODO(ellyjones): figure out if the "forked child hanging around"
+	 * problem is fixable or not. It would be nice if we worked in this
+	 * case.
+	 */
+	if (pid_namespace) {
+		int clone_flags = CLONE_NEWPID | SIGCHLD;
+		if (j->flags.userns)
+			clone_flags |= CLONE_NEWUSER;
+		child_pid = syscall(SYS_clone, clone_flags, NULL);
+	} else {
+		child_pid = fork();
+	}
+
+	if (child_pid < 0) {
+		if (use_preload) {
+			free(oldenv_copy);
+		}
+		die("failed to fork child");
+	}
+
+	if (child_pid) {
+		if (use_preload) {
+			/* Restore parent's LD_PRELOAD. */
+			if (oldenv_copy) {
+				setenv(kLdPreloadEnvVar, oldenv_copy, 1);
+				free(oldenv_copy);
+			} else {
+				unsetenv(kLdPreloadEnvVar);
+			}
+			unsetenv(kFdEnvVar);
+		}
+
+		j->initpid = child_pid;
+
+		if (j->flags.pid_file)
+			write_pid_file_or_die(j);
+
+		if (j->flags.cgroups)
+			add_to_cgroups_or_die(j);
+
+		if (j->flags.userns)
+			write_ugid_maps_or_die(j);
+
+		if (sync_child)
+			parent_setup_complete(child_sync_pipe_fds);
+
+		if (use_preload) {
+			/* Send marshalled minijail. */
+			close(pipe_fds[0]);	/* read endpoint */
+			ret = minijail_to_fd(j, pipe_fds[1]);
+			close(pipe_fds[1]);	/* write endpoint */
+			if (ret) {
+				kill(j->initpid, SIGKILL);
+				die("failed to send marshalled minijail");
+			}
+		}
+
+		if (pchild_pid)
+			*pchild_pid = child_pid;
+
+		/*
+		 * If we want to write to the child process' standard input,
+		 * set up the write end of the pipe.
+		 */
+		if (pstdin_fd)
+			*pstdin_fd = setup_pipe_end(stdin_fds,
+						    1 /* write end */);
+
+		/*
+		 * If we want to read from the child process' standard output,
+		 * set up the read end of the pipe.
+		 */
+		if (pstdout_fd)
+			*pstdout_fd = setup_pipe_end(stdout_fds,
+						     0 /* read end */);
+
+		/*
+		 * If we want to read from the child process' standard error,
+		 * set up the read end of the pipe.
+		 */
+		if (pstderr_fd)
+			*pstderr_fd = setup_pipe_end(stderr_fds,
+						     0 /* read end */);
+
+		return 0;
+	}
+	/* Child process. */
+	free(oldenv_copy);
+
+	if (j->flags.reset_signal_mask) {
+		sigset_t signal_mask;
+		if (sigemptyset(&signal_mask) != 0)
+			pdie("sigemptyset failed");
+		if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0)
+			pdie("sigprocmask failed");
+	}
+
+	if (sync_child)
+		wait_for_parent_setup(child_sync_pipe_fds);
+
+	if (j->flags.userns)
+		enter_user_namespace(j);
+
+	/*
+	 * If we want to write to the jailed process' standard input,
+	 * set up the read end of the pipe.
+	 */
+	if (pstdin_fd) {
+		if (setup_and_dupe_pipe_end(stdin_fds, 0 /* read end */,
+					    STDIN_FILENO) < 0)
+			die("failed to set up stdin pipe");
+	}
+
+	/*
+	 * If we want to read from the jailed process' standard output,
+	 * set up the write end of the pipe.
+	 */
+	if (pstdout_fd) {
+		if (setup_and_dupe_pipe_end(stdout_fds, 1 /* write end */,
+					    STDOUT_FILENO) < 0)
+			die("failed to set up stdout pipe");
+	}
+
+	/*
+	 * If we want to read from the jailed process' standard error,
+	 * set up the write end of the pipe.
+	 */
+	if (pstderr_fd) {
+		if (setup_and_dupe_pipe_end(stderr_fds, 1 /* write end */,
+					    STDERR_FILENO) < 0)
+			die("failed to set up stderr pipe");
+	}
+
+	/* If running an init program, let it decide when/how to mount /proc. */
+	if (pid_namespace && !do_init)
+		j->flags.remount_proc_ro = 0;
+
+	if (use_preload) {
+		/* Strip out flags that cannot be inherited across execve(2). */
+		minijail_preexec(j);
+	} else {
+		/*
+		 * If not using LD_PRELOAD, do all jailing before execve(2).
+		 * Note that PID namespaces can only be entered on fork(2),
+		 * so that flag is still cleared.
+		 */
+		j->flags.pids = 0;
+	}
+	/* Jail this process, then execve(2) the target. */
+	minijail_enter(j);
+
+	if (pid_namespace && do_init) {
+		/*
+		 * pid namespace: this process will become init inside the new
+		 * namespace. We don't want all programs we might exec to have
+		 * to know how to be init. Normally (do_init == 1) we fork off
+		 * a child to actually run the program. If |do_init == 0|, we
+		 * let the program keep pid 1 and be init.
+		 *
+		 * If we're multithreaded, we'll probably deadlock here. See
+		 * WARNING above.
+		 */
+		child_pid = fork();
+		if (child_pid < 0) {
+			_exit(child_pid);
+		} else if (child_pid > 0) {
+			/* Best effort. Don't bother checking the return value. */
+			prctl(PR_SET_NAME, "minijail-init");
+			init(child_pid);	/* Never returns. */
+		}
+	}
+
+	/*
+	 * If we aren't pid-namespaced, or the jailed program asked to be init:
+	 *   calling process
+	 *   -> execve()-ing process
+	 * If we are:
+	 *   calling process
+	 *   -> init()-ing process
+	 *      -> execve()-ing process
+	 */
+	ret = execve(filename, argv, environ);
+	if (ret == -1) {
+		pwarn("execve(%s) failed", filename);
+	}
+	_exit(ret);
+}
+
+int API minijail_kill(struct minijail *j)
+{
+	int st;
+	if (kill(j->initpid, SIGTERM))
+		return -errno;
+	if (waitpid(j->initpid, &st, 0) < 0)
+		return -errno;
+	return st;
+}
+
+int API minijail_wait(struct minijail *j)
+{
+	int st;
+	if (waitpid(j->initpid, &st, 0) < 0)
+		return -errno;
+
+	if (!WIFEXITED(st)) {
+		int error_status = st;
+		if (WIFSIGNALED(st)) {
+			int signum = WTERMSIG(st);
+			warn("child process %d received signal %d",
+			     j->initpid, signum);
+			/*
+			 * We return MINIJAIL_ERR_JAIL if the process received
+			 * SIGSYS, which happens when a syscall is blocked by
+			 * seccomp filters.
+			 * If not, we do what bash(1) does:
+			 * $? = 128 + signum
+			 */
+			if (signum == SIGSYS) {
+				error_status = MINIJAIL_ERR_JAIL;
+			} else {
+				error_status = 128 + signum;
+			}
+		}
+		return error_status;
+	}
+
+	int exit_status = WEXITSTATUS(st);
+	if (exit_status != 0)
+		info("child process %d exited with status %d",
+		     j->initpid, exit_status);
+
+	return exit_status;
+}
+
+void API minijail_destroy(struct minijail *j)
+{
+	size_t i;
+
+	if (j->flags.seccomp_filter && j->filter_prog) {
+		free(j->filter_prog->filter);
+		free(j->filter_prog);
+	}
+	while (j->mounts_head) {
+		struct mountpoint *m = j->mounts_head;
+		j->mounts_head = j->mounts_head->next;
+		free(m->data);
+		free(m->type);
+		free(m->dest);
+		free(m->src);
+		free(m);
+	}
+	j->mounts_tail = NULL;
+	if (j->user)
+		free(j->user);
+	if (j->suppl_gid_list)
+		free(j->suppl_gid_list);
+	if (j->chrootdir)
+		free(j->chrootdir);
+	if (j->pid_file_path)
+		free(j->pid_file_path);
+	if (j->uidmap)
+		free(j->uidmap);
+	if (j->gidmap)
+		free(j->gidmap);
+	if (j->alt_syscall_table)
+		free(j->alt_syscall_table);
+	for (i = 0; i < j->cgroup_count; ++i)
+		free(j->cgroups[i]);
+	free(j);
+}
diff --git a/minijail/libminijail.h b/minijail/libminijail.h
new file mode 100644
index 0000000..62005c8
--- /dev/null
+++ b/minijail/libminijail.h
@@ -0,0 +1,266 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * The general pattern of use here:
+ * 1) Construct a minijail with minijail_new()
+ * 2) Apply the desired restrictions to it
+ * 3) Enter it, which locks the current process inside it, or:
+ * 3) Run a process inside it
+ * 4) Destroy it.
+ */
+
+#ifndef _LIBMINIJAIL_H_
+#define _LIBMINIJAIL_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+	MINIJAIL_ERR_PRELOAD = 252,
+	MINIJAIL_ERR_JAIL = 253,
+	MINIJAIL_ERR_INIT = 254,
+};
+
+struct minijail;
+
+/* Allocates a new minijail with no restrictions. */
+struct minijail *minijail_new(void);
+
+/*
+ * These functions add restrictions to the minijail. They are not applied until
+ * minijail_enter() is called. See the documentation in minijail0.1 for
+ * explanations in detail of what the restrictions do.
+ */
+void minijail_change_uid(struct minijail *j, uid_t uid);
+void minijail_change_gid(struct minijail *j, gid_t gid);
+/* Copies |list|. */
+void minijail_set_supplementary_gids(struct minijail *j, size_t size,
+				     const gid_t *list);
+/* Stores user to change to and copies |user| for internal consistency. */
+int minijail_change_user(struct minijail *j, const char *user);
+/* Does not take ownership of |group|. */
+int minijail_change_group(struct minijail *j, const char *group);
+void minijail_use_seccomp(struct minijail *j);
+void minijail_no_new_privs(struct minijail *j);
+void minijail_use_seccomp_filter(struct minijail *j);
+void minijail_parse_seccomp_filters(struct minijail *j, const char *path);
+void minijail_parse_seccomp_filters_from_fd(struct minijail *j, int fd);
+void minijail_log_seccomp_filter_failures(struct minijail *j);
+/* 'minijail_use_caps' and 'minijail_capbset_drop' are mutually exclusive. */
+void minijail_use_caps(struct minijail *j, uint64_t capmask);
+void minijail_capbset_drop(struct minijail *j, uint64_t capmask);
+void minijail_reset_signal_mask(struct minijail *j);
+void minijail_namespace_vfs(struct minijail *j);
+void minijail_namespace_enter_vfs(struct minijail *j, const char *ns_path);
+/*
+ * This option is *dangerous* as it negates most of the functionality of
+ * minijail_namespace_vfs(). You very likely don't need this.
+ */
+void minijail_skip_remount_private(struct minijail *j);
+void minijail_namespace_ipc(struct minijail *j);
+void minijail_namespace_net(struct minijail *j);
+void minijail_namespace_enter_net(struct minijail *j, const char *ns_path);
+void minijail_namespace_cgroups(struct minijail *j);
+/*
+ * Implies namespace_vfs and remount_proc_readonly.
+ * WARNING: this is NOT THREAD SAFE. See the block comment in </libminijail.c>.
+ */
+void minijail_namespace_pids(struct minijail *j);
+void minijail_namespace_user(struct minijail *j);
+int minijail_uidmap(struct minijail *j, const char *uidmap);
+int minijail_gidmap(struct minijail *j, const char *gidmap);
+void minijail_remount_proc_readonly(struct minijail *j);
+void minijail_run_as_init(struct minijail *j);
+int minijail_write_pid_file(struct minijail *j, const char *path);
+void minijail_inherit_usergroups(struct minijail *j);
+/*
+ * Changes the jailed process's syscall table to the alt_syscall table
+ * named |table|.
+ */
+int minijail_use_alt_syscall(struct minijail *j, const char *table);
+
+/*
+ * Adds the jailed process to the cgroup given by |path|.  |path| should be the
+ * full path to the cgroups "tasks" file.
+ * Example: /sys/fs/cgroup/cpu/jailed_procs/tasks adds to the "jailed_procs" cpu
+ * cgroup.
+ */
+int minijail_add_to_cgroup(struct minijail *j, const char *path);
+
+/*
+ * minijail_enter_chroot: enables chroot() restriction for @j
+ * @j   minijail to apply restriction to
+ * @dir directory to chroot() to. Owned by caller.
+ *
+ * Enters @dir, binding all bind mounts specified with minijail_bind() into
+ * place. Requires @dir to contain all necessary directories for bind mounts
+ * (i.e., if you have requested a bind mount at /etc, /etc must exist in @dir.)
+ *
+ * Returns 0 on success.
+ */
+int minijail_enter_chroot(struct minijail *j, const char *dir);
+int minijail_enter_pivot_root(struct minijail *j, const char *dir);
+
+/*
+ * minijail_get_original_path: returns the path of a given file outside of the
+ * chroot.
+ * @j           minijail to obtain the path from.
+ * @chroot_path path inside of the chroot() to.
+ *
+ * When executing a binary in a chroot or pivot_root, return path to the binary
+ * outside of the chroot.
+ *
+ * Returns a string containing the path.  This must be freed by the caller.
+ */
+char *minijail_get_original_path(struct minijail *j, const char *chroot_path);
+
+/*
+ * minijail_mount_tmp: enables mounting of a tmpfs filesystem on /tmp.
+ * As be rules of bind mounts, /tmp must exist in chroot.
+ */
+void minijail_mount_tmp(struct minijail *j);
+
+/*
+ * minijail_mount_with_data: when entering minijail @j,
+ *   mounts @src at @dst with @flags and @data.
+ * @j         minijail to bind inside
+ * @src       source to bind
+ * @dest      location to bind (inside chroot)
+ * @type      type of filesystem
+ * @flags     flags passed to mount
+ * @data      data arguments passed to mount(2), e.g. "mode=755"
+ *
+ * This may be called multiple times; all mounts will be applied in the order
+ * of minijail_mount() calls.
+ */
+int minijail_mount_with_data(struct minijail *j, const char *src,
+			     const char *dest, const char *type,
+			     unsigned long flags, const char *data);
+
+/*
+ * minijail_mount: when entering minijail @j, mounts @src at @dst with @flags
+ * @j         minijail to bind inside
+ * @src       source to bind
+ * @dest      location to bind (inside chroot)
+ * @type      type of filesystem
+ * @flags     flags passed to mount
+ *
+ * This may be called multiple times; all mounts will be applied in the order
+ * of minijail_mount() calls.
+ */
+int minijail_mount(struct minijail *j, const char *src, const char *dest,
+		   const char *type, unsigned long flags);
+
+/*
+ * minijail_bind: bind-mounts @src into @j as @dest, optionally writeable
+ * @j         minijail to bind inside
+ * @src       source to bind
+ * @dest      location to bind (inside chroot)
+ * @writeable 1 if the bind mount should be writeable
+ *
+ * This may be called multiple times; all bindings will be applied in the order
+ * of minijail_bind() calls.
+ */
+int minijail_bind(struct minijail *j, const char *src, const char *dest,
+		  int writeable);
+
+/*
+ * Lock this process into the given minijail. Note that this procedure cannot
+ * fail, since there is no way to undo privilege-dropping; therefore, if any
+ * part of the privilege-drop fails, minijail_enter() will abort the entire
+ * process.
+ *
+ * Some restrictions cannot be enabled this way (pid namespaces) and attempting
+ * to do so will cause an abort.
+ */
+void minijail_enter(const struct minijail *j);
+
+/*
+ * Run the specified command in the given minijail, execve(2)-style. This is
+ * required if minijail_namespace_pids() was used.
+ */
+int minijail_run(struct minijail *j, const char *filename,
+		 char *const argv[]);
+
+/*
+ * Run the specified command in the given minijail, execve(2)-style.
+ * Used with static binaries, or on systems without support for LD_PRELOAD.
+ */
+int minijail_run_no_preload(struct minijail *j, const char *filename,
+			    char *const argv[]);
+
+/*
+ * Run the specified command in the given minijail, execve(2)-style.
+ * Update |*pchild_pid| with the pid of the child.
+ */
+int minijail_run_pid(struct minijail *j, const char *filename,
+		     char *const argv[], pid_t *pchild_pid);
+
+/*
+ * Run the specified command in the given minijail, execve(2)-style.
+ * Update |*pstdin_fd| with a fd that allows writing to the child's
+ * standard input.
+ */
+int minijail_run_pipe(struct minijail *j, const char *filename,
+		      char *const argv[], int *pstdin_fd);
+
+/*
+ * Run the specified command in the given minijail, execve(2)-style.
+ * Update |*pchild_pid| with the pid of the child.
+ * Update |*pstdin_fd| with a fd that allows writing to the child's
+ * standard input.
+ * Update |*pstdout_fd| with a fd that allows reading from the child's
+ * standard output.
+ * Update |*pstderr_fd| with a fd that allows reading from the child's
+ * standard error.
+ */
+int minijail_run_pid_pipes(struct minijail *j, const char *filename,
+			   char *const argv[], pid_t *pchild_pid,
+			   int *pstdin_fd, int *pstdout_fd, int *pstderr_fd);
+
+/*
+ * Run the specified command in the given minijail, execve(2)-style.
+ * Update |*pchild_pid| with the pid of the child.
+ * Update |*pstdin_fd| with a fd that allows writing to the child's
+ * standard input.
+ * Update |*pstdout_fd| with a fd that allows reading from the child's
+ * standard output.
+ * Update |*pstderr_fd| with a fd that allows reading from the child's
+ * standard error.
+ * Used with static binaries, or on systems without support for LD_PRELOAD.
+ */
+int minijail_run_pid_pipes_no_preload(struct minijail *j, const char *filename,
+				      char *const argv[], pid_t *pchild_pid,
+				      int *pstdin_fd, int *pstdout_fd,
+				      int *pstderr_fd);
+
+/*
+ * Kill the specified minijail. The minijail must have been created with pid
+ * namespacing; if it was, all processes inside it are atomically killed.
+ */
+int minijail_kill(struct minijail *j);
+
+/*
+ * Wait for all processes in the specified minijail to exit. Returns the exit
+ * status of the _first_ process spawned in the jail.
+ */
+int minijail_wait(struct minijail *j);
+
+/*
+ * Frees the given minijail. It does not matter if the process is inside the
+ * minijail or not.
+ */
+void minijail_destroy(struct minijail *j);
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#endif /* !_LIBMINIJAIL_H_ */
diff --git a/minijail/libminijail.pc.in b/minijail/libminijail.pc.in
new file mode 100644
index 0000000..29f7c77
--- /dev/null
+++ b/minijail/libminijail.pc.in
@@ -0,0 +1,8 @@
+bslot=@BSLOT@
+include_dir=@INCLUDE_DIR@
+
+Name: libminijail
+Description: Minijail shared library.
+Version: ${bslot}
+CFlags: -I${include_dir}
+Libs: -lminijail
diff --git a/minijail/libminijail_unittest.c b/minijail/libminijail_unittest.c
new file mode 100644
index 0000000..e89c810
--- /dev/null
+++ b/minijail/libminijail_unittest.c
@@ -0,0 +1,210 @@
+/* libminijail_unittest.c
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Test platform independent logic of Minijail.
+ */
+
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "test_harness.h"
+
+#include "libminijail.h"
+#include "libminijail-private.h"
+#include "util.h"
+
+/* Prototypes needed only by test. */
+void *consumebytes(size_t length, char **buf, size_t *buflength);
+char *consumestr(char **buf, size_t *buflength);
+
+/* Silence unused variable warnings. */
+TEST(silence_unused) {
+  EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
+  EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
+  EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
+}
+
+TEST(consumebytes_zero) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  EXPECT_NE(NULL, consumebytes(0, &pos, &len));
+  EXPECT_EQ(&buf[0], pos);
+  EXPECT_EQ(sizeof(buf), len);
+}
+
+TEST(consumebytes_exact) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  /* One past the end since it consumes the whole buffer. */
+  char *end = &buf[sizeof(buf)];
+  EXPECT_NE(NULL, consumebytes(len, &pos, &len));
+  EXPECT_EQ((size_t)0, len);
+  EXPECT_EQ(end, pos);
+}
+
+TEST(consumebytes_half) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  /* One past the end since it consumes the whole buffer. */
+  char *end = &buf[sizeof(buf) / 2];
+  EXPECT_NE(NULL, consumebytes(len / 2, &pos, &len));
+  EXPECT_EQ(sizeof(buf) / 2, len);
+  EXPECT_EQ(end, pos);
+}
+
+TEST(consumebytes_toolong) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  /* One past the end since it consumes the whole buffer. */
+  EXPECT_EQ(NULL, consumebytes(len + 1, &pos, &len));
+  EXPECT_EQ(sizeof(buf), len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr_zero) {
+  char buf[1024];
+  size_t len = 0;
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  EXPECT_EQ(NULL, consumestr(&pos, &len));
+  EXPECT_EQ((size_t)0, len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr_nonul) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  EXPECT_EQ(NULL, consumestr(&pos, &len));
+  EXPECT_EQ(sizeof(buf), len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr_full) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  buf[sizeof(buf)-1] = '\0';
+  EXPECT_EQ((void *)buf, consumestr(&pos, &len));
+  EXPECT_EQ((size_t)0, len);
+  EXPECT_EQ(&buf[sizeof(buf)], pos);
+}
+
+TEST(consumestr_trailing_nul) {
+  char buf[1024];
+  size_t len = sizeof(buf) - 1;
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  buf[sizeof(buf)-1] = '\0';
+  EXPECT_EQ(NULL, consumestr(&pos, &len));
+  EXPECT_EQ(sizeof(buf) - 1, len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+FIXTURE(marshal) {
+  char buf[4096];
+  struct minijail *m;
+  struct minijail *j;
+  size_t size;
+};
+
+FIXTURE_SETUP(marshal) {
+  self->m = minijail_new();
+  self->j = minijail_new();
+  ASSERT_TRUE(self->m && self->j) TH_LOG("allocation failed");
+  self->size = minijail_size(self->m);
+  ASSERT_GT(sizeof(self->buf), self->size) {
+    TH_LOG("static buffer too small for test");
+  }
+}
+
+FIXTURE_TEARDOWN(marshal) {
+  minijail_destroy(self->m);
+  minijail_destroy(self->j);
+}
+
+TEST_F(marshal, empty) {
+  ASSERT_EQ(0, minijail_marshal(self->m, self->buf, sizeof(self->buf)));
+  EXPECT_EQ(0, minijail_unmarshal(self->j, self->buf, self->size));
+}
+
+TEST_F(marshal, 0xff) {
+  memset(self->buf, 0xff, sizeof(self->buf));
+  /* Should fail on the first consumestr since a NUL will never be found. */
+  EXPECT_EQ(-EINVAL, minijail_unmarshal(self->j, self->buf, sizeof(self->buf)));
+}
+
+TEST(test_minijail_run_pid_pipes_no_preload) {
+  pid_t pid;
+  int child_stdin, child_stdout, child_stderr;
+  int mj_run_ret;
+  ssize_t write_ret, read_ret;
+  const size_t buf_len = 128;
+  char buf[buf_len];
+  int status;
+#if defined(__ANDROID__)
+  char filename[] = "/system/bin/cat";
+#else
+  char filename[] = "/bin/cat";
+#endif
+  char teststr[] = "test\n";
+  size_t teststr_len = strlen(teststr);
+  char *argv[4];
+
+  struct minijail *j = minijail_new();
+
+  argv[0] = filename;
+  argv[1] = NULL;
+  mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
+                                                 &pid,
+                                                 &child_stdin, &child_stdout,
+                                                 NULL);
+  EXPECT_EQ(mj_run_ret, 0);
+
+  write_ret = write(child_stdin, teststr, teststr_len);
+  EXPECT_EQ(write_ret, (int)teststr_len);
+
+  read_ret = read(child_stdout, buf, 8);
+  EXPECT_EQ(read_ret, (int)teststr_len);
+  buf[teststr_len] = 0;
+  EXPECT_EQ(strcmp(buf, teststr), 0);
+
+  EXPECT_EQ(kill(pid, SIGTERM), 0);
+  waitpid(pid, &status, 0);
+  ASSERT_TRUE(WIFSIGNALED(status));
+  EXPECT_EQ(WTERMSIG(status), SIGTERM);
+
+#if defined(__ANDROID__)
+  argv[0] = "/system/bin/sh";
+#else
+  argv[0] = "/bin/sh";
+#endif
+  argv[1] = "-c";
+  argv[2] = "echo test >&2";
+  argv[3] = NULL;
+  mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
+                                                 &child_stdin, &child_stdout,
+                                                 &child_stderr);
+  EXPECT_EQ(mj_run_ret, 0);
+
+  read_ret = read(child_stderr, buf, buf_len);
+  EXPECT_GE(read_ret, (int)teststr_len);
+
+  waitpid(pid, &status, 0);
+  ASSERT_TRUE(WIFEXITED(status));
+  EXPECT_EQ(WEXITSTATUS(status), 0);
+
+  minijail_destroy(j);
+}
+
+TEST_HARNESS_MAIN
diff --git a/minijail/libminijail_unittest.cpp b/minijail/libminijail_unittest.cpp
new file mode 100644
index 0000000..4e75bdc
--- /dev/null
+++ b/minijail/libminijail_unittest.cpp
@@ -0,0 +1,213 @@
+// libminijail_unittest.cpp
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Test platform independent logic of Minijail using gtest.
+
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <gtest/gtest.h>
+
+#include "libminijail.h"
+#include "libminijail-private.h"
+#include "util.h"
+
+/* Prototypes needed only by test. */
+void *consumebytes(size_t length, char **buf, size_t *buflength);
+char *consumestr(char **buf, size_t *buflength);
+
+/* Silence unused variable warnings. */
+TEST(silence, silence_unused) {
+  EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
+  EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
+  EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
+}
+
+TEST(consumebytes, zero) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  EXPECT_TRUE(NULL != consumebytes(0, &pos, &len));
+  EXPECT_EQ(&buf[0], pos);
+  EXPECT_EQ(sizeof(buf), len);
+}
+
+TEST(consumebytes, exact) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  /* One past the end since it consumes the whole buffer. */
+  char *end = &buf[sizeof(buf)];
+  EXPECT_TRUE(NULL != consumebytes(len, &pos, &len));
+  EXPECT_EQ((size_t)0, len);
+  EXPECT_EQ(end, pos);
+}
+
+TEST(consumebytes, half) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  /* One past the end since it consumes the whole buffer. */
+  char *end = &buf[sizeof(buf) / 2];
+  EXPECT_TRUE(NULL != consumebytes(len / 2, &pos, &len));
+  EXPECT_EQ(sizeof(buf) / 2, len);
+  EXPECT_EQ(end, pos);
+}
+
+TEST(consumebytes, toolong) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  /* One past the end since it consumes the whole buffer. */
+  EXPECT_TRUE(NULL == consumebytes(len + 1, &pos, &len));
+  EXPECT_EQ(sizeof(buf), len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr, zero) {
+  char buf[1024];
+  size_t len = 0;
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  EXPECT_EQ(NULL, consumestr(&pos, &len));
+  EXPECT_EQ((size_t)0, len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr, nonul) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  EXPECT_EQ(NULL, consumestr(&pos, &len));
+  EXPECT_EQ(sizeof(buf), len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr, full) {
+  char buf[1024];
+  size_t len = sizeof(buf);
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  buf[sizeof(buf)-1] = '\0';
+  EXPECT_EQ((void *)buf, consumestr(&pos, &len));
+  EXPECT_EQ((size_t)0, len);
+  EXPECT_EQ(&buf[sizeof(buf)], pos);
+}
+
+TEST(consumestr, trailing_nul) {
+  char buf[1024];
+  size_t len = sizeof(buf) - 1;
+  char *pos = &buf[0];
+  memset(buf, 0xff, sizeof(buf));
+  buf[sizeof(buf)-1] = '\0';
+  EXPECT_EQ(NULL, consumestr(&pos, &len));
+  EXPECT_EQ(sizeof(buf) - 1, len);
+  EXPECT_EQ(&buf[0], pos);
+}
+
+class MarshalTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    m_ = minijail_new();
+    j_ = minijail_new();
+    size_ = minijail_size(m_);
+  }
+  virtual void TearDown() {
+    minijail_destroy(m_);
+    minijail_destroy(j_);
+  }
+
+  char buf_[4096];
+  struct minijail *m_;
+  struct minijail *j_;
+  size_t size_;
+};
+
+TEST_F(MarshalTest, empty) {
+  ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
+  EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
+}
+
+TEST_F(MarshalTest, 0xff) {
+  memset(buf_, 0xff, sizeof(buf_));
+  /* Should fail on the first consumestr since a NUL will never be found. */
+  EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
+}
+
+TEST(Test, minijail_run_pid_pipes_no_preload) {
+  pid_t pid;
+  int child_stdin, child_stdout, child_stderr;
+  int mj_run_ret;
+  ssize_t write_ret, read_ret;
+  const size_t buf_len = 128;
+  char buf[buf_len];
+  int status;
+#if defined(__ANDROID__)
+  char filename[] = "/system/bin/cat";
+#else
+  char filename[] = "/bin/cat";
+#endif
+  char teststr[] = "test\n";
+  size_t teststr_len = strlen(teststr);
+  char *argv[4];
+
+  struct minijail *j = minijail_new();
+
+  argv[0] = filename;
+  argv[1] = NULL;
+  mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
+                                                 &pid,
+                                                 &child_stdin, &child_stdout,
+                                                 NULL);
+  EXPECT_EQ(mj_run_ret, 0);
+
+  write_ret = write(child_stdin, teststr, teststr_len);
+  EXPECT_EQ(write_ret, (int)teststr_len);
+
+  read_ret = read(child_stdout, buf, 8);
+  EXPECT_EQ(read_ret, (int)teststr_len);
+  buf[teststr_len] = 0;
+  EXPECT_EQ(strcmp(buf, teststr), 0);
+
+  EXPECT_EQ(kill(pid, SIGTERM), 0);
+  waitpid(pid, &status, 0);
+  ASSERT_TRUE(WIFSIGNALED(status));
+  EXPECT_EQ(WTERMSIG(status), SIGTERM);
+
+#if defined(__ANDROID__)
+  argv[0] = "/system/bin/sh";
+#else
+  argv[0] = "/bin/sh";
+#endif
+  argv[1] = "-c";
+  argv[2] = "echo test >&2";
+  argv[3] = NULL;
+  mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
+                                                 &child_stdin, &child_stdout,
+                                                 &child_stderr);
+  EXPECT_EQ(mj_run_ret, 0);
+
+  read_ret = read(child_stderr, buf, buf_len);
+  EXPECT_GE(read_ret, (int)teststr_len);
+
+  waitpid(pid, &status, 0);
+  ASSERT_TRUE(WIFEXITED(status));
+  EXPECT_EQ(WEXITSTATUS(status), 0);
+
+  minijail_destroy(j);
+}
diff --git a/minijail/libminijailpreload.c b/minijail/libminijailpreload.c
new file mode 100644
index 0000000..a1e376e
--- /dev/null
+++ b/minijail/libminijailpreload.c
@@ -0,0 +1,147 @@
+/* libminijailpreload.c - preload hack library
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * This library is preloaded into every program launched by minijail_run().
+ * DO NOT EXPORT ANY SYMBOLS FROM THIS LIBRARY. They will replace other symbols
+ * in the programs it is preloaded into and cause impossible-to-debug failures.
+ * See the minijail0.1 for a design explanation.
+ */
+
+#include "libminijail.h"
+#include "libminijail-private.h"
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+static int (*real_main) (int, char **, char **);
+static void *libc_handle;
+
+static void die(const char *failed)
+{
+	syslog(LOG_ERR, "libminijail: %s", failed);
+	abort();
+}
+
+static void unset_in_env(char **envp, const char *name)
+{
+	int i;
+	for (i = 0; envp[i]; i++)
+		if (!strncmp(envp[i], name, strlen(name)))
+			envp[i][0] = '\0';
+}
+
+/** @brief Fake main(), spliced in before the real call to main() by
+ *         __libc_start_main (see below).
+ *  We get serialized commands from our invoking process over an fd specified
+ *  by an environment variable (kFdEnvVar). The environment variable is a list
+ *  of key=value pairs (see move_commands_to_env); we use them to construct a
+ *  jail, then enter it.
+ */
+static int fake_main(int argc, char **argv, char **envp)
+{
+	char *fd_name = getenv(kFdEnvVar);
+	int fd = -1;
+	struct minijail *j;
+	if (geteuid() != getuid() || getegid() != getgid()) {
+		/*
+		 * If we didn't do this check, an attacker could set kFdEnvVar
+		 * for any setuid program that uses libminijail to cause it to
+		 * get capabilities or a uid it did not expect.
+		 */
+		/* TODO(wad): why would libminijail interact here? */
+		return MINIJAIL_ERR_PRELOAD;
+	}
+	if (!fd_name)
+		return MINIJAIL_ERR_PRELOAD;
+	fd = atoi(fd_name);
+	if (fd < 0)
+		return MINIJAIL_ERR_PRELOAD;
+
+	j = minijail_new();
+	if (!j)
+		die("preload: out of memory");
+	if (minijail_from_fd(fd, j))
+		die("preload: failed to parse minijail from parent");
+	close(fd);
+
+	/* TODO(ellyjones): this trashes existing preloads, so one can't do:
+	 * LD_PRELOAD="/tmp/test.so libminijailpreload.so" prog; the
+	 * descendants of prog will have no LD_PRELOAD set at all.
+	 */
+	unset_in_env(envp, kLdPreloadEnvVar);
+	/* Strip out flags meant for the parent. */
+	minijail_preenter(j);
+	minijail_enter(j);
+	minijail_destroy(j);
+	dlclose(libc_handle);
+	return real_main(argc, argv, envp);
+}
+
+/** @brief LD_PRELOAD override of __libc_start_main.
+ *
+ *  It is really best if you do not look too closely at this function.  We need
+ *  to ensure that some of our code runs before the target program (see the
+ *  minijail0.1 file in this directory for high-level details about this), and
+ *  the only available place to hook is this function, which is normally
+ *  responsible for calling main(). Our LD_PRELOAD will overwrite the real
+ *  __libc_start_main with this one, so we have to look up the real one from
+ *  libc and invoke it with a pointer to the fake main() we'd like to run before
+ *  the real main(). We can't just run our setup code *here* because
+ *  __libc_start_main is responsible for setting up the C runtime environment,
+ *  so we can't rely on things like malloc() being available yet.
+ */
+
+int API __libc_start_main(int (*main)(int, char **, char **), int argc,
+			  char **ubp_av, void (*init)(void), void (*fini)(void),
+			  void (*rtld_fini)(void), void(*stack_end))
+{
+	void *sym;
+	/*
+	 * This hack is unfortunately required by C99 - casting directly from
+	 * void* to function pointers is left undefined. See POSIX.1-2003, the
+	 * Rationale for the specification of dlsym(), and dlsym(3). This
+	 * deliberately violates strict-aliasing rules, but gcc can't tell.
+	 */
+	union {
+		int (*fn)(int (*main)(int, char **, char **), int argc,
+			  char **ubp_av, void (*init)(void), void (*fini)(void),
+			  void (*rtld_fini)(void), void(*stack_end));
+		void *symval;
+	} real_libc_start_main;
+
+	/*
+	 * We hold this handle for the duration of the real __libc_start_main()
+	 * and drop it just before calling the real main().
+	 */
+	libc_handle = dlopen("libc.so.6", RTLD_NOW);
+
+	if (!libc_handle) {
+		syslog(LOG_ERR, "can't dlopen() libc");
+		/*
+		 * We dare not use abort() here because it will run atexit()
+		 * handlers and try to flush stdio.
+		 */
+		_exit(1);
+	}
+	sym = dlsym(libc_handle, "__libc_start_main");
+	if (!sym) {
+		syslog(LOG_ERR, "can't find the real __libc_start_main()");
+		_exit(1);
+	}
+	real_libc_start_main.symval = sym;
+	real_main = main;
+
+	/*
+	 * Note that we swap fake_main in for main - fake_main knows that it
+	 * should call real_main after it's done.
+	 */
+	return real_libc_start_main.fn(fake_main, argc, ubp_av, init, fini,
+				       rtld_fini, stack_end);
+}
diff --git a/minijail/libsyscalls.h b/minijail/libsyscalls.h
new file mode 100644
index 0000000..f6c3212
--- /dev/null
+++ b/minijail/libsyscalls.h
@@ -0,0 +1,16 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef MINIJAIL_LIBSYSCALLS_H_
+#define MINIJAIL_LIBSYSCALLS_H_
+#include <sys/types.h>
+
+struct syscall_entry {
+	const char *name;
+	int nr;
+};
+
+extern const struct syscall_entry syscall_table[];
+
+#endif  /* MINIJAIL_LIBSYSCALLS_H_ */
diff --git a/minijail/linux-x86/libconstants.gen.c b/minijail/linux-x86/libconstants.gen.c
new file mode 100644
index 0000000..36df6b0
--- /dev/null
+++ b/minijail/linux-x86/libconstants.gen.c
@@ -0,0 +1,1245 @@
+/* GENERATED BY MAKEFILE */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/prctl.h>
+#include <linux/sched.h>
+#include <stddef.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "libconstants.h"
+const struct constant_entry constant_table[] = {
+#ifdef AT_EACCESS
+  { "AT_EACCESS", (unsigned long) AT_EACCESS },
+#endif  // AT_EACCESS
+#ifdef AT_REMOVEDIR
+  { "AT_REMOVEDIR", (unsigned long) AT_REMOVEDIR },
+#endif  // AT_REMOVEDIR
+#ifdef AT_SYMLINK_FOLLOW
+  { "AT_SYMLINK_FOLLOW", (unsigned long) AT_SYMLINK_FOLLOW },
+#endif  // AT_SYMLINK_FOLLOW
+#ifdef AT_SYMLINK_NOFOLLOW
+  { "AT_SYMLINK_NOFOLLOW", (unsigned long) AT_SYMLINK_NOFOLLOW },
+#endif  // AT_SYMLINK_NOFOLLOW
+#ifdef BUS_ADRALN
+  { "BUS_ADRALN", (unsigned long) BUS_ADRALN },
+#endif  // BUS_ADRALN
+#ifdef BUS_ADRERR
+  { "BUS_ADRERR", (unsigned long) BUS_ADRERR },
+#endif  // BUS_ADRERR
+#ifdef BUS_MCEERR_AO
+  { "BUS_MCEERR_AO", (unsigned long) BUS_MCEERR_AO },
+#endif  // BUS_MCEERR_AO
+#ifdef BUS_MCEERR_AR
+  { "BUS_MCEERR_AR", (unsigned long) BUS_MCEERR_AR },
+#endif  // BUS_MCEERR_AR
+#ifdef BUS_OBJERR
+  { "BUS_OBJERR", (unsigned long) BUS_OBJERR },
+#endif  // BUS_OBJERR
+#ifdef CLD_CONTINUED
+  { "CLD_CONTINUED", (unsigned long) CLD_CONTINUED },
+#endif  // CLD_CONTINUED
+#ifdef CLD_DUMPED
+  { "CLD_DUMPED", (unsigned long) CLD_DUMPED },
+#endif  // CLD_DUMPED
+#ifdef CLD_EXITED
+  { "CLD_EXITED", (unsigned long) CLD_EXITED },
+#endif  // CLD_EXITED
+#ifdef CLD_KILLED
+  { "CLD_KILLED", (unsigned long) CLD_KILLED },
+#endif  // CLD_KILLED
+#ifdef CLD_STOPPED
+  { "CLD_STOPPED", (unsigned long) CLD_STOPPED },
+#endif  // CLD_STOPPED
+#ifdef CLD_TRAPPED
+  { "CLD_TRAPPED", (unsigned long) CLD_TRAPPED },
+#endif  // CLD_TRAPPED
+#ifdef CLONE_CHILD_CLEARTID
+  { "CLONE_CHILD_CLEARTID", (unsigned long) CLONE_CHILD_CLEARTID },
+#endif  // CLONE_CHILD_CLEARTID
+#ifdef CLONE_CHILD_SETTID
+  { "CLONE_CHILD_SETTID", (unsigned long) CLONE_CHILD_SETTID },
+#endif  // CLONE_CHILD_SETTID
+#ifdef CLONE_DETACHED
+  { "CLONE_DETACHED", (unsigned long) CLONE_DETACHED },
+#endif  // CLONE_DETACHED
+#ifdef CLONE_FILES
+  { "CLONE_FILES", (unsigned long) CLONE_FILES },
+#endif  // CLONE_FILES
+#ifdef CLONE_FS
+  { "CLONE_FS", (unsigned long) CLONE_FS },
+#endif  // CLONE_FS
+#ifdef CLONE_IO
+  { "CLONE_IO", (unsigned long) CLONE_IO },
+#endif  // CLONE_IO
+#ifdef CLONE_NEWIPC
+  { "CLONE_NEWIPC", (unsigned long) CLONE_NEWIPC },
+#endif  // CLONE_NEWIPC
+#ifdef CLONE_NEWNET
+  { "CLONE_NEWNET", (unsigned long) CLONE_NEWNET },
+#endif  // CLONE_NEWNET
+#ifdef CLONE_NEWNS
+  { "CLONE_NEWNS", (unsigned long) CLONE_NEWNS },
+#endif  // CLONE_NEWNS
+#ifdef CLONE_NEWPID
+  { "CLONE_NEWPID", (unsigned long) CLONE_NEWPID },
+#endif  // CLONE_NEWPID
+#ifdef CLONE_NEWUSER
+  { "CLONE_NEWUSER", (unsigned long) CLONE_NEWUSER },
+#endif  // CLONE_NEWUSER
+#ifdef CLONE_NEWUTS
+  { "CLONE_NEWUTS", (unsigned long) CLONE_NEWUTS },
+#endif  // CLONE_NEWUTS
+#ifdef CLONE_PARENT
+  { "CLONE_PARENT", (unsigned long) CLONE_PARENT },
+#endif  // CLONE_PARENT
+#ifdef CLONE_PARENT_SETTID
+  { "CLONE_PARENT_SETTID", (unsigned long) CLONE_PARENT_SETTID },
+#endif  // CLONE_PARENT_SETTID
+#ifdef CLONE_PTRACE
+  { "CLONE_PTRACE", (unsigned long) CLONE_PTRACE },
+#endif  // CLONE_PTRACE
+#ifdef CLONE_SETTLS
+  { "CLONE_SETTLS", (unsigned long) CLONE_SETTLS },
+#endif  // CLONE_SETTLS
+#ifdef CLONE_SIGHAND
+  { "CLONE_SIGHAND", (unsigned long) CLONE_SIGHAND },
+#endif  // CLONE_SIGHAND
+#ifdef CLONE_SYSVSEM
+  { "CLONE_SYSVSEM", (unsigned long) CLONE_SYSVSEM },
+#endif  // CLONE_SYSVSEM
+#ifdef CLONE_THREAD
+  { "CLONE_THREAD", (unsigned long) CLONE_THREAD },
+#endif  // CLONE_THREAD
+#ifdef CLONE_UNTRACED
+  { "CLONE_UNTRACED", (unsigned long) CLONE_UNTRACED },
+#endif  // CLONE_UNTRACED
+#ifdef CLONE_VFORK
+  { "CLONE_VFORK", (unsigned long) CLONE_VFORK },
+#endif  // CLONE_VFORK
+#ifdef CLONE_VM
+  { "CLONE_VM", (unsigned long) CLONE_VM },
+#endif  // CLONE_VM
+#ifdef CSIGNAL
+  { "CSIGNAL", (unsigned long) CSIGNAL },
+#endif  // CSIGNAL
+#ifdef E2BIG
+  { "E2BIG", (unsigned long) E2BIG },
+#endif  // E2BIG
+#ifdef EACCES
+  { "EACCES", (unsigned long) EACCES },
+#endif  // EACCES
+#ifdef EADDRINUSE
+  { "EADDRINUSE", (unsigned long) EADDRINUSE },
+#endif  // EADDRINUSE
+#ifdef EADDRNOTAVAIL
+  { "EADDRNOTAVAIL", (unsigned long) EADDRNOTAVAIL },
+#endif  // EADDRNOTAVAIL
+#ifdef EADV
+  { "EADV", (unsigned long) EADV },
+#endif  // EADV
+#ifdef EAFNOSUPPORT
+  { "EAFNOSUPPORT", (unsigned long) EAFNOSUPPORT },
+#endif  // EAFNOSUPPORT
+#ifdef EAGAIN
+  { "EAGAIN", (unsigned long) EAGAIN },
+#endif  // EAGAIN
+#ifdef EALREADY
+  { "EALREADY", (unsigned long) EALREADY },
+#endif  // EALREADY
+#ifdef EBADE
+  { "EBADE", (unsigned long) EBADE },
+#endif  // EBADE
+#ifdef EBADF
+  { "EBADF", (unsigned long) EBADF },
+#endif  // EBADF
+#ifdef EBADFD
+  { "EBADFD", (unsigned long) EBADFD },
+#endif  // EBADFD
+#ifdef EBADMSG
+  { "EBADMSG", (unsigned long) EBADMSG },
+#endif  // EBADMSG
+#ifdef EBADR
+  { "EBADR", (unsigned long) EBADR },
+#endif  // EBADR
+#ifdef EBADRQC
+  { "EBADRQC", (unsigned long) EBADRQC },
+#endif  // EBADRQC
+#ifdef EBADSLT
+  { "EBADSLT", (unsigned long) EBADSLT },
+#endif  // EBADSLT
+#ifdef EBFONT
+  { "EBFONT", (unsigned long) EBFONT },
+#endif  // EBFONT
+#ifdef EBUSY
+  { "EBUSY", (unsigned long) EBUSY },
+#endif  // EBUSY
+#ifdef ECANCELED
+  { "ECANCELED", (unsigned long) ECANCELED },
+#endif  // ECANCELED
+#ifdef ECHILD
+  { "ECHILD", (unsigned long) ECHILD },
+#endif  // ECHILD
+#ifdef ECHRNG
+  { "ECHRNG", (unsigned long) ECHRNG },
+#endif  // ECHRNG
+#ifdef ECOMM
+  { "ECOMM", (unsigned long) ECOMM },
+#endif  // ECOMM
+#ifdef ECONNABORTED
+  { "ECONNABORTED", (unsigned long) ECONNABORTED },
+#endif  // ECONNABORTED
+#ifdef ECONNREFUSED
+  { "ECONNREFUSED", (unsigned long) ECONNREFUSED },
+#endif  // ECONNREFUSED
+#ifdef ECONNRESET
+  { "ECONNRESET", (unsigned long) ECONNRESET },
+#endif  // ECONNRESET
+#ifdef EDEADLK
+  { "EDEADLK", (unsigned long) EDEADLK },
+#endif  // EDEADLK
+#ifdef EDEADLOCK
+  { "EDEADLOCK", (unsigned long) EDEADLOCK },
+#endif  // EDEADLOCK
+#ifdef EDESTADDRREQ
+  { "EDESTADDRREQ", (unsigned long) EDESTADDRREQ },
+#endif  // EDESTADDRREQ
+#ifdef EDOM
+  { "EDOM", (unsigned long) EDOM },
+#endif  // EDOM
+#ifdef EDOTDOT
+  { "EDOTDOT", (unsigned long) EDOTDOT },
+#endif  // EDOTDOT
+#ifdef EDQUOT
+  { "EDQUOT", (unsigned long) EDQUOT },
+#endif  // EDQUOT
+#ifdef EEXIST
+  { "EEXIST", (unsigned long) EEXIST },
+#endif  // EEXIST
+#ifdef EFAULT
+  { "EFAULT", (unsigned long) EFAULT },
+#endif  // EFAULT
+#ifdef EFBIG
+  { "EFBIG", (unsigned long) EFBIG },
+#endif  // EFBIG
+#ifdef EHOSTDOWN
+  { "EHOSTDOWN", (unsigned long) EHOSTDOWN },
+#endif  // EHOSTDOWN
+#ifdef EHOSTUNREACH
+  { "EHOSTUNREACH", (unsigned long) EHOSTUNREACH },
+#endif  // EHOSTUNREACH
+#ifdef EHWPOISON
+  { "EHWPOISON", (unsigned long) EHWPOISON },
+#endif  // EHWPOISON
+#ifdef EIDRM
+  { "EIDRM", (unsigned long) EIDRM },
+#endif  // EIDRM
+#ifdef EILSEQ
+  { "EILSEQ", (unsigned long) EILSEQ },
+#endif  // EILSEQ
+#ifdef EINPROGRESS
+  { "EINPROGRESS", (unsigned long) EINPROGRESS },
+#endif  // EINPROGRESS
+#ifdef EINTR
+  { "EINTR", (unsigned long) EINTR },
+#endif  // EINTR
+#ifdef EINVAL
+  { "EINVAL", (unsigned long) EINVAL },
+#endif  // EINVAL
+#ifdef EIO
+  { "EIO", (unsigned long) EIO },
+#endif  // EIO
+#ifdef EISCONN
+  { "EISCONN", (unsigned long) EISCONN },
+#endif  // EISCONN
+#ifdef EISDIR
+  { "EISDIR", (unsigned long) EISDIR },
+#endif  // EISDIR
+#ifdef EISNAM
+  { "EISNAM", (unsigned long) EISNAM },
+#endif  // EISNAM
+#ifdef EKEYEXPIRED
+  { "EKEYEXPIRED", (unsigned long) EKEYEXPIRED },
+#endif  // EKEYEXPIRED
+#ifdef EKEYREJECTED
+  { "EKEYREJECTED", (unsigned long) EKEYREJECTED },
+#endif  // EKEYREJECTED
+#ifdef EKEYREVOKED
+  { "EKEYREVOKED", (unsigned long) EKEYREVOKED },
+#endif  // EKEYREVOKED
+#ifdef EL2HLT
+  { "EL2HLT", (unsigned long) EL2HLT },
+#endif  // EL2HLT
+#ifdef EL2NSYNC
+  { "EL2NSYNC", (unsigned long) EL2NSYNC },
+#endif  // EL2NSYNC
+#ifdef EL3HLT
+  { "EL3HLT", (unsigned long) EL3HLT },
+#endif  // EL3HLT
+#ifdef EL3RST
+  { "EL3RST", (unsigned long) EL3RST },
+#endif  // EL3RST
+#ifdef ELIBACC
+  { "ELIBACC", (unsigned long) ELIBACC },
+#endif  // ELIBACC
+#ifdef ELIBBAD
+  { "ELIBBAD", (unsigned long) ELIBBAD },
+#endif  // ELIBBAD
+#ifdef ELIBEXEC
+  { "ELIBEXEC", (unsigned long) ELIBEXEC },
+#endif  // ELIBEXEC
+#ifdef ELIBMAX
+  { "ELIBMAX", (unsigned long) ELIBMAX },
+#endif  // ELIBMAX
+#ifdef ELIBSCN
+  { "ELIBSCN", (unsigned long) ELIBSCN },
+#endif  // ELIBSCN
+#ifdef ELNRNG
+  { "ELNRNG", (unsigned long) ELNRNG },
+#endif  // ELNRNG
+#ifdef ELOOP
+  { "ELOOP", (unsigned long) ELOOP },
+#endif  // ELOOP
+#ifdef EMEDIUMTYPE
+  { "EMEDIUMTYPE", (unsigned long) EMEDIUMTYPE },
+#endif  // EMEDIUMTYPE
+#ifdef EMFILE
+  { "EMFILE", (unsigned long) EMFILE },
+#endif  // EMFILE
+#ifdef EMLINK
+  { "EMLINK", (unsigned long) EMLINK },
+#endif  // EMLINK
+#ifdef EMSGSIZE
+  { "EMSGSIZE", (unsigned long) EMSGSIZE },
+#endif  // EMSGSIZE
+#ifdef EMULTIHOP
+  { "EMULTIHOP", (unsigned long) EMULTIHOP },
+#endif  // EMULTIHOP
+#ifdef ENAMETOOLONG
+  { "ENAMETOOLONG", (unsigned long) ENAMETOOLONG },
+#endif  // ENAMETOOLONG
+#ifdef ENAVAIL
+  { "ENAVAIL", (unsigned long) ENAVAIL },
+#endif  // ENAVAIL
+#ifdef ENETDOWN
+  { "ENETDOWN", (unsigned long) ENETDOWN },
+#endif  // ENETDOWN
+#ifdef ENETRESET
+  { "ENETRESET", (unsigned long) ENETRESET },
+#endif  // ENETRESET
+#ifdef ENETUNREACH
+  { "ENETUNREACH", (unsigned long) ENETUNREACH },
+#endif  // ENETUNREACH
+#ifdef ENFILE
+  { "ENFILE", (unsigned long) ENFILE },
+#endif  // ENFILE
+#ifdef ENOANO
+  { "ENOANO", (unsigned long) ENOANO },
+#endif  // ENOANO
+#ifdef ENOBUFS
+  { "ENOBUFS", (unsigned long) ENOBUFS },
+#endif  // ENOBUFS
+#ifdef ENOCSI
+  { "ENOCSI", (unsigned long) ENOCSI },
+#endif  // ENOCSI
+#ifdef ENODATA
+  { "ENODATA", (unsigned long) ENODATA },
+#endif  // ENODATA
+#ifdef ENODEV
+  { "ENODEV", (unsigned long) ENODEV },
+#endif  // ENODEV
+#ifdef ENOENT
+  { "ENOENT", (unsigned long) ENOENT },
+#endif  // ENOENT
+#ifdef ENOEXEC
+  { "ENOEXEC", (unsigned long) ENOEXEC },
+#endif  // ENOEXEC
+#ifdef ENOKEY
+  { "ENOKEY", (unsigned long) ENOKEY },
+#endif  // ENOKEY
+#ifdef ENOLCK
+  { "ENOLCK", (unsigned long) ENOLCK },
+#endif  // ENOLCK
+#ifdef ENOLINK
+  { "ENOLINK", (unsigned long) ENOLINK },
+#endif  // ENOLINK
+#ifdef ENOMEDIUM
+  { "ENOMEDIUM", (unsigned long) ENOMEDIUM },
+#endif  // ENOMEDIUM
+#ifdef ENOMEM
+  { "ENOMEM", (unsigned long) ENOMEM },
+#endif  // ENOMEM
+#ifdef ENOMSG
+  { "ENOMSG", (unsigned long) ENOMSG },
+#endif  // ENOMSG
+#ifdef ENONET
+  { "ENONET", (unsigned long) ENONET },
+#endif  // ENONET
+#ifdef ENOPKG
+  { "ENOPKG", (unsigned long) ENOPKG },
+#endif  // ENOPKG
+#ifdef ENOPROTOOPT
+  { "ENOPROTOOPT", (unsigned long) ENOPROTOOPT },
+#endif  // ENOPROTOOPT
+#ifdef ENOSPC
+  { "ENOSPC", (unsigned long) ENOSPC },
+#endif  // ENOSPC
+#ifdef ENOSR
+  { "ENOSR", (unsigned long) ENOSR },
+#endif  // ENOSR
+#ifdef ENOSTR
+  { "ENOSTR", (unsigned long) ENOSTR },
+#endif  // ENOSTR
+#ifdef ENOSYS
+  { "ENOSYS", (unsigned long) ENOSYS },
+#endif  // ENOSYS
+#ifdef ENOTBLK
+  { "ENOTBLK", (unsigned long) ENOTBLK },
+#endif  // ENOTBLK
+#ifdef ENOTCONN
+  { "ENOTCONN", (unsigned long) ENOTCONN },
+#endif  // ENOTCONN
+#ifdef ENOTDIR
+  { "ENOTDIR", (unsigned long) ENOTDIR },
+#endif  // ENOTDIR
+#ifdef ENOTEMPTY
+  { "ENOTEMPTY", (unsigned long) ENOTEMPTY },
+#endif  // ENOTEMPTY
+#ifdef ENOTNAM
+  { "ENOTNAM", (unsigned long) ENOTNAM },
+#endif  // ENOTNAM
+#ifdef ENOTRECOVERABLE
+  { "ENOTRECOVERABLE", (unsigned long) ENOTRECOVERABLE },
+#endif  // ENOTRECOVERABLE
+#ifdef ENOTSOCK
+  { "ENOTSOCK", (unsigned long) ENOTSOCK },
+#endif  // ENOTSOCK
+#ifdef ENOTSUP
+  { "ENOTSUP", (unsigned long) ENOTSUP },
+#endif  // ENOTSUP
+#ifdef ENOTTY
+  { "ENOTTY", (unsigned long) ENOTTY },
+#endif  // ENOTTY
+#ifdef ENOTUNIQ
+  { "ENOTUNIQ", (unsigned long) ENOTUNIQ },
+#endif  // ENOTUNIQ
+#ifdef ENXIO
+  { "ENXIO", (unsigned long) ENXIO },
+#endif  // ENXIO
+#ifdef EOPNOTSUPP
+  { "EOPNOTSUPP", (unsigned long) EOPNOTSUPP },
+#endif  // EOPNOTSUPP
+#ifdef EOVERFLOW
+  { "EOVERFLOW", (unsigned long) EOVERFLOW },
+#endif  // EOVERFLOW
+#ifdef EOWNERDEAD
+  { "EOWNERDEAD", (unsigned long) EOWNERDEAD },
+#endif  // EOWNERDEAD
+#ifdef EPERM
+  { "EPERM", (unsigned long) EPERM },
+#endif  // EPERM
+#ifdef EPFNOSUPPORT
+  { "EPFNOSUPPORT", (unsigned long) EPFNOSUPPORT },
+#endif  // EPFNOSUPPORT
+#ifdef EPIPE
+  { "EPIPE", (unsigned long) EPIPE },
+#endif  // EPIPE
+#ifdef EPROTO
+  { "EPROTO", (unsigned long) EPROTO },
+#endif  // EPROTO
+#ifdef EPROTONOSUPPORT
+  { "EPROTONOSUPPORT", (unsigned long) EPROTONOSUPPORT },
+#endif  // EPROTONOSUPPORT
+#ifdef EPROTOTYPE
+  { "EPROTOTYPE", (unsigned long) EPROTOTYPE },
+#endif  // EPROTOTYPE
+#ifdef ERANGE
+  { "ERANGE", (unsigned long) ERANGE },
+#endif  // ERANGE
+#ifdef EREMCHG
+  { "EREMCHG", (unsigned long) EREMCHG },
+#endif  // EREMCHG
+#ifdef EREMOTE
+  { "EREMOTE", (unsigned long) EREMOTE },
+#endif  // EREMOTE
+#ifdef EREMOTEIO
+  { "EREMOTEIO", (unsigned long) EREMOTEIO },
+#endif  // EREMOTEIO
+#ifdef ERESTART
+  { "ERESTART", (unsigned long) ERESTART },
+#endif  // ERESTART
+#ifdef ERFKILL
+  { "ERFKILL", (unsigned long) ERFKILL },
+#endif  // ERFKILL
+#ifdef EROFS
+  { "EROFS", (unsigned long) EROFS },
+#endif  // EROFS
+#ifdef ESHUTDOWN
+  { "ESHUTDOWN", (unsigned long) ESHUTDOWN },
+#endif  // ESHUTDOWN
+#ifdef ESOCKTNOSUPPORT
+  { "ESOCKTNOSUPPORT", (unsigned long) ESOCKTNOSUPPORT },
+#endif  // ESOCKTNOSUPPORT
+#ifdef ESPIPE
+  { "ESPIPE", (unsigned long) ESPIPE },
+#endif  // ESPIPE
+#ifdef ESRCH
+  { "ESRCH", (unsigned long) ESRCH },
+#endif  // ESRCH
+#ifdef ESRMNT
+  { "ESRMNT", (unsigned long) ESRMNT },
+#endif  // ESRMNT
+#ifdef ESTALE
+  { "ESTALE", (unsigned long) ESTALE },
+#endif  // ESTALE
+#ifdef ESTRPIPE
+  { "ESTRPIPE", (unsigned long) ESTRPIPE },
+#endif  // ESTRPIPE
+#ifdef ETIME
+  { "ETIME", (unsigned long) ETIME },
+#endif  // ETIME
+#ifdef ETIMEDOUT
+  { "ETIMEDOUT", (unsigned long) ETIMEDOUT },
+#endif  // ETIMEDOUT
+#ifdef ETOOMANYREFS
+  { "ETOOMANYREFS", (unsigned long) ETOOMANYREFS },
+#endif  // ETOOMANYREFS
+#ifdef ETXTBSY
+  { "ETXTBSY", (unsigned long) ETXTBSY },
+#endif  // ETXTBSY
+#ifdef EUCLEAN
+  { "EUCLEAN", (unsigned long) EUCLEAN },
+#endif  // EUCLEAN
+#ifdef EUNATCH
+  { "EUNATCH", (unsigned long) EUNATCH },
+#endif  // EUNATCH
+#ifdef EUSERS
+  { "EUSERS", (unsigned long) EUSERS },
+#endif  // EUSERS
+#ifdef EWOULDBLOCK
+  { "EWOULDBLOCK", (unsigned long) EWOULDBLOCK },
+#endif  // EWOULDBLOCK
+#ifdef EXDEV
+  { "EXDEV", (unsigned long) EXDEV },
+#endif  // EXDEV
+#ifdef EXFULL
+  { "EXFULL", (unsigned long) EXFULL },
+#endif  // EXFULL
+#ifdef FAPPEND
+  { "FAPPEND", (unsigned long) FAPPEND },
+#endif  // FAPPEND
+#ifdef FASYNC
+  { "FASYNC", (unsigned long) FASYNC },
+#endif  // FASYNC
+#ifdef FD_CLOEXEC
+  { "FD_CLOEXEC", (unsigned long) FD_CLOEXEC },
+#endif  // FD_CLOEXEC
+#ifdef F_DUPFD
+  { "F_DUPFD", (unsigned long) F_DUPFD },
+#endif  // F_DUPFD
+#ifdef F_DUPFD_CLOEXEC
+  { "F_DUPFD_CLOEXEC", (unsigned long) F_DUPFD_CLOEXEC },
+#endif  // F_DUPFD_CLOEXEC
+#ifdef F_EXLCK
+  { "F_EXLCK", (unsigned long) F_EXLCK },
+#endif  // F_EXLCK
+#ifdef FFSYNC
+  { "FFSYNC", (unsigned long) FFSYNC },
+#endif  // FFSYNC
+#ifdef F_GETFD
+  { "F_GETFD", (unsigned long) F_GETFD },
+#endif  // F_GETFD
+#ifdef F_GETFL
+  { "F_GETFL", (unsigned long) F_GETFL },
+#endif  // F_GETFL
+#ifdef F_GETLK
+  { "F_GETLK", (unsigned long) F_GETLK },
+#endif  // F_GETLK
+#ifdef F_GETLK64
+  { "F_GETLK64", (unsigned long) F_GETLK64 },
+#endif  // F_GETLK64
+#ifdef F_LOCK
+  { "F_LOCK", (unsigned long) F_LOCK },
+#endif  // F_LOCK
+#ifdef FNDELAY
+  { "FNDELAY", (unsigned long) FNDELAY },
+#endif  // FNDELAY
+#ifdef FNONBLOCK
+  { "FNONBLOCK", (unsigned long) FNONBLOCK },
+#endif  // FNONBLOCK
+#ifdef F_OK
+  { "F_OK", (unsigned long) F_OK },
+#endif  // F_OK
+#ifdef FPE_FLTDIV
+  { "FPE_FLTDIV", (unsigned long) FPE_FLTDIV },
+#endif  // FPE_FLTDIV
+#ifdef FPE_FLTINV
+  { "FPE_FLTINV", (unsigned long) FPE_FLTINV },
+#endif  // FPE_FLTINV
+#ifdef FPE_FLTOVF
+  { "FPE_FLTOVF", (unsigned long) FPE_FLTOVF },
+#endif  // FPE_FLTOVF
+#ifdef FPE_FLTRES
+  { "FPE_FLTRES", (unsigned long) FPE_FLTRES },
+#endif  // FPE_FLTRES
+#ifdef FPE_FLTSUB
+  { "FPE_FLTSUB", (unsigned long) FPE_FLTSUB },
+#endif  // FPE_FLTSUB
+#ifdef FPE_FLTUND
+  { "FPE_FLTUND", (unsigned long) FPE_FLTUND },
+#endif  // FPE_FLTUND
+#ifdef FPE_INTDIV
+  { "FPE_INTDIV", (unsigned long) FPE_INTDIV },
+#endif  // FPE_INTDIV
+#ifdef FPE_INTOVF
+  { "FPE_INTOVF", (unsigned long) FPE_INTOVF },
+#endif  // FPE_INTOVF
+#ifdef FP_XSTATE_MAGIC1
+  { "FP_XSTATE_MAGIC1", (unsigned long) FP_XSTATE_MAGIC1 },
+#endif  // FP_XSTATE_MAGIC1
+#ifdef FP_XSTATE_MAGIC2
+  { "FP_XSTATE_MAGIC2", (unsigned long) FP_XSTATE_MAGIC2 },
+#endif  // FP_XSTATE_MAGIC2
+#ifdef FP_XSTATE_MAGIC2_SIZE
+  { "FP_XSTATE_MAGIC2_SIZE", (unsigned long) FP_XSTATE_MAGIC2_SIZE },
+#endif  // FP_XSTATE_MAGIC2_SIZE
+#ifdef F_RDLCK
+  { "F_RDLCK", (unsigned long) F_RDLCK },
+#endif  // F_RDLCK
+#ifdef F_SETFD
+  { "F_SETFD", (unsigned long) F_SETFD },
+#endif  // F_SETFD
+#ifdef F_SETFL
+  { "F_SETFL", (unsigned long) F_SETFL },
+#endif  // F_SETFL
+#ifdef F_SETLK
+  { "F_SETLK", (unsigned long) F_SETLK },
+#endif  // F_SETLK
+#ifdef F_SETLK64
+  { "F_SETLK64", (unsigned long) F_SETLK64 },
+#endif  // F_SETLK64
+#ifdef F_SETLKW64
+  { "F_SETLKW64", (unsigned long) F_SETLKW64 },
+#endif  // F_SETLKW64
+#ifdef F_SETLKW
+  { "F_SETLKW", (unsigned long) F_SETLKW },
+#endif  // F_SETLKW
+#ifdef F_SHLCK
+  { "F_SHLCK", (unsigned long) F_SHLCK },
+#endif  // F_SHLCK
+#ifdef F_TEST
+  { "F_TEST", (unsigned long) F_TEST },
+#endif  // F_TEST
+#ifdef F_TLOCK
+  { "F_TLOCK", (unsigned long) F_TLOCK },
+#endif  // F_TLOCK
+#ifdef F_ULOCK
+  { "F_ULOCK", (unsigned long) F_ULOCK },
+#endif  // F_ULOCK
+#ifdef F_UNLCK
+  { "F_UNLCK", (unsigned long) F_UNLCK },
+#endif  // F_UNLCK
+#ifdef F_WRLCK
+  { "F_WRLCK", (unsigned long) F_WRLCK },
+#endif  // F_WRLCK
+#ifdef ILL_BADSTK
+  { "ILL_BADSTK", (unsigned long) ILL_BADSTK },
+#endif  // ILL_BADSTK
+#ifdef ILL_COPROC
+  { "ILL_COPROC", (unsigned long) ILL_COPROC },
+#endif  // ILL_COPROC
+#ifdef ILL_ILLADR
+  { "ILL_ILLADR", (unsigned long) ILL_ILLADR },
+#endif  // ILL_ILLADR
+#ifdef ILL_ILLOPC
+  { "ILL_ILLOPC", (unsigned long) ILL_ILLOPC },
+#endif  // ILL_ILLOPC
+#ifdef ILL_ILLOPN
+  { "ILL_ILLOPN", (unsigned long) ILL_ILLOPN },
+#endif  // ILL_ILLOPN
+#ifdef ILL_ILLTRP
+  { "ILL_ILLTRP", (unsigned long) ILL_ILLTRP },
+#endif  // ILL_ILLTRP
+#ifdef ILL_PRVOPC
+  { "ILL_PRVOPC", (unsigned long) ILL_PRVOPC },
+#endif  // ILL_PRVOPC
+#ifdef ILL_PRVREG
+  { "ILL_PRVREG", (unsigned long) ILL_PRVREG },
+#endif  // ILL_PRVREG
+#ifdef LOCK_EX
+  { "LOCK_EX", (unsigned long) LOCK_EX },
+#endif  // LOCK_EX
+#ifdef LOCK_NB
+  { "LOCK_NB", (unsigned long) LOCK_NB },
+#endif  // LOCK_NB
+#ifdef LOCK_SH
+  { "LOCK_SH", (unsigned long) LOCK_SH },
+#endif  // LOCK_SH
+#ifdef LOCK_UN
+  { "LOCK_UN", (unsigned long) LOCK_UN },
+#endif  // LOCK_UN
+#ifdef MINSIGSTKSZ
+  { "MINSIGSTKSZ", (unsigned long) MINSIGSTKSZ },
+#endif  // MINSIGSTKSZ
+#ifdef NGREG
+  { "NGREG", (unsigned long) NGREG },
+#endif  // NGREG
+#ifdef O_ACCMODE
+  { "O_ACCMODE", (unsigned long) O_ACCMODE },
+#endif  // O_ACCMODE
+#ifdef O_APPEND
+  { "O_APPEND", (unsigned long) O_APPEND },
+#endif  // O_APPEND
+#ifdef O_ASYNC
+  { "O_ASYNC", (unsigned long) O_ASYNC },
+#endif  // O_ASYNC
+#ifdef O_CREAT
+  { "O_CREAT", (unsigned long) O_CREAT },
+#endif  // O_CREAT
+#ifdef O_EXCL
+  { "O_EXCL", (unsigned long) O_EXCL },
+#endif  // O_EXCL
+#ifdef O_FSYNC
+  { "O_FSYNC", (unsigned long) O_FSYNC },
+#endif  // O_FSYNC
+#ifdef O_NDELAY
+  { "O_NDELAY", (unsigned long) O_NDELAY },
+#endif  // O_NDELAY
+#ifdef O_NOCTTY
+  { "O_NOCTTY", (unsigned long) O_NOCTTY },
+#endif  // O_NOCTTY
+#ifdef O_NONBLOCK
+  { "O_NONBLOCK", (unsigned long) O_NONBLOCK },
+#endif  // O_NONBLOCK
+#ifdef O_RDONLY
+  { "O_RDONLY", (unsigned long) O_RDONLY },
+#endif  // O_RDONLY
+#ifdef O_RDWR
+  { "O_RDWR", (unsigned long) O_RDWR },
+#endif  // O_RDWR
+#ifdef O_RSYNC
+  { "O_RSYNC", (unsigned long) O_RSYNC },
+#endif  // O_RSYNC
+#ifdef O_SYNC
+  { "O_SYNC", (unsigned long) O_SYNC },
+#endif  // O_SYNC
+#ifdef O_TRUNC
+  { "O_TRUNC", (unsigned long) O_TRUNC },
+#endif  // O_TRUNC
+#ifdef O_WRONLY
+  { "O_WRONLY", (unsigned long) O_WRONLY },
+#endif  // O_WRONLY
+#ifdef POLL_ERR
+  { "POLL_ERR", (unsigned long) POLL_ERR },
+#endif  // POLL_ERR
+#ifdef POLL_HUP
+  { "POLL_HUP", (unsigned long) POLL_HUP },
+#endif  // POLL_HUP
+#ifdef POLL_IN
+  { "POLL_IN", (unsigned long) POLL_IN },
+#endif  // POLL_IN
+#ifdef POLL_MSG
+  { "POLL_MSG", (unsigned long) POLL_MSG },
+#endif  // POLL_MSG
+#ifdef POLL_OUT
+  { "POLL_OUT", (unsigned long) POLL_OUT },
+#endif  // POLL_OUT
+#ifdef POLL_PRI
+  { "POLL_PRI", (unsigned long) POLL_PRI },
+#endif  // POLL_PRI
+#ifdef POSIX_FADV_NORMAL
+  { "POSIX_FADV_NORMAL", (unsigned long) POSIX_FADV_NORMAL },
+#endif  // POSIX_FADV_NORMAL
+#ifdef POSIX_FADV_RANDOM
+  { "POSIX_FADV_RANDOM", (unsigned long) POSIX_FADV_RANDOM },
+#endif  // POSIX_FADV_RANDOM
+#ifdef POSIX_FADV_SEQUENTIAL
+  { "POSIX_FADV_SEQUENTIAL", (unsigned long) POSIX_FADV_SEQUENTIAL },
+#endif  // POSIX_FADV_SEQUENTIAL
+#ifdef POSIX_FADV_WILLNEED
+  { "POSIX_FADV_WILLNEED", (unsigned long) POSIX_FADV_WILLNEED },
+#endif  // POSIX_FADV_WILLNEED
+#ifdef PR_CAPBSET_DROP
+  { "PR_CAPBSET_DROP", (unsigned long) PR_CAPBSET_DROP },
+#endif  // PR_CAPBSET_DROP
+#ifdef PR_CAPBSET_READ
+  { "PR_CAPBSET_READ", (unsigned long) PR_CAPBSET_READ },
+#endif  // PR_CAPBSET_READ
+#ifdef PR_ENDIAN_BIG
+  { "PR_ENDIAN_BIG", (unsigned long) PR_ENDIAN_BIG },
+#endif  // PR_ENDIAN_BIG
+#ifdef PR_ENDIAN_LITTLE
+  { "PR_ENDIAN_LITTLE", (unsigned long) PR_ENDIAN_LITTLE },
+#endif  // PR_ENDIAN_LITTLE
+#ifdef PR_ENDIAN_PPC_LITTLE
+  { "PR_ENDIAN_PPC_LITTLE", (unsigned long) PR_ENDIAN_PPC_LITTLE },
+#endif  // PR_ENDIAN_PPC_LITTLE
+#ifdef PR_FPEMU_NOPRINT
+  { "PR_FPEMU_NOPRINT", (unsigned long) PR_FPEMU_NOPRINT },
+#endif  // PR_FPEMU_NOPRINT
+#ifdef PR_FPEMU_SIGFPE
+  { "PR_FPEMU_SIGFPE", (unsigned long) PR_FPEMU_SIGFPE },
+#endif  // PR_FPEMU_SIGFPE
+#ifdef PR_FP_EXC_ASYNC
+  { "PR_FP_EXC_ASYNC", (unsigned long) PR_FP_EXC_ASYNC },
+#endif  // PR_FP_EXC_ASYNC
+#ifdef PR_FP_EXC_DISABLED
+  { "PR_FP_EXC_DISABLED", (unsigned long) PR_FP_EXC_DISABLED },
+#endif  // PR_FP_EXC_DISABLED
+#ifdef PR_FP_EXC_DIV
+  { "PR_FP_EXC_DIV", (unsigned long) PR_FP_EXC_DIV },
+#endif  // PR_FP_EXC_DIV
+#ifdef PR_FP_EXC_INV
+  { "PR_FP_EXC_INV", (unsigned long) PR_FP_EXC_INV },
+#endif  // PR_FP_EXC_INV
+#ifdef PR_FP_EXC_NONRECOV
+  { "PR_FP_EXC_NONRECOV", (unsigned long) PR_FP_EXC_NONRECOV },
+#endif  // PR_FP_EXC_NONRECOV
+#ifdef PR_FP_EXC_OVF
+  { "PR_FP_EXC_OVF", (unsigned long) PR_FP_EXC_OVF },
+#endif  // PR_FP_EXC_OVF
+#ifdef PR_FP_EXC_PRECISE
+  { "PR_FP_EXC_PRECISE", (unsigned long) PR_FP_EXC_PRECISE },
+#endif  // PR_FP_EXC_PRECISE
+#ifdef PR_FP_EXC_RES
+  { "PR_FP_EXC_RES", (unsigned long) PR_FP_EXC_RES },
+#endif  // PR_FP_EXC_RES
+#ifdef PR_FP_EXC_SW_ENABLE
+  { "PR_FP_EXC_SW_ENABLE", (unsigned long) PR_FP_EXC_SW_ENABLE },
+#endif  // PR_FP_EXC_SW_ENABLE
+#ifdef PR_FP_EXC_UND
+  { "PR_FP_EXC_UND", (unsigned long) PR_FP_EXC_UND },
+#endif  // PR_FP_EXC_UND
+#ifdef PR_GET_CHILD_SUBREAPER
+  { "PR_GET_CHILD_SUBREAPER", (unsigned long) PR_GET_CHILD_SUBREAPER },
+#endif  // PR_GET_CHILD_SUBREAPER
+#ifdef PR_GET_DUMPABLE
+  { "PR_GET_DUMPABLE", (unsigned long) PR_GET_DUMPABLE },
+#endif  // PR_GET_DUMPABLE
+#ifdef PR_GET_ENDIAN
+  { "PR_GET_ENDIAN", (unsigned long) PR_GET_ENDIAN },
+#endif  // PR_GET_ENDIAN
+#ifdef PR_GET_FPEMU
+  { "PR_GET_FPEMU", (unsigned long) PR_GET_FPEMU },
+#endif  // PR_GET_FPEMU
+#ifdef PR_GET_FPEXC
+  { "PR_GET_FPEXC", (unsigned long) PR_GET_FPEXC },
+#endif  // PR_GET_FPEXC
+#ifdef PR_GET_KEEPCAPS
+  { "PR_GET_KEEPCAPS", (unsigned long) PR_GET_KEEPCAPS },
+#endif  // PR_GET_KEEPCAPS
+#ifdef PR_GET_NAME
+  { "PR_GET_NAME", (unsigned long) PR_GET_NAME },
+#endif  // PR_GET_NAME
+#ifdef PR_GET_NO_NEW_PRIVS
+  { "PR_GET_NO_NEW_PRIVS", (unsigned long) PR_GET_NO_NEW_PRIVS },
+#endif  // PR_GET_NO_NEW_PRIVS
+#ifdef PR_GET_PDEATHSIG
+  { "PR_GET_PDEATHSIG", (unsigned long) PR_GET_PDEATHSIG },
+#endif  // PR_GET_PDEATHSIG
+#ifdef PR_GET_SECCOMP
+  { "PR_GET_SECCOMP", (unsigned long) PR_GET_SECCOMP },
+#endif  // PR_GET_SECCOMP
+#ifdef PR_GET_SECUREBITS
+  { "PR_GET_SECUREBITS", (unsigned long) PR_GET_SECUREBITS },
+#endif  // PR_GET_SECUREBITS
+#ifdef PR_GET_TID_ADDRESS
+  { "PR_GET_TID_ADDRESS", (unsigned long) PR_GET_TID_ADDRESS },
+#endif  // PR_GET_TID_ADDRESS
+#ifdef PR_GET_TIMERSLACK
+  { "PR_GET_TIMERSLACK", (unsigned long) PR_GET_TIMERSLACK },
+#endif  // PR_GET_TIMERSLACK
+#ifdef PR_GET_TIMING
+  { "PR_GET_TIMING", (unsigned long) PR_GET_TIMING },
+#endif  // PR_GET_TIMING
+#ifdef PR_GET_TSC
+  { "PR_GET_TSC", (unsigned long) PR_GET_TSC },
+#endif  // PR_GET_TSC
+#ifdef PR_GET_UNALIGN
+  { "PR_GET_UNALIGN", (unsigned long) PR_GET_UNALIGN },
+#endif  // PR_GET_UNALIGN
+#ifdef PR_MCE_KILL
+  { "PR_MCE_KILL", (unsigned long) PR_MCE_KILL },
+#endif  // PR_MCE_KILL
+#ifdef PR_MCE_KILL_CLEAR
+  { "PR_MCE_KILL_CLEAR", (unsigned long) PR_MCE_KILL_CLEAR },
+#endif  // PR_MCE_KILL_CLEAR
+#ifdef PR_MCE_KILL_DEFAULT
+  { "PR_MCE_KILL_DEFAULT", (unsigned long) PR_MCE_KILL_DEFAULT },
+#endif  // PR_MCE_KILL_DEFAULT
+#ifdef PR_MCE_KILL_EARLY
+  { "PR_MCE_KILL_EARLY", (unsigned long) PR_MCE_KILL_EARLY },
+#endif  // PR_MCE_KILL_EARLY
+#ifdef PR_MCE_KILL_GET
+  { "PR_MCE_KILL_GET", (unsigned long) PR_MCE_KILL_GET },
+#endif  // PR_MCE_KILL_GET
+#ifdef PR_MCE_KILL_LATE
+  { "PR_MCE_KILL_LATE", (unsigned long) PR_MCE_KILL_LATE },
+#endif  // PR_MCE_KILL_LATE
+#ifdef PR_MCE_KILL_SET
+  { "PR_MCE_KILL_SET", (unsigned long) PR_MCE_KILL_SET },
+#endif  // PR_MCE_KILL_SET
+#ifdef PR_SET_CHILD_SUBREAPER
+  { "PR_SET_CHILD_SUBREAPER", (unsigned long) PR_SET_CHILD_SUBREAPER },
+#endif  // PR_SET_CHILD_SUBREAPER
+#ifdef PR_SET_DUMPABLE
+  { "PR_SET_DUMPABLE", (unsigned long) PR_SET_DUMPABLE },
+#endif  // PR_SET_DUMPABLE
+#ifdef PR_SET_ENDIAN
+  { "PR_SET_ENDIAN", (unsigned long) PR_SET_ENDIAN },
+#endif  // PR_SET_ENDIAN
+#ifdef PR_SET_FPEMU
+  { "PR_SET_FPEMU", (unsigned long) PR_SET_FPEMU },
+#endif  // PR_SET_FPEMU
+#ifdef PR_SET_FPEXC
+  { "PR_SET_FPEXC", (unsigned long) PR_SET_FPEXC },
+#endif  // PR_SET_FPEXC
+#ifdef PR_SET_KEEPCAPS
+  { "PR_SET_KEEPCAPS", (unsigned long) PR_SET_KEEPCAPS },
+#endif  // PR_SET_KEEPCAPS
+#ifdef PR_SET_MM
+  { "PR_SET_MM", (unsigned long) PR_SET_MM },
+#endif  // PR_SET_MM
+#ifdef PR_SET_MM_ARG_END
+  { "PR_SET_MM_ARG_END", (unsigned long) PR_SET_MM_ARG_END },
+#endif  // PR_SET_MM_ARG_END
+#ifdef PR_SET_MM_ARG_START
+  { "PR_SET_MM_ARG_START", (unsigned long) PR_SET_MM_ARG_START },
+#endif  // PR_SET_MM_ARG_START
+#ifdef PR_SET_MM_AUXV
+  { "PR_SET_MM_AUXV", (unsigned long) PR_SET_MM_AUXV },
+#endif  // PR_SET_MM_AUXV
+#ifdef PR_SET_MM_BRK
+  { "PR_SET_MM_BRK", (unsigned long) PR_SET_MM_BRK },
+#endif  // PR_SET_MM_BRK
+#ifdef PR_SET_MM_END_CODE
+  { "PR_SET_MM_END_CODE", (unsigned long) PR_SET_MM_END_CODE },
+#endif  // PR_SET_MM_END_CODE
+#ifdef PR_SET_MM_END_DATA
+  { "PR_SET_MM_END_DATA", (unsigned long) PR_SET_MM_END_DATA },
+#endif  // PR_SET_MM_END_DATA
+#ifdef PR_SET_MM_ENV_END
+  { "PR_SET_MM_ENV_END", (unsigned long) PR_SET_MM_ENV_END },
+#endif  // PR_SET_MM_ENV_END
+#ifdef PR_SET_MM_ENV_START
+  { "PR_SET_MM_ENV_START", (unsigned long) PR_SET_MM_ENV_START },
+#endif  // PR_SET_MM_ENV_START
+#ifdef PR_SET_MM_EXE_FILE
+  { "PR_SET_MM_EXE_FILE", (unsigned long) PR_SET_MM_EXE_FILE },
+#endif  // PR_SET_MM_EXE_FILE
+#ifdef PR_SET_MM_START_BRK
+  { "PR_SET_MM_START_BRK", (unsigned long) PR_SET_MM_START_BRK },
+#endif  // PR_SET_MM_START_BRK
+#ifdef PR_SET_MM_START_CODE
+  { "PR_SET_MM_START_CODE", (unsigned long) PR_SET_MM_START_CODE },
+#endif  // PR_SET_MM_START_CODE
+#ifdef PR_SET_MM_START_DATA
+  { "PR_SET_MM_START_DATA", (unsigned long) PR_SET_MM_START_DATA },
+#endif  // PR_SET_MM_START_DATA
+#ifdef PR_SET_MM_START_STACK
+  { "PR_SET_MM_START_STACK", (unsigned long) PR_SET_MM_START_STACK },
+#endif  // PR_SET_MM_START_STACK
+#ifdef PR_SET_NAME
+  { "PR_SET_NAME", (unsigned long) PR_SET_NAME },
+#endif  // PR_SET_NAME
+#ifdef PR_SET_NO_NEW_PRIVS
+  { "PR_SET_NO_NEW_PRIVS", (unsigned long) PR_SET_NO_NEW_PRIVS },
+#endif  // PR_SET_NO_NEW_PRIVS
+#ifdef PR_SET_PDEATHSIG
+  { "PR_SET_PDEATHSIG", (unsigned long) PR_SET_PDEATHSIG },
+#endif  // PR_SET_PDEATHSIG
+#ifdef PR_SET_PTRACER
+  { "PR_SET_PTRACER", (unsigned long) PR_SET_PTRACER },
+#endif  // PR_SET_PTRACER
+#ifdef PR_SET_SECCOMP
+  { "PR_SET_SECCOMP", (unsigned long) PR_SET_SECCOMP },
+#endif  // PR_SET_SECCOMP
+#ifdef PR_SET_SECUREBITS
+  { "PR_SET_SECUREBITS", (unsigned long) PR_SET_SECUREBITS },
+#endif  // PR_SET_SECUREBITS
+#ifdef PR_SET_TIMERSLACK
+  { "PR_SET_TIMERSLACK", (unsigned long) PR_SET_TIMERSLACK },
+#endif  // PR_SET_TIMERSLACK
+#ifdef PR_SET_TIMING
+  { "PR_SET_TIMING", (unsigned long) PR_SET_TIMING },
+#endif  // PR_SET_TIMING
+#ifdef PR_SET_TSC
+  { "PR_SET_TSC", (unsigned long) PR_SET_TSC },
+#endif  // PR_SET_TSC
+#ifdef PR_SET_UNALIGN
+  { "PR_SET_UNALIGN", (unsigned long) PR_SET_UNALIGN },
+#endif  // PR_SET_UNALIGN
+#ifdef PR_TASK_PERF_EVENTS_DISABLE
+  { "PR_TASK_PERF_EVENTS_DISABLE", (unsigned long) PR_TASK_PERF_EVENTS_DISABLE },
+#endif  // PR_TASK_PERF_EVENTS_DISABLE
+#ifdef PR_TASK_PERF_EVENTS_ENABLE
+  { "PR_TASK_PERF_EVENTS_ENABLE", (unsigned long) PR_TASK_PERF_EVENTS_ENABLE },
+#endif  // PR_TASK_PERF_EVENTS_ENABLE
+#ifdef PR_TIMING_STATISTICAL
+  { "PR_TIMING_STATISTICAL", (unsigned long) PR_TIMING_STATISTICAL },
+#endif  // PR_TIMING_STATISTICAL
+#ifdef PR_TIMING_TIMESTAMP
+  { "PR_TIMING_TIMESTAMP", (unsigned long) PR_TIMING_TIMESTAMP },
+#endif  // PR_TIMING_TIMESTAMP
+#ifdef PR_TSC_ENABLE
+  { "PR_TSC_ENABLE", (unsigned long) PR_TSC_ENABLE },
+#endif  // PR_TSC_ENABLE
+#ifdef PR_TSC_SIGSEGV
+  { "PR_TSC_SIGSEGV", (unsigned long) PR_TSC_SIGSEGV },
+#endif  // PR_TSC_SIGSEGV
+#ifdef PR_UNALIGN_NOPRINT
+  { "PR_UNALIGN_NOPRINT", (unsigned long) PR_UNALIGN_NOPRINT },
+#endif  // PR_UNALIGN_NOPRINT
+#ifdef PR_UNALIGN_SIGBUS
+  { "PR_UNALIGN_SIGBUS", (unsigned long) PR_UNALIGN_SIGBUS },
+#endif  // PR_UNALIGN_SIGBUS
+#ifdef R_OK
+  { "R_OK", (unsigned long) R_OK },
+#endif  // R_OK
+#ifdef SA_INTERRUPT
+  { "SA_INTERRUPT", (unsigned long) SA_INTERRUPT },
+#endif  // SA_INTERRUPT
+#ifdef SA_NOCLDSTOP
+  { "SA_NOCLDSTOP", (unsigned long) SA_NOCLDSTOP },
+#endif  // SA_NOCLDSTOP
+#ifdef SA_NOCLDWAIT
+  { "SA_NOCLDWAIT", (unsigned long) SA_NOCLDWAIT },
+#endif  // SA_NOCLDWAIT
+#ifdef SA_NODEFER
+  { "SA_NODEFER", (unsigned long) SA_NODEFER },
+#endif  // SA_NODEFER
+#ifdef SA_NOMASK
+  { "SA_NOMASK", (unsigned long) SA_NOMASK },
+#endif  // SA_NOMASK
+#ifdef SA_ONESHOT
+  { "SA_ONESHOT", (unsigned long) SA_ONESHOT },
+#endif  // SA_ONESHOT
+#ifdef SA_ONSTACK
+  { "SA_ONSTACK", (unsigned long) SA_ONSTACK },
+#endif  // SA_ONSTACK
+#ifdef SA_RESETHAND
+  { "SA_RESETHAND", (unsigned long) SA_RESETHAND },
+#endif  // SA_RESETHAND
+#ifdef SA_RESTART
+  { "SA_RESTART", (unsigned long) SA_RESTART },
+#endif  // SA_RESTART
+#ifdef SA_SIGINFO
+  { "SA_SIGINFO", (unsigned long) SA_SIGINFO },
+#endif  // SA_SIGINFO
+#ifdef SA_STACK
+  { "SA_STACK", (unsigned long) SA_STACK },
+#endif  // SA_STACK
+#ifdef S_BLKSIZE
+  { "S_BLKSIZE", (unsigned long) S_BLKSIZE },
+#endif  // S_BLKSIZE
+#ifdef SCHED_BATCH
+  { "SCHED_BATCH", (unsigned long) SCHED_BATCH },
+#endif  // SCHED_BATCH
+#ifdef SCHED_FIFO
+  { "SCHED_FIFO", (unsigned long) SCHED_FIFO },
+#endif  // SCHED_FIFO
+#ifdef SCHED_IDLE
+  { "SCHED_IDLE", (unsigned long) SCHED_IDLE },
+#endif  // SCHED_IDLE
+#ifdef SCHED_NORMAL
+  { "SCHED_NORMAL", (unsigned long) SCHED_NORMAL },
+#endif  // SCHED_NORMAL
+#ifdef SCHED_RESET_ON_FORK
+  { "SCHED_RESET_ON_FORK", (unsigned long) SCHED_RESET_ON_FORK },
+#endif  // SCHED_RESET_ON_FORK
+#ifdef SCHED_RR
+  { "SCHED_RR", (unsigned long) SCHED_RR },
+#endif  // SCHED_RR
+#ifdef SEEK_CUR
+  { "SEEK_CUR", (unsigned long) SEEK_CUR },
+#endif  // SEEK_CUR
+#ifdef SEEK_END
+  { "SEEK_END", (unsigned long) SEEK_END },
+#endif  // SEEK_END
+#ifdef SEEK_SET
+  { "SEEK_SET", (unsigned long) SEEK_SET },
+#endif  // SEEK_SET
+#ifdef SEGV_ACCERR
+  { "SEGV_ACCERR", (unsigned long) SEGV_ACCERR },
+#endif  // SEGV_ACCERR
+#ifdef SEGV_MAPERR
+  { "SEGV_MAPERR", (unsigned long) SEGV_MAPERR },
+#endif  // SEGV_MAPERR
+#ifdef SI_ASYNCIO
+  { "SI_ASYNCIO", (unsigned long) SI_ASYNCIO },
+#endif  // SI_ASYNCIO
+#ifdef SI_ASYNCNL
+  { "SI_ASYNCNL", (unsigned long) SI_ASYNCNL },
+#endif  // SI_ASYNCNL
+#ifdef S_IEXEC
+  { "S_IEXEC", (unsigned long) S_IEXEC },
+#endif  // S_IEXEC
+#ifdef SIGABRT
+  { "SIGABRT", (unsigned long) SIGABRT },
+#endif  // SIGABRT
+#ifdef SIGALRM
+  { "SIGALRM", (unsigned long) SIGALRM },
+#endif  // SIGALRM
+#ifdef SIGBUS
+  { "SIGBUS", (unsigned long) SIGBUS },
+#endif  // SIGBUS
+#ifdef SIGCHLD
+  { "SIGCHLD", (unsigned long) SIGCHLD },
+#endif  // SIGCHLD
+#ifdef SIGCLD
+  { "SIGCLD", (unsigned long) SIGCLD },
+#endif  // SIGCLD
+#ifdef SIGCONT
+  { "SIGCONT", (unsigned long) SIGCONT },
+#endif  // SIGCONT
+#ifdef SIGEV_NONE
+  { "SIGEV_NONE", (unsigned long) SIGEV_NONE },
+#endif  // SIGEV_NONE
+#ifdef SIGEV_SIGNAL
+  { "SIGEV_SIGNAL", (unsigned long) SIGEV_SIGNAL },
+#endif  // SIGEV_SIGNAL
+#ifdef SIGEV_THREAD_ID
+  { "SIGEV_THREAD_ID", (unsigned long) SIGEV_THREAD_ID },
+#endif  // SIGEV_THREAD_ID
+#ifdef SIGEV_THREAD
+  { "SIGEV_THREAD", (unsigned long) SIGEV_THREAD },
+#endif  // SIGEV_THREAD
+#ifdef SIGFPE
+  { "SIGFPE", (unsigned long) SIGFPE },
+#endif  // SIGFPE
+#ifdef SIGHUP
+  { "SIGHUP", (unsigned long) SIGHUP },
+#endif  // SIGHUP
+#ifdef SIGILL
+  { "SIGILL", (unsigned long) SIGILL },
+#endif  // SIGILL
+#ifdef SIGINT
+  { "SIGINT", (unsigned long) SIGINT },
+#endif  // SIGINT
+#ifdef SIGIO
+  { "SIGIO", (unsigned long) SIGIO },
+#endif  // SIGIO
+#ifdef SIGIOT
+  { "SIGIOT", (unsigned long) SIGIOT },
+#endif  // SIGIOT
+#ifdef SIGKILL
+  { "SIGKILL", (unsigned long) SIGKILL },
+#endif  // SIGKILL
+#ifdef SIGPIPE
+  { "SIGPIPE", (unsigned long) SIGPIPE },
+#endif  // SIGPIPE
+#ifdef SIGPOLL
+  { "SIGPOLL", (unsigned long) SIGPOLL },
+#endif  // SIGPOLL
+#ifdef SIGPROF
+  { "SIGPROF", (unsigned long) SIGPROF },
+#endif  // SIGPROF
+#ifdef SIGPWR
+  { "SIGPWR", (unsigned long) SIGPWR },
+#endif  // SIGPWR
+#ifdef SIGQUIT
+  { "SIGQUIT", (unsigned long) SIGQUIT },
+#endif  // SIGQUIT
+#ifdef SIGSEGV
+  { "SIGSEGV", (unsigned long) SIGSEGV },
+#endif  // SIGSEGV
+#ifdef SIGSTKFLT
+  { "SIGSTKFLT", (unsigned long) SIGSTKFLT },
+#endif  // SIGSTKFLT
+#ifdef SIGSTKSZ
+  { "SIGSTKSZ", (unsigned long) SIGSTKSZ },
+#endif  // SIGSTKSZ
+#ifdef SIGSTOP
+  { "SIGSTOP", (unsigned long) SIGSTOP },
+#endif  // SIGSTOP
+#ifdef SIGSYS
+  { "SIGSYS", (unsigned long) SIGSYS },
+#endif  // SIGSYS
+#ifdef SIGTERM
+  { "SIGTERM", (unsigned long) SIGTERM },
+#endif  // SIGTERM
+#ifdef SIGTRAP
+  { "SIGTRAP", (unsigned long) SIGTRAP },
+#endif  // SIGTRAP
+#ifdef SIGTSTP
+  { "SIGTSTP", (unsigned long) SIGTSTP },
+#endif  // SIGTSTP
+#ifdef SIGTTIN
+  { "SIGTTIN", (unsigned long) SIGTTIN },
+#endif  // SIGTTIN
+#ifdef SIGTTOU
+  { "SIGTTOU", (unsigned long) SIGTTOU },
+#endif  // SIGTTOU
+#ifdef SIGUNUSED
+  { "SIGUNUSED", (unsigned long) SIGUNUSED },
+#endif  // SIGUNUSED
+#ifdef SIGURG
+  { "SIGURG", (unsigned long) SIGURG },
+#endif  // SIGURG
+#ifdef SIGUSR1
+  { "SIGUSR1", (unsigned long) SIGUSR1 },
+#endif  // SIGUSR1
+#ifdef SIGUSR2
+  { "SIGUSR2", (unsigned long) SIGUSR2 },
+#endif  // SIGUSR2
+#ifdef SIGVTALRM
+  { "SIGVTALRM", (unsigned long) SIGVTALRM },
+#endif  // SIGVTALRM
+#ifdef SIGWINCH
+  { "SIGWINCH", (unsigned long) SIGWINCH },
+#endif  // SIGWINCH
+#ifdef SIGXCPU
+  { "SIGXCPU", (unsigned long) SIGXCPU },
+#endif  // SIGXCPU
+#ifdef SIGXFSZ
+  { "SIGXFSZ", (unsigned long) SIGXFSZ },
+#endif  // SIGXFSZ
+#ifdef SI_KERNEL
+  { "SI_KERNEL", (unsigned long) SI_KERNEL },
+#endif  // SI_KERNEL
+#ifdef SI_MESGQ
+  { "SI_MESGQ", (unsigned long) SI_MESGQ },
+#endif  // SI_MESGQ
+#ifdef SI_QUEUE
+  { "SI_QUEUE", (unsigned long) SI_QUEUE },
+#endif  // SI_QUEUE
+#ifdef S_IREAD
+  { "S_IREAD", (unsigned long) S_IREAD },
+#endif  // S_IREAD
+#ifdef SI_SIGIO
+  { "SI_SIGIO", (unsigned long) SI_SIGIO },
+#endif  // SI_SIGIO
+#ifdef SI_TIMER
+  { "SI_TIMER", (unsigned long) SI_TIMER },
+#endif  // SI_TIMER
+#ifdef SI_TKILL
+  { "SI_TKILL", (unsigned long) SI_TKILL },
+#endif  // SI_TKILL
+#ifdef SI_USER
+  { "SI_USER", (unsigned long) SI_USER },
+#endif  // SI_USER
+#ifdef S_IWRITE
+  { "S_IWRITE", (unsigned long) S_IWRITE },
+#endif  // S_IWRITE
+#ifdef SS_DISABLE
+  { "SS_DISABLE", (unsigned long) SS_DISABLE },
+#endif  // SS_DISABLE
+#ifdef SS_ONSTACK
+  { "SS_ONSTACK", (unsigned long) SS_ONSTACK },
+#endif  // SS_ONSTACK
+#ifdef TRAP_BRKPT
+  { "TRAP_BRKPT", (unsigned long) TRAP_BRKPT },
+#endif  // TRAP_BRKPT
+#ifdef TRAP_TRACE
+  { "TRAP_TRACE", (unsigned long) TRAP_TRACE },
+#endif  // TRAP_TRACE
+#ifdef W_OK
+  { "W_OK", (unsigned long) W_OK },
+#endif  // W_OK
+#ifdef X_OK
+  { "X_OK", (unsigned long) X_OK },
+#endif  // X_OK
+  { NULL, 0 },
+};
diff --git a/minijail/linux-x86/libsyscalls.gen.c b/minijail/linux-x86/libsyscalls.gen.c
new file mode 100644
index 0000000..db00274
--- /dev/null
+++ b/minijail/linux-x86/libsyscalls.gen.c
@@ -0,0 +1,961 @@
+/* GENERATED BY MAKEFILE */
+#include <stddef.h>
+#include <asm/unistd.h>
+#include "libsyscalls.h"
+const struct syscall_entry syscall_table[] = {
+#ifdef __NR_read
+{ "read", __NR_read },
+#endif
+#ifdef __NR_write
+{ "write", __NR_write },
+#endif
+#ifdef __NR_open
+{ "open", __NR_open },
+#endif
+#ifdef __NR_close
+{ "close", __NR_close },
+#endif
+#ifdef __NR_stat
+{ "stat", __NR_stat },
+#endif
+#ifdef __NR_fstat
+{ "fstat", __NR_fstat },
+#endif
+#ifdef __NR_lstat
+{ "lstat", __NR_lstat },
+#endif
+#ifdef __NR_poll
+{ "poll", __NR_poll },
+#endif
+#ifdef __NR_lseek
+{ "lseek", __NR_lseek },
+#endif
+#ifdef __NR_mmap
+{ "mmap", __NR_mmap },
+#endif
+#ifdef __NR_mprotect
+{ "mprotect", __NR_mprotect },
+#endif
+#ifdef __NR_munmap
+{ "munmap", __NR_munmap },
+#endif
+#ifdef __NR_brk
+{ "brk", __NR_brk },
+#endif
+#ifdef __NR_rt_sigaction
+{ "rt_sigaction", __NR_rt_sigaction },
+#endif
+#ifdef __NR_rt_sigprocmask
+{ "rt_sigprocmask", __NR_rt_sigprocmask },
+#endif
+#ifdef __NR_rt_sigreturn
+{ "rt_sigreturn", __NR_rt_sigreturn },
+#endif
+#ifdef __NR_ioctl
+{ "ioctl", __NR_ioctl },
+#endif
+#ifdef __NR_pread64
+{ "pread64", __NR_pread64 },
+#endif
+#ifdef __NR_pwrite64
+{ "pwrite64", __NR_pwrite64 },
+#endif
+#ifdef __NR_readv
+{ "readv", __NR_readv },
+#endif
+#ifdef __NR_writev
+{ "writev", __NR_writev },
+#endif
+#ifdef __NR_access
+{ "access", __NR_access },
+#endif
+#ifdef __NR_pipe
+{ "pipe", __NR_pipe },
+#endif
+#ifdef __NR_select
+{ "select", __NR_select },
+#endif
+#ifdef __NR_sched_yield
+{ "sched_yield", __NR_sched_yield },
+#endif
+#ifdef __NR_mremap
+{ "mremap", __NR_mremap },
+#endif
+#ifdef __NR_msync
+{ "msync", __NR_msync },
+#endif
+#ifdef __NR_mincore
+{ "mincore", __NR_mincore },
+#endif
+#ifdef __NR_madvise
+{ "madvise", __NR_madvise },
+#endif
+#ifdef __NR_shmget
+{ "shmget", __NR_shmget },
+#endif
+#ifdef __NR_shmat
+{ "shmat", __NR_shmat },
+#endif
+#ifdef __NR_shmctl
+{ "shmctl", __NR_shmctl },
+#endif
+#ifdef __NR_dup
+{ "dup", __NR_dup },
+#endif
+#ifdef __NR_dup2
+{ "dup2", __NR_dup2 },
+#endif
+#ifdef __NR_pause
+{ "pause", __NR_pause },
+#endif
+#ifdef __NR_nanosleep
+{ "nanosleep", __NR_nanosleep },
+#endif
+#ifdef __NR_getitimer
+{ "getitimer", __NR_getitimer },
+#endif
+#ifdef __NR_alarm
+{ "alarm", __NR_alarm },
+#endif
+#ifdef __NR_setitimer
+{ "setitimer", __NR_setitimer },
+#endif
+#ifdef __NR_getpid
+{ "getpid", __NR_getpid },
+#endif
+#ifdef __NR_sendfile
+{ "sendfile", __NR_sendfile },
+#endif
+#ifdef __NR_socket
+{ "socket", __NR_socket },
+#endif
+#ifdef __NR_connect
+{ "connect", __NR_connect },
+#endif
+#ifdef __NR_accept
+{ "accept", __NR_accept },
+#endif
+#ifdef __NR_sendto
+{ "sendto", __NR_sendto },
+#endif
+#ifdef __NR_recvfrom
+{ "recvfrom", __NR_recvfrom },
+#endif
+#ifdef __NR_sendmsg
+{ "sendmsg", __NR_sendmsg },
+#endif
+#ifdef __NR_recvmsg
+{ "recvmsg", __NR_recvmsg },
+#endif
+#ifdef __NR_shutdown
+{ "shutdown", __NR_shutdown },
+#endif
+#ifdef __NR_bind
+{ "bind", __NR_bind },
+#endif
+#ifdef __NR_listen
+{ "listen", __NR_listen },
+#endif
+#ifdef __NR_getsockname
+{ "getsockname", __NR_getsockname },
+#endif
+#ifdef __NR_getpeername
+{ "getpeername", __NR_getpeername },
+#endif
+#ifdef __NR_socketpair
+{ "socketpair", __NR_socketpair },
+#endif
+#ifdef __NR_setsockopt
+{ "setsockopt", __NR_setsockopt },
+#endif
+#ifdef __NR_getsockopt
+{ "getsockopt", __NR_getsockopt },
+#endif
+#ifdef __NR_clone
+{ "clone", __NR_clone },
+#endif
+#ifdef __NR_fork
+{ "fork", __NR_fork },
+#endif
+#ifdef __NR_vfork
+{ "vfork", __NR_vfork },
+#endif
+#ifdef __NR_execve
+{ "execve", __NR_execve },
+#endif
+#ifdef __NR_exit
+{ "exit", __NR_exit },
+#endif
+#ifdef __NR_wait4
+{ "wait4", __NR_wait4 },
+#endif
+#ifdef __NR_kill
+{ "kill", __NR_kill },
+#endif
+#ifdef __NR_uname
+{ "uname", __NR_uname },
+#endif
+#ifdef __NR_semget
+{ "semget", __NR_semget },
+#endif
+#ifdef __NR_semop
+{ "semop", __NR_semop },
+#endif
+#ifdef __NR_semctl
+{ "semctl", __NR_semctl },
+#endif
+#ifdef __NR_shmdt
+{ "shmdt", __NR_shmdt },
+#endif
+#ifdef __NR_msgget
+{ "msgget", __NR_msgget },
+#endif
+#ifdef __NR_msgsnd
+{ "msgsnd", __NR_msgsnd },
+#endif
+#ifdef __NR_msgrcv
+{ "msgrcv", __NR_msgrcv },
+#endif
+#ifdef __NR_msgctl
+{ "msgctl", __NR_msgctl },
+#endif
+#ifdef __NR_fcntl
+{ "fcntl", __NR_fcntl },
+#endif
+#ifdef __NR_flock
+{ "flock", __NR_flock },
+#endif
+#ifdef __NR_fsync
+{ "fsync", __NR_fsync },
+#endif
+#ifdef __NR_fdatasync
+{ "fdatasync", __NR_fdatasync },
+#endif
+#ifdef __NR_truncate
+{ "truncate", __NR_truncate },
+#endif
+#ifdef __NR_ftruncate
+{ "ftruncate", __NR_ftruncate },
+#endif
+#ifdef __NR_getdents
+{ "getdents", __NR_getdents },
+#endif
+#ifdef __NR_getcwd
+{ "getcwd", __NR_getcwd },
+#endif
+#ifdef __NR_chdir
+{ "chdir", __NR_chdir },
+#endif
+#ifdef __NR_fchdir
+{ "fchdir", __NR_fchdir },
+#endif
+#ifdef __NR_rename
+{ "rename", __NR_rename },
+#endif
+#ifdef __NR_mkdir
+{ "mkdir", __NR_mkdir },
+#endif
+#ifdef __NR_rmdir
+{ "rmdir", __NR_rmdir },
+#endif
+#ifdef __NR_creat
+{ "creat", __NR_creat },
+#endif
+#ifdef __NR_link
+{ "link", __NR_link },
+#endif
+#ifdef __NR_unlink
+{ "unlink", __NR_unlink },
+#endif
+#ifdef __NR_symlink
+{ "symlink", __NR_symlink },
+#endif
+#ifdef __NR_readlink
+{ "readlink", __NR_readlink },
+#endif
+#ifdef __NR_chmod
+{ "chmod", __NR_chmod },
+#endif
+#ifdef __NR_fchmod
+{ "fchmod", __NR_fchmod },
+#endif
+#ifdef __NR_chown
+{ "chown", __NR_chown },
+#endif
+#ifdef __NR_fchown
+{ "fchown", __NR_fchown },
+#endif
+#ifdef __NR_lchown
+{ "lchown", __NR_lchown },
+#endif
+#ifdef __NR_umask
+{ "umask", __NR_umask },
+#endif
+#ifdef __NR_gettimeofday
+{ "gettimeofday", __NR_gettimeofday },
+#endif
+#ifdef __NR_getrlimit
+{ "getrlimit", __NR_getrlimit },
+#endif
+#ifdef __NR_getrusage
+{ "getrusage", __NR_getrusage },
+#endif
+#ifdef __NR_sysinfo
+{ "sysinfo", __NR_sysinfo },
+#endif
+#ifdef __NR_times
+{ "times", __NR_times },
+#endif
+#ifdef __NR_ptrace
+{ "ptrace", __NR_ptrace },
+#endif
+#ifdef __NR_getuid
+{ "getuid", __NR_getuid },
+#endif
+#ifdef __NR_syslog
+{ "syslog", __NR_syslog },
+#endif
+#ifdef __NR_getgid
+{ "getgid", __NR_getgid },
+#endif
+#ifdef __NR_setuid
+{ "setuid", __NR_setuid },
+#endif
+#ifdef __NR_setgid
+{ "setgid", __NR_setgid },
+#endif
+#ifdef __NR_geteuid
+{ "geteuid", __NR_geteuid },
+#endif
+#ifdef __NR_getegid
+{ "getegid", __NR_getegid },
+#endif
+#ifdef __NR_setpgid
+{ "setpgid", __NR_setpgid },
+#endif
+#ifdef __NR_getppid
+{ "getppid", __NR_getppid },
+#endif
+#ifdef __NR_getpgrp
+{ "getpgrp", __NR_getpgrp },
+#endif
+#ifdef __NR_setsid
+{ "setsid", __NR_setsid },
+#endif
+#ifdef __NR_setreuid
+{ "setreuid", __NR_setreuid },
+#endif
+#ifdef __NR_setregid
+{ "setregid", __NR_setregid },
+#endif
+#ifdef __NR_getgroups
+{ "getgroups", __NR_getgroups },
+#endif
+#ifdef __NR_setgroups
+{ "setgroups", __NR_setgroups },
+#endif
+#ifdef __NR_setresuid
+{ "setresuid", __NR_setresuid },
+#endif
+#ifdef __NR_getresuid
+{ "getresuid", __NR_getresuid },
+#endif
+#ifdef __NR_setresgid
+{ "setresgid", __NR_setresgid },
+#endif
+#ifdef __NR_getresgid
+{ "getresgid", __NR_getresgid },
+#endif
+#ifdef __NR_getpgid
+{ "getpgid", __NR_getpgid },
+#endif
+#ifdef __NR_setfsuid
+{ "setfsuid", __NR_setfsuid },
+#endif
+#ifdef __NR_setfsgid
+{ "setfsgid", __NR_setfsgid },
+#endif
+#ifdef __NR_getsid
+{ "getsid", __NR_getsid },
+#endif
+#ifdef __NR_capget
+{ "capget", __NR_capget },
+#endif
+#ifdef __NR_capset
+{ "capset", __NR_capset },
+#endif
+#ifdef __NR_rt_sigpending
+{ "rt_sigpending", __NR_rt_sigpending },
+#endif
+#ifdef __NR_rt_sigtimedwait
+{ "rt_sigtimedwait", __NR_rt_sigtimedwait },
+#endif
+#ifdef __NR_rt_sigqueueinfo
+{ "rt_sigqueueinfo", __NR_rt_sigqueueinfo },
+#endif
+#ifdef __NR_rt_sigsuspend
+{ "rt_sigsuspend", __NR_rt_sigsuspend },
+#endif
+#ifdef __NR_sigaltstack
+{ "sigaltstack", __NR_sigaltstack },
+#endif
+#ifdef __NR_utime
+{ "utime", __NR_utime },
+#endif
+#ifdef __NR_mknod
+{ "mknod", __NR_mknod },
+#endif
+#ifdef __NR_uselib
+{ "uselib", __NR_uselib },
+#endif
+#ifdef __NR_personality
+{ "personality", __NR_personality },
+#endif
+#ifdef __NR_ustat
+{ "ustat", __NR_ustat },
+#endif
+#ifdef __NR_statfs
+{ "statfs", __NR_statfs },
+#endif
+#ifdef __NR_fstatfs
+{ "fstatfs", __NR_fstatfs },
+#endif
+#ifdef __NR_sysfs
+{ "sysfs", __NR_sysfs },
+#endif
+#ifdef __NR_getpriority
+{ "getpriority", __NR_getpriority },
+#endif
+#ifdef __NR_setpriority
+{ "setpriority", __NR_setpriority },
+#endif
+#ifdef __NR_sched_setparam
+{ "sched_setparam", __NR_sched_setparam },
+#endif
+#ifdef __NR_sched_getparam
+{ "sched_getparam", __NR_sched_getparam },
+#endif
+#ifdef __NR_sched_setscheduler
+{ "sched_setscheduler", __NR_sched_setscheduler },
+#endif
+#ifdef __NR_sched_getscheduler
+{ "sched_getscheduler", __NR_sched_getscheduler },
+#endif
+#ifdef __NR_sched_get_priority_max
+{ "sched_get_priority_max", __NR_sched_get_priority_max },
+#endif
+#ifdef __NR_sched_get_priority_min
+{ "sched_get_priority_min", __NR_sched_get_priority_min },
+#endif
+#ifdef __NR_sched_rr_get_interval
+{ "sched_rr_get_interval", __NR_sched_rr_get_interval },
+#endif
+#ifdef __NR_mlock
+{ "mlock", __NR_mlock },
+#endif
+#ifdef __NR_munlock
+{ "munlock", __NR_munlock },
+#endif
+#ifdef __NR_mlockall
+{ "mlockall", __NR_mlockall },
+#endif
+#ifdef __NR_munlockall
+{ "munlockall", __NR_munlockall },
+#endif
+#ifdef __NR_vhangup
+{ "vhangup", __NR_vhangup },
+#endif
+#ifdef __NR_modify_ldt
+{ "modify_ldt", __NR_modify_ldt },
+#endif
+#ifdef __NR_pivot_root
+{ "pivot_root", __NR_pivot_root },
+#endif
+#ifdef __NR__sysctl
+{ "_sysctl", __NR__sysctl },
+#endif
+#ifdef __NR_prctl
+{ "prctl", __NR_prctl },
+#endif
+#ifdef __NR_arch_prctl
+{ "arch_prctl", __NR_arch_prctl },
+#endif
+#ifdef __NR_adjtimex
+{ "adjtimex", __NR_adjtimex },
+#endif
+#ifdef __NR_setrlimit
+{ "setrlimit", __NR_setrlimit },
+#endif
+#ifdef __NR_chroot
+{ "chroot", __NR_chroot },
+#endif
+#ifdef __NR_sync
+{ "sync", __NR_sync },
+#endif
+#ifdef __NR_acct
+{ "acct", __NR_acct },
+#endif
+#ifdef __NR_settimeofday
+{ "settimeofday", __NR_settimeofday },
+#endif
+#ifdef __NR_mount
+{ "mount", __NR_mount },
+#endif
+#ifdef __NR_umount2
+{ "umount2", __NR_umount2 },
+#endif
+#ifdef __NR_swapon
+{ "swapon", __NR_swapon },
+#endif
+#ifdef __NR_swapoff
+{ "swapoff", __NR_swapoff },
+#endif
+#ifdef __NR_reboot
+{ "reboot", __NR_reboot },
+#endif
+#ifdef __NR_sethostname
+{ "sethostname", __NR_sethostname },
+#endif
+#ifdef __NR_setdomainname
+{ "setdomainname", __NR_setdomainname },
+#endif
+#ifdef __NR_iopl
+{ "iopl", __NR_iopl },
+#endif
+#ifdef __NR_ioperm
+{ "ioperm", __NR_ioperm },
+#endif
+#ifdef __NR_create_module
+{ "create_module", __NR_create_module },
+#endif
+#ifdef __NR_init_module
+{ "init_module", __NR_init_module },
+#endif
+#ifdef __NR_delete_module
+{ "delete_module", __NR_delete_module },
+#endif
+#ifdef __NR_get_kernel_syms
+{ "get_kernel_syms", __NR_get_kernel_syms },
+#endif
+#ifdef __NR_query_module
+{ "query_module", __NR_query_module },
+#endif
+#ifdef __NR_quotactl
+{ "quotactl", __NR_quotactl },
+#endif
+#ifdef __NR_nfsservctl
+{ "nfsservctl", __NR_nfsservctl },
+#endif
+#ifdef __NR_getpmsg
+{ "getpmsg", __NR_getpmsg },
+#endif
+#ifdef __NR_putpmsg
+{ "putpmsg", __NR_putpmsg },
+#endif
+#ifdef __NR_afs_syscall
+{ "afs_syscall", __NR_afs_syscall },
+#endif
+#ifdef __NR_tuxcall
+{ "tuxcall", __NR_tuxcall },
+#endif
+#ifdef __NR_security
+{ "security", __NR_security },
+#endif
+#ifdef __NR_gettid
+{ "gettid", __NR_gettid },
+#endif
+#ifdef __NR_readahead
+{ "readahead", __NR_readahead },
+#endif
+#ifdef __NR_setxattr
+{ "setxattr", __NR_setxattr },
+#endif
+#ifdef __NR_lsetxattr
+{ "lsetxattr", __NR_lsetxattr },
+#endif
+#ifdef __NR_fsetxattr
+{ "fsetxattr", __NR_fsetxattr },
+#endif
+#ifdef __NR_getxattr
+{ "getxattr", __NR_getxattr },
+#endif
+#ifdef __NR_lgetxattr
+{ "lgetxattr", __NR_lgetxattr },
+#endif
+#ifdef __NR_fgetxattr
+{ "fgetxattr", __NR_fgetxattr },
+#endif
+#ifdef __NR_listxattr
+{ "listxattr", __NR_listxattr },
+#endif
+#ifdef __NR_llistxattr
+{ "llistxattr", __NR_llistxattr },
+#endif
+#ifdef __NR_flistxattr
+{ "flistxattr", __NR_flistxattr },
+#endif
+#ifdef __NR_removexattr
+{ "removexattr", __NR_removexattr },
+#endif
+#ifdef __NR_lremovexattr
+{ "lremovexattr", __NR_lremovexattr },
+#endif
+#ifdef __NR_fremovexattr
+{ "fremovexattr", __NR_fremovexattr },
+#endif
+#ifdef __NR_tkill
+{ "tkill", __NR_tkill },
+#endif
+#ifdef __NR_time
+{ "time", __NR_time },
+#endif
+#ifdef __NR_futex
+{ "futex", __NR_futex },
+#endif
+#ifdef __NR_sched_setaffinity
+{ "sched_setaffinity", __NR_sched_setaffinity },
+#endif
+#ifdef __NR_sched_getaffinity
+{ "sched_getaffinity", __NR_sched_getaffinity },
+#endif
+#ifdef __NR_set_thread_area
+{ "set_thread_area", __NR_set_thread_area },
+#endif
+#ifdef __NR_io_setup
+{ "io_setup", __NR_io_setup },
+#endif
+#ifdef __NR_io_destroy
+{ "io_destroy", __NR_io_destroy },
+#endif
+#ifdef __NR_io_getevents
+{ "io_getevents", __NR_io_getevents },
+#endif
+#ifdef __NR_io_submit
+{ "io_submit", __NR_io_submit },
+#endif
+#ifdef __NR_io_cancel
+{ "io_cancel", __NR_io_cancel },
+#endif
+#ifdef __NR_get_thread_area
+{ "get_thread_area", __NR_get_thread_area },
+#endif
+#ifdef __NR_lookup_dcookie
+{ "lookup_dcookie", __NR_lookup_dcookie },
+#endif
+#ifdef __NR_epoll_create
+{ "epoll_create", __NR_epoll_create },
+#endif
+#ifdef __NR_epoll_ctl_old
+{ "epoll_ctl_old", __NR_epoll_ctl_old },
+#endif
+#ifdef __NR_epoll_wait_old
+{ "epoll_wait_old", __NR_epoll_wait_old },
+#endif
+#ifdef __NR_remap_file_pages
+{ "remap_file_pages", __NR_remap_file_pages },
+#endif
+#ifdef __NR_getdents64
+{ "getdents64", __NR_getdents64 },
+#endif
+#ifdef __NR_set_tid_address
+{ "set_tid_address", __NR_set_tid_address },
+#endif
+#ifdef __NR_restart_syscall
+{ "restart_syscall", __NR_restart_syscall },
+#endif
+#ifdef __NR_semtimedop
+{ "semtimedop", __NR_semtimedop },
+#endif
+#ifdef __NR_fadvise64
+{ "fadvise64", __NR_fadvise64 },
+#endif
+#ifdef __NR_timer_create
+{ "timer_create", __NR_timer_create },
+#endif
+#ifdef __NR_timer_settime
+{ "timer_settime", __NR_timer_settime },
+#endif
+#ifdef __NR_timer_gettime
+{ "timer_gettime", __NR_timer_gettime },
+#endif
+#ifdef __NR_timer_getoverrun
+{ "timer_getoverrun", __NR_timer_getoverrun },
+#endif
+#ifdef __NR_timer_delete
+{ "timer_delete", __NR_timer_delete },
+#endif
+#ifdef __NR_clock_settime
+{ "clock_settime", __NR_clock_settime },
+#endif
+#ifdef __NR_clock_gettime
+{ "clock_gettime", __NR_clock_gettime },
+#endif
+#ifdef __NR_clock_getres
+{ "clock_getres", __NR_clock_getres },
+#endif
+#ifdef __NR_clock_nanosleep
+{ "clock_nanosleep", __NR_clock_nanosleep },
+#endif
+#ifdef __NR_exit_group
+{ "exit_group", __NR_exit_group },
+#endif
+#ifdef __NR_epoll_wait
+{ "epoll_wait", __NR_epoll_wait },
+#endif
+#ifdef __NR_epoll_ctl
+{ "epoll_ctl", __NR_epoll_ctl },
+#endif
+#ifdef __NR_tgkill
+{ "tgkill", __NR_tgkill },
+#endif
+#ifdef __NR_utimes
+{ "utimes", __NR_utimes },
+#endif
+#ifdef __NR_vserver
+{ "vserver", __NR_vserver },
+#endif
+#ifdef __NR_mbind
+{ "mbind", __NR_mbind },
+#endif
+#ifdef __NR_set_mempolicy
+{ "set_mempolicy", __NR_set_mempolicy },
+#endif
+#ifdef __NR_get_mempolicy
+{ "get_mempolicy", __NR_get_mempolicy },
+#endif
+#ifdef __NR_mq_open
+{ "mq_open", __NR_mq_open },
+#endif
+#ifdef __NR_mq_unlink
+{ "mq_unlink", __NR_mq_unlink },
+#endif
+#ifdef __NR_mq_timedsend
+{ "mq_timedsend", __NR_mq_timedsend },
+#endif
+#ifdef __NR_mq_timedreceive
+{ "mq_timedreceive", __NR_mq_timedreceive },
+#endif
+#ifdef __NR_mq_notify
+{ "mq_notify", __NR_mq_notify },
+#endif
+#ifdef __NR_mq_getsetattr
+{ "mq_getsetattr", __NR_mq_getsetattr },
+#endif
+#ifdef __NR_kexec_load
+{ "kexec_load", __NR_kexec_load },
+#endif
+#ifdef __NR_waitid
+{ "waitid", __NR_waitid },
+#endif
+#ifdef __NR_add_key
+{ "add_key", __NR_add_key },
+#endif
+#ifdef __NR_request_key
+{ "request_key", __NR_request_key },
+#endif
+#ifdef __NR_keyctl
+{ "keyctl", __NR_keyctl },
+#endif
+#ifdef __NR_ioprio_set
+{ "ioprio_set", __NR_ioprio_set },
+#endif
+#ifdef __NR_ioprio_get
+{ "ioprio_get", __NR_ioprio_get },
+#endif
+#ifdef __NR_inotify_init
+{ "inotify_init", __NR_inotify_init },
+#endif
+#ifdef __NR_inotify_add_watch
+{ "inotify_add_watch", __NR_inotify_add_watch },
+#endif
+#ifdef __NR_inotify_rm_watch
+{ "inotify_rm_watch", __NR_inotify_rm_watch },
+#endif
+#ifdef __NR_migrate_pages
+{ "migrate_pages", __NR_migrate_pages },
+#endif
+#ifdef __NR_openat
+{ "openat", __NR_openat },
+#endif
+#ifdef __NR_mkdirat
+{ "mkdirat", __NR_mkdirat },
+#endif
+#ifdef __NR_mknodat
+{ "mknodat", __NR_mknodat },
+#endif
+#ifdef __NR_fchownat
+{ "fchownat", __NR_fchownat },
+#endif
+#ifdef __NR_futimesat
+{ "futimesat", __NR_futimesat },
+#endif
+#ifdef __NR_newfstatat
+{ "newfstatat", __NR_newfstatat },
+#endif
+#ifdef __NR_unlinkat
+{ "unlinkat", __NR_unlinkat },
+#endif
+#ifdef __NR_renameat
+{ "renameat", __NR_renameat },
+#endif
+#ifdef __NR_linkat
+{ "linkat", __NR_linkat },
+#endif
+#ifdef __NR_symlinkat
+{ "symlinkat", __NR_symlinkat },
+#endif
+#ifdef __NR_readlinkat
+{ "readlinkat", __NR_readlinkat },
+#endif
+#ifdef __NR_fchmodat
+{ "fchmodat", __NR_fchmodat },
+#endif
+#ifdef __NR_faccessat
+{ "faccessat", __NR_faccessat },
+#endif
+#ifdef __NR_pselect6
+{ "pselect6", __NR_pselect6 },
+#endif
+#ifdef __NR_ppoll
+{ "ppoll", __NR_ppoll },
+#endif
+#ifdef __NR_unshare
+{ "unshare", __NR_unshare },
+#endif
+#ifdef __NR_set_robust_list
+{ "set_robust_list", __NR_set_robust_list },
+#endif
+#ifdef __NR_get_robust_list
+{ "get_robust_list", __NR_get_robust_list },
+#endif
+#ifdef __NR_splice
+{ "splice", __NR_splice },
+#endif
+#ifdef __NR_tee
+{ "tee", __NR_tee },
+#endif
+#ifdef __NR_sync_file_range
+{ "sync_file_range", __NR_sync_file_range },
+#endif
+#ifdef __NR_vmsplice
+{ "vmsplice", __NR_vmsplice },
+#endif
+#ifdef __NR_move_pages
+{ "move_pages", __NR_move_pages },
+#endif
+#ifdef __NR_utimensat
+{ "utimensat", __NR_utimensat },
+#endif
+#ifdef __NR_epoll_pwait
+{ "epoll_pwait", __NR_epoll_pwait },
+#endif
+#ifdef __NR_signalfd
+{ "signalfd", __NR_signalfd },
+#endif
+#ifdef __NR_timerfd_create
+{ "timerfd_create", __NR_timerfd_create },
+#endif
+#ifdef __NR_eventfd
+{ "eventfd", __NR_eventfd },
+#endif
+#ifdef __NR_fallocate
+{ "fallocate", __NR_fallocate },
+#endif
+#ifdef __NR_timerfd_settime
+{ "timerfd_settime", __NR_timerfd_settime },
+#endif
+#ifdef __NR_timerfd_gettime
+{ "timerfd_gettime", __NR_timerfd_gettime },
+#endif
+#ifdef __NR_accept4
+{ "accept4", __NR_accept4 },
+#endif
+#ifdef __NR_signalfd4
+{ "signalfd4", __NR_signalfd4 },
+#endif
+#ifdef __NR_eventfd2
+{ "eventfd2", __NR_eventfd2 },
+#endif
+#ifdef __NR_epoll_create1
+{ "epoll_create1", __NR_epoll_create1 },
+#endif
+#ifdef __NR_dup3
+{ "dup3", __NR_dup3 },
+#endif
+#ifdef __NR_pipe2
+{ "pipe2", __NR_pipe2 },
+#endif
+#ifdef __NR_inotify_init1
+{ "inotify_init1", __NR_inotify_init1 },
+#endif
+#ifdef __NR_preadv
+{ "preadv", __NR_preadv },
+#endif
+#ifdef __NR_pwritev
+{ "pwritev", __NR_pwritev },
+#endif
+#ifdef __NR_rt_tgsigqueueinfo
+{ "rt_tgsigqueueinfo", __NR_rt_tgsigqueueinfo },
+#endif
+#ifdef __NR_perf_event_open
+{ "perf_event_open", __NR_perf_event_open },
+#endif
+#ifdef __NR_recvmmsg
+{ "recvmmsg", __NR_recvmmsg },
+#endif
+#ifdef __NR_fanotify_init
+{ "fanotify_init", __NR_fanotify_init },
+#endif
+#ifdef __NR_fanotify_mark
+{ "fanotify_mark", __NR_fanotify_mark },
+#endif
+#ifdef __NR_prlimit64
+{ "prlimit64", __NR_prlimit64 },
+#endif
+#ifdef __NR_name_to_handle_at
+{ "name_to_handle_at", __NR_name_to_handle_at },
+#endif
+#ifdef __NR_open_by_handle_at
+{ "open_by_handle_at", __NR_open_by_handle_at },
+#endif
+#ifdef __NR_clock_adjtime
+{ "clock_adjtime", __NR_clock_adjtime },
+#endif
+#ifdef __NR_syncfs
+{ "syncfs", __NR_syncfs },
+#endif
+#ifdef __NR_sendmmsg
+{ "sendmmsg", __NR_sendmmsg },
+#endif
+#ifdef __NR_setns
+{ "setns", __NR_setns },
+#endif
+#ifdef __NR_getcpu
+{ "getcpu", __NR_getcpu },
+#endif
+#ifdef __NR_process_vm_readv
+{ "process_vm_readv", __NR_process_vm_readv },
+#endif
+#ifdef __NR_process_vm_writev
+{ "process_vm_writev", __NR_process_vm_writev },
+#endif
+#ifdef __NR_kcmp
+{ "kcmp", __NR_kcmp },
+#endif
+#ifdef __NR_finit_module
+{ "finit_module", __NR_finit_module },
+#endif
+#ifdef __NR_sched_setattr
+{ "sched_setattr", __NR_sched_setattr },
+#endif
+#ifdef __NR_sched_getattr
+{ "sched_getattr", __NR_sched_getattr },
+#endif
+#ifdef __NR_renameat2
+{ "renameat2", __NR_renameat2 },
+#endif
+#ifdef __NR_seccomp
+{ "seccomp", __NR_seccomp },
+#endif
+  { NULL, -1 },
+};
diff --git a/minijail/minijail0.1 b/minijail/minijail0.1
new file mode 100644
index 0000000..3e077c1
--- /dev/null
+++ b/minijail/minijail0.1
@@ -0,0 +1,157 @@
+.TH MINIJAIL0 "1" "March 2016" "Chromium OS" "User Commands"
+.SH NAME
+minijail0 \- sandbox a process
+.SH SYNOPSIS
+.B minijail0
+[\fIOPTION\fR]... <\fIprogram\fR> [\fIargs\fR]...
+.SH DESCRIPTION
+.PP
+Runs PROGRAM inside a sandbox.
+.TP
+\fB-a <table>\fR
+Run using the alternate syscall table named \fItable\fR. Only available on kernels
+and architectures that support the PR_ALT_SYSCALL option of prctl(2).
+.TP
+\fB-b <src>,<dest>[,<writeable>]
+Bind-mount \fIsrc\fR into the chroot directory at \fIdest\fR, optionally writeable.
+.TP
+\fB-c <caps>\fR
+Restrict capabilities to \fIcaps\fR. When used in conjunction with \fB-u\fR and
+\fB-g\fR, this allows a program to have access to only certain parts of root's
+default privileges while running as another user and group ID altogether. Note
+that these capabilities are not inherited by subprocesses of the process given
+capabilities unless those subprocesses have POSIX file capabilities. See
+\fBcapabilities\fR(7).
+.TP
+\fB-C <dir>\fR
+Change root (using chroot(2)) to \fIdir\fR.
+.TP
+\fB-e[file]\fR
+Enter a new network namespace, or if \fIfile\fR is specified, enter an existing
+network namespace specified by \fIfile\fR which is typically of the form
+/proc/<pid>/ns/net.
+.TP
+\fB-f <file>\fR
+Write the pid of the jailed process to \fIfile\fR.
+.TP
+\fB-G\fR
+Inherit all the supplementary groups of the user specified with \fB-u\fR. It
+is an error to use this option without having specified a \fBuser name\fR to
+\fB-u\fR.
+.TP
+\fB-g <group>\fR
+Change groups to \fIgroup\fR, which may be either a group name or a numeric
+group ID.
+.TP
+\fB-h\fR
+Print a help message.
+.TP
+\fB-H\fR
+Print a help message detailing supported system call names for seccomp_filter.
+(Other direct numbers may be specified if minijail0 is not in sync with the
+ host kernel or something like 32/64-bit compatibility issues exist.)
+.TP
+\fB-I\fR
+Run \fIprogram\fR as init (pid 1) inside a new pid namespace (implies \fB-p\fR).
+.TP
+\fB-k <src>,<dest>,<type>[,<flags>]\fR
+Mount \fIsrc\fR, a \fItype\fR filesystem, into the chroot directory at \fIdest\fR, with optional \fIflags\fR.
+.TP
+\fB-K\fR
+Don't mark all existing mounts as MS_PRIVATE.
+This option is \fBdangerous\fR as it negates most of the functionality of \fB-v\fR.
+You very likely don't need this.
+.TP
+\fB-l\fR
+Run inside a new IPC namespace. This option makes the program's System V IPC
+namespace independent.
+.TP
+\fB-L\fR
+Report blocked syscalls to syslog when using seccomp filter. This option will
+force certain syscalls to be allowed in order to achieve this, depending on the
+system.
+.TP
+\fB-m "<uid> <loweruid> <count>[,<uid> <loweruid> <count>]"\fR
+Set the uid mapping of a user namespace (implies \fB-pU\fR). Same arguments as
+\fBnewuidmap(1)\fR. Multiple mappings should be separated by ','.
+.TP
+\fB-M "<uid> <loweruid> <count>[,<uid> <loweruid> <count>]"\fR
+Set the gid mapping of a user namespace (implies \fB-pU\fR). Same arguments as
+\fBnewgidmap(1)\fR. Multiple mappings should be separated by ','.
+.TP
+\fB-n\fR
+Set the process's \fIno_new_privs\fR bit. See \fBprctl(2)\fR and the kernel
+source file \fIDocumentation/prctl/no_new_privs.txt\fR for more info.
+.TP
+\fB-N\fR
+Run inside a new cgroup namespace. This option runs the program with a cgroup
+view showing the program's cgroup as the root. This is only available on v4.6+
+of the Linux kernel.
+.TP
+\fB-p\fR
+Run inside a new PID namespace. This option will make it impossible for the
+program to see or affect processes that are not its descendants. This implies
+\fB-v\fR and \fB-r\fR, since otherwise the process can see outside its namespace
+by inspecting /proc.
+.TP
+\fB-P <dir>\fR
+Set \fIdir\fR as the root fs using \fBpivot_root\fR. Implies \fB-v\fR, not
+compatible with \fB-C\fR.
+.TP
+\fB-r\fR
+Remount /proc readonly. This implies \fB-v\fR. Remounting /proc readonly means
+that even if the process has write access to a system config knob in /proc
+(e.g., in /sys/kernel), it cannot change the value.
+.TP
+\fB-s\fR
+Enable seccomp(2) in mode 1, which restricts the child process to a very small
+set of system calls.
+.TP
+\fB-S <arch-specific seccomp_filter policy file>\fR
+Enable seccomp(2) in mode 13 which restricts the child process to a set of
+system calls defined in the policy file. Note that system calls often change
+names based on the architecture or mode. (uname -m is your friend.)
+.TP
+\fB-t\fR
+Mounts a tmpfs filesystem on /tmp. /tmp must exist in the chroot.
+This must be used with \fB-C\fR. The default filesystem has a max size of 128M
+and has standard /tmp permissions (777).
+.TP
+\fB-T <type>\fR
+Assume program's ELF linkage type is \fItype\fR,
+which should be either 'static' or 'dynamic'.
+.TP
+\fB-u <user>\fR
+Change users to \fIuser\fR, which may be either a user name or a numeric user
+ID.
+.TP
+\fB-U\fR
+Enter a new user namespace (implies \fB-p\fR).
+.TP
+\fB-v\fR
+Run inside a new VFS namespace. This option makes the program's mountpoints
+independent of the rest of the system's.
+.TP
+\fB-V <file>\fR
+Enter the VFS namespace specified by \fIfile\fR.
+.SH IMPLEMENTATION
+This program is broken up into two parts: \fBminijail0\fR (the frontend) and a helper
+library called \fBlibminijailpreload\fR. Some jailings can only be achieved from
+the process to which they will actually apply - specifically capability use
+(since capabilities are not inherited to an exec'd process unless the exec'd
+process has POSIX file capabilities), seccomp (since we can't exec() once we're
+seccomp'd), and ptrace-disable (which is always cleared on exec()).
+
+To this end, \fBlibminijailpreload\fR is forcibly loaded into all
+dynamically-linked target programs if any of these restrictions are in effect;
+we pass the specific restrictions in an environment variable which the preloaded
+library looks for. The forcibly-loaded library then applies the restrictions
+to the newly-loaded program.
+
+.SH AUTHOR
+The Chromium OS Authors <chromiumos-dev@chromium.org>
+.SH COPYRIGHT
+Copyright \(co 2011 The Chromium OS Authors
+License BSD-like.
+.SH "SEE ALSO"
+\fBlibminijail.h\fR \fBminijail0(5)\fR
diff --git a/minijail/minijail0.5 b/minijail/minijail0.5
new file mode 100644
index 0000000..b9036b9
--- /dev/null
+++ b/minijail/minijail0.5
@@ -0,0 +1,85 @@
+.TH MINIJAIL0 "1" "July 2011" "Chromium OS" "User Commands"
+.SH NAME
+minijail0 \- sandbox a process
+.SH DESCRIPTION
+.PP
+Runs PROGRAM inside a sandbox. See minijail(1) for details.
+.SH EXAMPLES
+
+Safely switch from root to nobody while dropping all capabilities and
+inheriting any groups from nobody:
+
+  # minijail0 -c 0 -G -u nobody /usr/bin/whoami
+  nobody
+
+Run in a PID and VFS namespace without superuser capabilities (but still
+as root) and with a private view of /proc:
+
+  # minijail0 -p -v -r -c 0 /bin/ps
+    PID TTY           TIME CMD
+      1 pts/0     00:00:00 minijail0
+      2 pts/0     00:00:00 ps
+
+Running a process with a seccomp filter policy at reduced privileges:
+
+  # minijail0 -S /usr/share/minijail0/$(uname -m)/cat.policy -- \\
+              /bin/cat /proc/self/seccomp_filter
+  ...
+
+.SH SECCOMP_FILTER POLICY
+The policy file supplied to the \fB-S\fR argument supports the following syntax:
+
+  \fB<syscall_name>\fR:\fB<ftrace filter policy>\fR
+  \fB<syscall_number>\fR:\fB<ftrace filter policy>\fR
+  \fB<empty line>\fR
+  \fB# any single line comment\fR
+
+A policy that emulates seccomp(2) in mode 1 may look like:
+  read: 1
+  write: 1
+  sig_return: 1
+  exit: 1
+
+The "1" acts as a wildcard and allows any use of the mentioned system
+call.  More advanced filtering is possible if your kernel supports
+CONFIG_FTRACE_SYSCALLS.  For example, we can allow a process to open any
+file read only and mmap PROT_READ only:
+
+  # open with O_LARGEFILE|O_RDONLY|O_NONBLOCK or some combination
+  open: flags == 32768 || flags == 0 || flags == 34816 || flags == 2048
+  mmap2: prot == 0x0
+  munmap: 1
+  close: 1
+
+The supported arguments may be found by reviewing the system call
+prototypes in the Linux kernel source code.  Be aware that any
+non-numeric comparison may be subject to time-of-check-time-of-use
+attacks and cannot be considered safe.
+
+\fBexecve\fR may only be used when invoking with CAP_SYS_ADMIN privileges.
+
+.SH SECCOMP_FILTER POLICY WRITING
+
+Determining policy for seccomp_filter can be time consuming.  System
+calls are often named in arch-specific, or legacy tainted, ways.  E.g.,
+geteuid versus geteuid32.  On process death due to a seccomp filter
+rule, the offending system call number will be supplied with a best
+guess of the ABI defined name.  This information may be used to produce
+working baseline policies.  However, if the process being contained has
+a fairly tight working domain, using \fBstrace -e raw=all <program>\fR
+can generate the list of system calls that are needed. Note that when
+using libminijail or minijail with preloading, supporting initial
+process setup calls will not be required.  Be conservative.
+
+It's also possible to analyze the binary checking for all non-dead
+functions and determining if any of them issue system calls.  There is
+no active implementation for this, but something like
+code.google.com/p/seccompsandbox is one possible runtime variant.
+
+.SH AUTHOR
+The Chromium OS Authors <chromiumos-dev@chromium.org>
+.SH COPYRIGHT
+Copyright \(co 2011 The Chromium OS Authors
+License BSD-like.
+.SH "SEE ALSO"
+\fBminijail\fR(1)
diff --git a/minijail/minijail0.c b/minijail/minijail0.c
new file mode 100644
index 0000000..e21d056
--- /dev/null
+++ b/minijail/minijail0.c
@@ -0,0 +1,468 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libminijail.h"
+#include "libsyscalls.h"
+
+#include "elfparse.h"
+#include "util.h"
+
+#define IDMAP_LEN 32U
+
+static void set_user(struct minijail *j, const char *arg)
+{
+	char *end = NULL;
+	int uid = strtod(arg, &end);
+	if (!*end && *arg) {
+		minijail_change_uid(j, uid);
+		return;
+	}
+
+	if (minijail_change_user(j, arg)) {
+		fprintf(stderr, "Bad user: '%s'\n", arg);
+		exit(1);
+	}
+}
+
+static void set_group(struct minijail *j, const char *arg)
+{
+	char *end = NULL;
+	int gid = strtod(arg, &end);
+	if (!*end && *arg) {
+		minijail_change_gid(j, gid);
+		return;
+	}
+
+	if (minijail_change_group(j, arg)) {
+		fprintf(stderr, "Bad group: '%s'\n", arg);
+		exit(1);
+	}
+}
+
+static void use_caps(struct minijail *j, const char *arg)
+{
+	uint64_t caps;
+	char *end = NULL;
+	caps = strtoull(arg, &end, 16);
+	if (*end) {
+		fprintf(stderr, "Invalid cap set: '%s'\n", arg);
+		exit(1);
+	}
+	minijail_use_caps(j, caps);
+}
+
+static void add_binding(struct minijail *j, char *arg)
+{
+	char *src = strtok(arg, ",");
+	char *dest = strtok(NULL, ",");
+	char *flags = strtok(NULL, ",");
+	if (!src || !dest) {
+		fprintf(stderr, "Bad binding: %s %s\n", src, dest);
+		exit(1);
+	}
+	if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
+		fprintf(stderr, "minijail_bind failed.\n");
+		exit(1);
+	}
+}
+
+static void add_mount(struct minijail *j, char *arg)
+{
+	char *src = strtok(arg, ",");
+	char *dest = strtok(NULL, ",");
+	char *type = strtok(NULL, ",");
+	char *flags = strtok(NULL, ",");
+	char *data = strtok(NULL, ",");
+	if (!src || !dest || !type) {
+		fprintf(stderr, "Bad mount: %s %s %s\n", src, dest, type);
+		exit(1);
+	}
+	if (minijail_mount_with_data(j, src, dest, type,
+				     flags ? strtoul(flags, NULL, 16) : 0,
+				     data)) {
+		fprintf(stderr, "minijail_mount failed.\n");
+		exit(1);
+	}
+}
+
+static char *build_idmap(id_t id, id_t lowerid)
+{
+	int ret;
+	char *idmap = malloc(IDMAP_LEN);
+	ret = snprintf(idmap, IDMAP_LEN, "%d %d 1", id, lowerid);
+	if (ret < 0 || (size_t)ret >= IDMAP_LEN) {
+		free(idmap);
+		fprintf(stderr, "Could not build id map.\n");
+		exit(1);
+	}
+	return idmap;
+}
+
+static void usage(const char *progn)
+{
+	size_t i;
+
+	printf("Usage: %s [-GhiIlnprstUv]\n"
+	       "  [-b <src>,<dest>[,<writeable>]] [-f <file>]"
+	       " [-c <caps>] [-C <dir>] [-g <group>] [-u <user>]\n"
+	       "  [-S <file>] [-k <src>,<dest>,<type>[,<flags>][,<data>]] [-T <type>]\n"
+	       "  [-m[<uid> <loweruid> <count>]*] [-M[<gid> <lowergid> <count>]*]\n"
+	       "  <program> [args...]\n"
+	       "  -a <table>: Use alternate syscall table <table>.\n"
+	       "  -b:         Bind <src> to <dest> in chroot.\n"
+	       "              Multiple instances allowed.\n"
+	       "  -k:         Mount <src> at <dest> in chroot.\n"
+	       "              <flags> and <data> can be specified as in mount(2).\n"
+	       "              Multiple instances allowed.\n"
+	       "  -c <caps>:  Restrict caps to <caps>.\n"
+	       "  -C <dir>:   chroot(2) to <dir>.\n"
+	       "              Not compatible with -P.\n"
+	       "  -e[file]:   Enter new network namespace, or existing one if |file| is provided.\n"
+	       "  -f <file>:  Write the pid of the jailed process to <file>.\n"
+	       "  -G:         Inherit supplementary groups from uid.\n"
+	       "  -g <group>: Change gid to <group>.\n"
+	       "  -h:         Help (this message).\n"
+	       "  -H:         Seccomp filter help message.\n"
+	       "  -i:         Exit immediately after fork (do not act as init).\n"
+	       "              Not compatible with -p.\n"
+	       "  -I:         Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
+	       "  -K:         Don't mark all existing mounts as MS_PRIVATE.\n"
+	       "  -l:         Enter new IPC namespace.\n"
+	       "  -L:         Report blocked syscalls to syslog when using seccomp filter.\n"
+	       "              Forces the following syscalls to be allowed:\n"
+	       "                  ", progn);
+	for (i = 0; i < log_syscalls_len; i++)
+		printf("%s ", log_syscalls[i]);
+
+	printf("\n"
+	       "  -m:         Set the uid mapping of a user namespace (implies -pU).\n"
+	       "              Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
+	       "              Not compatible with -b without the 'writable' option.\n"
+	       "  -M:         Set the gid mapping of a user namespace (implies -pU).\n"
+	       "              Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
+	       "              Not compatible with -b without the 'writable' option.\n"
+	       "  -n:         Set no_new_privs.\n"
+	       "  -N:         Enter a new cgroup namespace.\n"
+	       "  -p:         Enter new pid namespace (implies -vr).\n"
+	       "  -P <dir>:   pivot_root(2) to <dir> (implies -v).\n"
+	       "              Not compatible with -C.\n"
+	       "  -r:         Remount /proc read-only (implies -v).\n"
+	       "  -s:         Use seccomp.\n"
+	       "  -S <file>:  Set seccomp filter using <file>.\n"
+	       "              E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
+	       "              Requires -n when not running as root.\n"
+	       "  -t:         Mount tmpfs at /tmp inside chroot.\n"
+	       "  -T <type>:  Don't access <program> before execve(2), assume <type> ELF binary.\n"
+	       "              <type> must be 'static' or 'dynamic'.\n"
+	       "  -u <user>:  Change uid to <user>.\n"
+	       "  -U:         Enter new user namespace (implies -p).\n"
+	       "  -v:         Enter new mount namespace.\n"
+	       "  -V <file>:  Enter specified mount namespace.\n");
+}
+
+static void seccomp_filter_usage(const char *progn)
+{
+	const struct syscall_entry *entry = syscall_table;
+	printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
+	       "System call names supported:\n", progn);
+	for (; entry->name && entry->nr >= 0; ++entry)
+		printf("  %s [%d]\n", entry->name, entry->nr);
+	printf("\nSee minijail0(5) for example policies.\n");
+}
+
+static int parse_args(struct minijail *j, int argc, char *argv[],
+		      int *exit_immediately, ElfType *elftype)
+{
+	int opt;
+	int use_seccomp_filter = 0;
+	int binding = 0;
+	int pivot_root = 0, chroot = 0;
+	int mount_ns = 0, skip_remount = 0;
+	const size_t path_max = 4096;
+	char *map;
+	const char *filter_path;
+	if (argc > 1 && argv[1][0] != '-')
+		return 1;
+
+	const char *optstring =
+	    "u:g:sS:c:C:P:b:V:f:m::M:k:a:e::T:vrGhHinNplLtIUK";
+	while ((opt = getopt(argc, argv, optstring)) != -1) {
+		switch (opt) {
+		case 'u':
+			set_user(j, optarg);
+			break;
+		case 'g':
+			set_group(j, optarg);
+			break;
+		case 'n':
+			minijail_no_new_privs(j);
+			break;
+		case 's':
+			minijail_use_seccomp(j);
+			break;
+		case 'S':
+			minijail_use_seccomp_filter(j);
+			if (strlen(optarg) >= path_max) {
+				fprintf(stderr, "Filter path is too long.\n");
+				exit(1);
+			}
+			filter_path = strndup(optarg, path_max);
+			if (!filter_path) {
+				fprintf(stderr,
+					"Could not strndup(3) filter path.\n");
+				exit(1);
+			}
+			use_seccomp_filter = 1;
+			break;
+		case 'l':
+			minijail_namespace_ipc(j);
+			break;
+		case 'L':
+			minijail_log_seccomp_filter_failures(j);
+			break;
+		case 'b':
+			add_binding(j, optarg);
+			binding = 1;
+			break;
+		case 'c':
+			use_caps(j, optarg);
+			break;
+		case 'C':
+			if (pivot_root) {
+				fprintf(stderr, "Could not set chroot because "
+						"'-P' was specified.\n");
+				exit(1);
+			}
+			if (0 != minijail_enter_chroot(j, optarg)) {
+				fprintf(stderr, "Could not set chroot.\n");
+				exit(1);
+			}
+			chroot = 1;
+			break;
+		case 'k':
+			add_mount(j, optarg);
+			break;
+		case 'K':
+			minijail_skip_remount_private(j);
+			skip_remount = 1;
+			break;
+		case 'P':
+			if (chroot) {
+				fprintf(stderr,
+					"Could not set pivot_root because "
+					"'-C' was specified.\n");
+				exit(1);
+			}
+			if (0 != minijail_enter_pivot_root(j, optarg)) {
+				fprintf(stderr, "Could not set pivot_root.\n");
+				exit(1);
+			}
+			minijail_namespace_vfs(j);
+			pivot_root = 1;
+			break;
+		case 'f':
+			if (0 != minijail_write_pid_file(j, optarg)) {
+				fprintf(stderr,
+					"Could not prepare pid file path.\n");
+				exit(1);
+			}
+			break;
+		case 't':
+			minijail_mount_tmp(j);
+			break;
+		case 'v':
+			minijail_namespace_vfs(j);
+			mount_ns = 1;
+			break;
+		case 'V':
+			minijail_namespace_enter_vfs(j, optarg);
+			break;
+		case 'r':
+			minijail_remount_proc_readonly(j);
+			break;
+		case 'G':
+			minijail_inherit_usergroups(j);
+			break;
+		case 'N':
+			minijail_namespace_cgroups(j);
+			break;
+		case 'p':
+			minijail_namespace_pids(j);
+			break;
+		case 'e':
+			if (optarg)
+				minijail_namespace_enter_net(j, optarg);
+			else
+				minijail_namespace_net(j);
+			break;
+		case 'i':
+			*exit_immediately = 1;
+			break;
+		case 'H':
+			seccomp_filter_usage(argv[0]);
+			exit(1);
+		case 'I':
+			minijail_namespace_pids(j);
+			minijail_run_as_init(j);
+			break;
+		case 'U':
+			minijail_namespace_user(j);
+			minijail_namespace_pids(j);
+			break;
+		case 'm':
+			minijail_namespace_user(j);
+			minijail_namespace_pids(j);
+
+			if (optarg) {
+				map = strdup(optarg);
+			} else {
+				/*
+				 * If no map is passed, map the current uid to
+				 * root.
+				 */
+				map = build_idmap(0, getuid());
+			}
+			if (0 != minijail_uidmap(j, map)) {
+				fprintf(stderr, "Could not set uid map.\n");
+				exit(1);
+			}
+			free(map);
+			break;
+		case 'M':
+			minijail_namespace_user(j);
+			minijail_namespace_pids(j);
+			if (0 != minijail_gidmap(j, optarg)) {
+				fprintf(stderr, "Could not set gid map.\n");
+				exit(1);
+			}
+			break;
+		case 'a':
+			if (0 != minijail_use_alt_syscall(j, optarg)) {
+				fprintf(stderr,
+					"Could not set alt-syscall table.\n");
+				exit(1);
+			}
+			break;
+		case 'T':
+			if (!strcmp(optarg, "static"))
+				*elftype = ELFSTATIC;
+			else if (!strcmp(optarg, "dynamic"))
+				*elftype = ELFDYNAMIC;
+			else {
+				fprintf(stderr, "ELF type must be 'static' or "
+						"'dynamic'.\n");
+				exit(1);
+			}
+			break;
+		default:
+			usage(argv[0]);
+			exit(1);
+		}
+		if (optind < argc && argv[optind][0] != '-')
+			break;
+	}
+
+	/* Only allow bind mounts when entering a chroot or using pivot_root. */
+	if (binding && !(chroot || pivot_root)) {
+		fprintf(stderr, "Can't add bind mounts without chroot or"
+				" pivot_root.\n");
+		exit(1);
+	}
+
+	/*
+	 * Remounting / as MS_PRIVATE only happens when entering a new mount
+	 * namespace, so skipping it only applies in that case.
+	 */
+	if (skip_remount && !mount_ns) {
+		fprintf(stderr, "Can't skip marking mounts as MS_PRIVATE"
+				" without mount namespaces.\n");
+		exit(1);
+	}
+
+	/*
+	 * We parse seccomp filters here to make sure we've collected all
+	 * cmdline options.
+	 */
+	if (use_seccomp_filter) {
+		minijail_parse_seccomp_filters(j, filter_path);
+		free((void*)filter_path);
+	}
+
+	if (argc == optind) {
+		usage(argv[0]);
+		exit(1);
+	}
+
+	return optind;
+}
+
+int main(int argc, char *argv[])
+{
+	struct minijail *j = minijail_new();
+	const char *dl_mesg = NULL;
+	int exit_immediately = 0;
+	ElfType elftype = ELFERROR;
+	int consumed = parse_args(j, argc, argv, &exit_immediately, &elftype);
+	argc -= consumed;
+	argv += consumed;
+
+	if (elftype == ELFERROR) {
+		/*
+		 * -T was not specified.
+		 * Get the path to the program adjusted for changing root.
+		 */
+		char *program_path = minijail_get_original_path(j, argv[0]);
+
+		/* Check that we can access the target program. */
+		if (access(program_path, X_OK)) {
+			fprintf(stderr,
+				"Target program '%s' is not accessible.\n",
+				argv[0]);
+			return 1;
+		}
+
+		/* Check if target is statically or dynamically linked. */
+		elftype = get_elf_linkage(program_path);
+		free(program_path);
+	}
+
+	if (elftype == ELFSTATIC) {
+		/*
+		 * Target binary is statically linked so we cannot use
+		 * libminijailpreload.so.
+		 */
+		minijail_run_no_preload(j, argv[0], argv);
+	} else if (elftype == ELFDYNAMIC) {
+		/*
+		 * Target binary is dynamically linked so we can
+		 * inject libminijailpreload.so into it.
+		 */
+
+		/* Check that we can dlopen() libminijailpreload.so. */
+		if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
+			dl_mesg = dlerror();
+			fprintf(stderr, "dlopen(): %s\n", dl_mesg);
+			return 1;
+		}
+		minijail_run(j, argv[0], argv);
+	} else {
+		fprintf(stderr,
+			"Target program '%s' is not a valid ELF file.\n",
+			argv[0]);
+		return 1;
+	}
+
+	if (exit_immediately) {
+		info("not running init loop, exiting immediately");
+		return 0;
+	}
+	return minijail_wait(j);
+}
diff --git a/minijail/platform2_preinstall.sh b/minijail/platform2_preinstall.sh
new file mode 100755
index 0000000..7d19d99
--- /dev/null
+++ b/minijail/platform2_preinstall.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+v=$1
+include_dir=$2
+
+sed \
+  -e "s/@BSLOT@/${v}/g" \
+  -e "s:@INCLUDE_DIR@:${include_dir}:g" \
+  "libminijail.pc.in" > "libminijail.pc"
diff --git a/minijail/scoped_minijail.h b/minijail/scoped_minijail.h
new file mode 100644
index 0000000..449364f
--- /dev/null
+++ b/minijail/scoped_minijail.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <memory>
+
+#include "libminijail.h"
+
+namespace {
+struct ScopedMinijailDeleter {
+    inline void operator()(minijail *j) const {
+        if (j) {
+            minijail_destroy(j);
+        }
+    }
+};
+}
+
+using ScopedMinijail = std::unique_ptr<minijail, ScopedMinijailDeleter>;
diff --git a/minijail/signal_handler.c b/minijail/signal_handler.c
new file mode 100644
index 0000000..5a5ae9c
--- /dev/null
+++ b/minijail/signal_handler.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* These header files need to be included before asm/siginfo.h such that
+ * pid_t, timer_t, and clock_t are defined. */
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <asm/siginfo.h>
+#define __have_siginfo_t 1
+#define __have_sigval_t 1
+#define __have_sigevent_t 1
+
+#include <signal.h>
+#include <string.h>
+
+#include "signal_handler.h"
+
+#include "util.h"
+
+struct local_sigsys {
+	void		*ip;
+	int		nr;
+	unsigned int	arch;
+};
+
+void log_sigsys_handler(int nr, siginfo_t *info, void *void_context)
+{
+	struct local_sigsys sigsys;
+	const char *syscall_name;
+	memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
+	syscall_name = lookup_syscall_name(sigsys.nr);
+
+	(void) void_context;
+
+	if (syscall_name)
+		die("blocked syscall: %s", syscall_name);
+	else
+		die("blocked syscall: %d", nr);
+
+	/*
+	 * We trapped on a syscall that should have killed the process.
+	 * This should never ever return, but we're paranoid.
+	 */
+	for (;;)
+		_exit(1);
+}
+
+int install_sigsys_handler()
+{
+	int ret = 0;
+	struct sigaction act;
+	sigset_t mask;
+
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = &log_sigsys_handler;
+	act.sa_flags = SA_SIGINFO;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGSYS);
+
+	ret = sigaction(SIGSYS, &act, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
diff --git a/minijail/signal_handler.h b/minijail/signal_handler.h
new file mode 100644
index 0000000..939a582
--- /dev/null
+++ b/minijail/signal_handler.h
@@ -0,0 +1,14 @@
+/* signal_handler.h
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Signal handling functions.
+ */
+
+#ifndef SIGNAL_HANDLER_H
+#define SIGNAL_HANDLER_H
+
+int install_sigsys_handler();
+
+#endif /* SIGNAL_HANDLER_H */
diff --git a/minijail/syscall_filter.c b/minijail/syscall_filter.c
new file mode 100644
index 0000000..3fcbe4f
--- /dev/null
+++ b/minijail/syscall_filter.c
@@ -0,0 +1,571 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "syscall_filter.h"
+
+#include "util.h"
+
+#define MAX_LINE_LENGTH 	1024
+#define MAX_POLICY_LINE_LENGTH	1024
+
+#define ONE_INSTR	1
+#define TWO_INSTRS	2
+
+int seccomp_can_softfail()
+{
+#if defined(USE_SECCOMP_SOFTFAIL)
+	/*
+	 * On Android devices seccomp is allowed to soft-fail on kernels < 3.8.
+	 */
+	if (is_android()) {
+		if (kernel_lessthan_3_8())
+			return 1;
+		else
+			return 0;
+	} else {
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+int str_to_op(const char *op_str)
+{
+	if (!strcmp(op_str, "==")) {
+		return EQ;
+	} else if (!strcmp(op_str, "!=")) {
+		return NE;
+	} else if (!strcmp(op_str, "&")) {
+		return SET;
+	} else {
+		return 0;
+	}
+}
+
+struct sock_filter *new_instr_buf(size_t count)
+{
+	struct sock_filter *buf = calloc(count, sizeof(struct sock_filter));
+	if (!buf)
+		die("could not allocate BPF instruction buffer");
+
+	return buf;
+}
+
+struct filter_block *new_filter_block()
+{
+	struct filter_block *block = calloc(1, sizeof(struct filter_block));
+	if (!block)
+		die("could not allocate BPF filter block");
+
+	block->instrs = NULL;
+	block->last = block->next = NULL;
+
+	return block;
+}
+
+void append_filter_block(struct filter_block *head, struct sock_filter *instrs,
+			 size_t len)
+{
+	struct filter_block *new_last;
+
+	/*
+	 * If |head| has no filter assigned yet,
+	 * we don't create a new node.
+	 */
+	if (head->instrs == NULL) {
+		new_last = head;
+	} else {
+		new_last = new_filter_block();
+		if (head->next != NULL) {
+			head->last->next = new_last;
+			head->last = new_last;
+		} else {
+			head->last = head->next = new_last;
+		}
+		head->total_len += len;
+	}
+
+	new_last->instrs = instrs;
+	new_last->total_len = new_last->len = len;
+	new_last->last = new_last->next = NULL;
+}
+
+void extend_filter_block_list(struct filter_block *list,
+			      struct filter_block *another)
+{
+	if (list->last != NULL) {
+		list->last->next = another;
+		list->last = another->last;
+	} else {
+		list->next = another;
+		list->last = another->last;
+	}
+	list->total_len += another->total_len;
+}
+
+void append_ret_kill(struct filter_block *head)
+{
+	struct sock_filter *filter = new_instr_buf(ONE_INSTR);
+	set_bpf_ret_kill(filter);
+	append_filter_block(head, filter, ONE_INSTR);
+}
+
+void append_ret_trap(struct filter_block *head)
+{
+	struct sock_filter *filter = new_instr_buf(ONE_INSTR);
+	set_bpf_ret_trap(filter);
+	append_filter_block(head, filter, ONE_INSTR);
+}
+
+void append_ret_errno(struct filter_block *head, int errno_val)
+{
+	struct sock_filter *filter = new_instr_buf(ONE_INSTR);
+	set_bpf_ret_errno(filter, errno_val);
+	append_filter_block(head, filter, ONE_INSTR);
+}
+
+void append_allow_syscall(struct filter_block *head, int nr)
+{
+	struct sock_filter *filter = new_instr_buf(ALLOW_SYSCALL_LEN);
+	size_t len = bpf_allow_syscall(filter, nr);
+	if (len != ALLOW_SYSCALL_LEN)
+		die("error building syscall number comparison");
+
+	append_filter_block(head, filter, len);
+}
+
+void allow_log_syscalls(struct filter_block *head)
+{
+	unsigned int i;
+	for (i = 0; i < log_syscalls_len; i++) {
+		warn("allowing syscall: %s", log_syscalls[i]);
+		append_allow_syscall(head, lookup_syscall(log_syscalls[i]));
+	}
+}
+
+unsigned int get_label_id(struct bpf_labels *labels, const char *label_str)
+{
+	int label_id = bpf_label_id(labels, label_str);
+	if (label_id < 0)
+		die("could not allocate BPF label string");
+	return label_id;
+}
+
+unsigned int group_end_lbl(struct bpf_labels *labels, int nr, int idx)
+{
+	char lbl_str[MAX_BPF_LABEL_LEN];
+	snprintf(lbl_str, MAX_BPF_LABEL_LEN, "%d_%d_end", nr, idx);
+	return get_label_id(labels, lbl_str);
+}
+
+unsigned int success_lbl(struct bpf_labels *labels, int nr)
+{
+	char lbl_str[MAX_BPF_LABEL_LEN];
+	snprintf(lbl_str, MAX_BPF_LABEL_LEN, "%d_success", nr);
+	return get_label_id(labels, lbl_str);
+}
+
+int compile_atom(struct filter_block *head, char *atom,
+		 struct bpf_labels *labels, int nr, int group_idx)
+{
+	/* Splits the atom. */
+	char *atom_ptr;
+	char *argidx_str = strtok_r(atom, " ", &atom_ptr);
+	char *operator_str = strtok_r(NULL, " ", &atom_ptr);
+	char *constant_str = strtok_r(NULL, " ", &atom_ptr);
+
+	if (argidx_str == NULL || operator_str == NULL || constant_str == NULL)
+		return -1;
+
+	int op = str_to_op(operator_str);
+	if (op < MIN_OPERATOR)
+		return -1;
+
+	if (strncmp(argidx_str, "arg", 3)) {
+		return -1;
+	}
+
+	char *argidx_ptr;
+	long int argidx = strtol(argidx_str + 3, &argidx_ptr, 10);
+	/*
+	 * Checks to see if an actual argument index
+	 * was parsed.
+	 */
+	if (argidx_ptr == argidx_str + 3)
+		return -1;
+
+	char *constant_str_ptr;
+	long int c = parse_constant(constant_str, &constant_str_ptr);
+	if (constant_str_ptr == constant_str)
+		return -1;
+
+	/*
+	 * Looks up the label for the end of the AND statement
+	 * this atom belongs to.
+	 */
+	unsigned int id = group_end_lbl(labels, nr, group_idx);
+
+	/*
+	 * Builds a BPF comparison between a syscall argument
+	 * and a constant.
+	 * The comparison lives inside an AND statement.
+	 * If the comparison succeeds, we continue
+	 * to the next comparison.
+	 * If this comparison fails, the whole AND statement
+	 * will fail, so we jump to the end of this AND statement.
+	 */
+	struct sock_filter *comp_block;
+	size_t len = bpf_arg_comp(&comp_block, op, argidx, c, id);
+	if (len == 0)
+		return -1;
+
+	append_filter_block(head, comp_block, len);
+	return 0;
+}
+
+int compile_errno(struct filter_block *head, char *ret_errno,
+		  int log_failures)
+{
+	char *errno_ptr;
+
+	/* Splits the 'return' keyword and the actual errno value. */
+	char *ret_str = strtok_r(ret_errno, " ", &errno_ptr);
+	if (strncmp(ret_str, "return", strlen("return")))
+		return -1;
+
+	char *errno_val_str = strtok_r(NULL, " ", &errno_ptr);
+
+	if (errno_val_str) {
+		char *errno_val_ptr;
+		int errno_val = parse_constant(errno_val_str, &errno_val_ptr);
+		/* Checks to see if we parsed an actual errno. */
+		if (errno_val_ptr == errno_val_str || errno_val == -1)
+			return -1;
+
+		append_ret_errno(head, errno_val);
+	} else {
+		if (!log_failures)
+			append_ret_kill(head);
+		else
+			append_ret_trap(head);
+	}
+	return 0;
+}
+
+struct filter_block *compile_section(int nr, const char *policy_line,
+				     unsigned int entry_lbl_id,
+				     struct bpf_labels *labels,
+				     int log_failures)
+{
+	/*
+	 * |policy_line| should be an expression of the form:
+	 * "arg0 == 3 && arg1 == 5 || arg0 == 0x8"
+	 *
+	 * This is, an expression in DNF (disjunctive normal form);
+	 * a disjunction ('||') of one or more conjunctions ('&&')
+	 * of one or more atoms.
+	 *
+	 * Atoms are of the form "arg{DNUM} {OP} {NUM}"
+	 * where:
+	 *   - DNUM is a decimal number.
+	 *   - OP is an operator: ==, !=, or & (flags set).
+	 *   - NUM is an octal, decimal, or hexadecimal number.
+	 *
+	 * When the syscall arguments make the expression true,
+	 * the syscall is allowed. If not, the process is killed.
+	 *
+	 * To block a syscall without killing the process,
+	 * |policy_line| can be of the form:
+	 * "return <errno>"
+	 *
+	 * This "return {NUM}" policy line will block the syscall,
+	 * make it return -1 and set |errno| to NUM.
+	 *
+	 * A regular policy line can also include a "return <errno>" clause,
+	 * separated by a semicolon (';'):
+	 * "arg0 == 3 && arg1 == 5 || arg0 == 0x8; return {NUM}"
+	 *
+	 * If the syscall arguments don't make the expression true,
+	 * the syscall will be blocked as above instead of killing the process.
+	 */
+
+	size_t len = 0;
+	int group_idx = 0;
+
+	/* Checks for overly long policy lines. */
+	if (strlen(policy_line) >= MAX_POLICY_LINE_LENGTH)
+		return NULL;
+
+	/* We will modify |policy_line|, so let's make a copy. */
+	char *line = strndup(policy_line, MAX_POLICY_LINE_LENGTH);
+	if (!line)
+		return NULL;
+
+	/*
+	 * We build the filter section as a collection of smaller
+	 * "filter blocks" linked together in a singly-linked list.
+	 */
+	struct filter_block *head = new_filter_block();
+
+	/*
+	 * Filter sections begin with a label where the main filter
+	 * will jump after checking the syscall number.
+	 */
+	struct sock_filter *entry_label = new_instr_buf(ONE_INSTR);
+	set_bpf_lbl(entry_label, entry_lbl_id);
+	append_filter_block(head, entry_label, ONE_INSTR);
+
+	/* Checks whether we're unconditionally blocking this syscall. */
+	if (strncmp(line, "return", strlen("return")) == 0) {
+		if (compile_errno(head, line, log_failures) < 0)
+			return NULL;
+		free(line);
+		return head;
+	}
+
+	/* Splits the optional "return <errno>" part. */
+	char *line_ptr;
+	char *arg_filter = strtok_r(line, ";", &line_ptr);
+	char *ret_errno = strtok_r(NULL, ";", &line_ptr);
+
+	/*
+	 * Splits the policy line by '||' into conjunctions and each conjunction
+	 * by '&&' into atoms.
+	 */
+	char *arg_filter_str = arg_filter;
+	char *group;
+	while ((group = tokenize(&arg_filter_str, "||")) != NULL) {
+		char *group_str = group;
+		char *comp;
+		while ((comp = tokenize(&group_str, "&&")) != NULL) {
+			/* Compiles each atom into a BPF block. */
+			if (compile_atom(head, comp, labels, nr, group_idx) < 0)
+				return NULL;
+		}
+		/*
+		 * If the AND statement succeeds, we're done,
+		 * so jump to SUCCESS line.
+		 */
+		unsigned int id = success_lbl(labels, nr);
+		struct sock_filter *group_end_block = new_instr_buf(TWO_INSTRS);
+		len = set_bpf_jump_lbl(group_end_block, id);
+		/*
+		 * The end of each AND statement falls after the
+		 * jump to SUCCESS.
+		 */
+		id = group_end_lbl(labels, nr, group_idx++);
+		len += set_bpf_lbl(group_end_block + len, id);
+		append_filter_block(head, group_end_block, len);
+	}
+
+	/*
+	 * If no AND statements succeed, we end up here,
+	 * because we never jumped to SUCCESS.
+	 * If we have to return an errno, do it,
+	 * otherwise just kill the task.
+	 */
+	if (ret_errno) {
+		if (compile_errno(head, ret_errno, log_failures) < 0)
+			return NULL;
+	} else {
+		if (!log_failures)
+			append_ret_kill(head);
+		else
+			append_ret_trap(head);
+	}
+
+	/*
+	 * Every time the filter succeeds we jump to a predefined SUCCESS
+	 * label. Add that label and BPF RET_ALLOW code now.
+	 */
+	unsigned int id = success_lbl(labels, nr);
+	struct sock_filter *success_block = new_instr_buf(TWO_INSTRS);
+	len = set_bpf_lbl(success_block, id);
+	len += set_bpf_ret_allow(success_block + len);
+	append_filter_block(head, success_block, len);
+
+	free(line);
+	return head;
+}
+
+int compile_filter(FILE *policy_file, struct sock_fprog *prog, int log_failures)
+{
+	char line[MAX_LINE_LENGTH];
+	int line_count = 0;
+
+	struct bpf_labels labels;
+	labels.count = 0;
+
+	if (!policy_file)
+		return -1;
+
+	struct filter_block *head = new_filter_block();
+	struct filter_block *arg_blocks = NULL;
+
+	/* Start filter by validating arch. */
+	struct sock_filter *valid_arch = new_instr_buf(ARCH_VALIDATION_LEN);
+	size_t len = bpf_validate_arch(valid_arch);
+	append_filter_block(head, valid_arch, len);
+
+	/* Load syscall number. */
+	struct sock_filter *load_nr = new_instr_buf(ONE_INSTR);
+	len = bpf_load_syscall_nr(load_nr);
+	append_filter_block(head, load_nr, len);
+
+	/* If we're logging failures, allow the necessary syscalls first. */
+	if (log_failures)
+		allow_log_syscalls(head);
+
+	/*
+	 * Loop through all the lines in the policy file.
+	 * Build a jump table for the syscall number.
+	 * If the policy line has an arg filter, build the arg filter
+	 * as well.
+	 * Chain the filter sections together and dump them into
+	 * the final buffer at the end.
+	 */
+	while (fgets(line, sizeof(line), policy_file)) {
+		++line_count;
+		char *policy_line = line;
+		char *syscall_name = strsep(&policy_line, ":");
+		int nr = -1;
+
+		syscall_name = strip(syscall_name);
+
+		/* Allow comments and empty lines. */
+		if (*syscall_name == '#' || *syscall_name == '\0')
+			continue;
+
+		if (!policy_line)
+			return -1;
+
+		nr = lookup_syscall(syscall_name);
+		if (nr < 0) {
+			warn("compile_filter: nonexistent syscall '%s'",
+			     syscall_name);
+			if (log_failures) {
+				/*
+				 * If we're logging failures, assume we're in a
+				 * debugging case and continue.
+				 * This is not super risky because an invalid
+				 * syscall name is likely caused by a typo or by
+				 * leftover lines from a different architecture.
+				 * In either case, not including a policy line
+				 * is equivalent to killing the process if the
+				 * syscall is made, so there's no added attack
+				 * surface.
+				 */
+				continue;
+			}
+			return -1;
+		}
+
+		policy_line = strip(policy_line);
+
+		/*
+		 * For each syscall, add either a simple ALLOW,
+		 * or an arg filter block.
+		 */
+		if (strcmp(policy_line, "1") == 0) {
+			/* Add simple ALLOW. */
+			append_allow_syscall(head, nr);
+		} else {
+			/*
+			 * Create and jump to the label that will hold
+			 * the arg filter block.
+			 */
+			unsigned int id = bpf_label_id(&labels, syscall_name);
+			struct sock_filter *nr_comp =
+			    new_instr_buf(ALLOW_SYSCALL_LEN);
+			bpf_allow_syscall_args(nr_comp, nr, id);
+			append_filter_block(head, nr_comp, ALLOW_SYSCALL_LEN);
+
+			/* Build the arg filter block. */
+			struct filter_block *block =
+			    compile_section(nr, policy_line, id, &labels,
+					    log_failures);
+
+			if (!block)
+				return -1;
+
+			if (arg_blocks) {
+				extend_filter_block_list(arg_blocks, block);
+			} else {
+				arg_blocks = block;
+			}
+		}
+	}
+
+	/*
+	 * If none of the syscalls match, either fall back to KILL,
+	 * or return TRAP.
+	 */
+	if (!log_failures)
+		append_ret_kill(head);
+	else
+		append_ret_trap(head);
+
+	/* Allocate the final buffer, now that we know its size. */
+	size_t final_filter_len =
+	    head->total_len + (arg_blocks ? arg_blocks->total_len : 0);
+	if (final_filter_len > BPF_MAXINSNS)
+		return -1;
+
+	struct sock_filter *final_filter =
+	    calloc(final_filter_len, sizeof(struct sock_filter));
+
+	if (flatten_block_list(head, final_filter, 0, final_filter_len) < 0)
+		return -1;
+
+	if (flatten_block_list(arg_blocks, final_filter, head->total_len,
+			       final_filter_len) < 0)
+		return -1;
+
+	free_block_list(head);
+	free_block_list(arg_blocks);
+
+	bpf_resolve_jumps(&labels, final_filter, final_filter_len);
+
+	free_label_strings(&labels);
+
+	prog->filter = final_filter;
+	prog->len = final_filter_len;
+	return 0;
+}
+
+int flatten_block_list(struct filter_block *head, struct sock_filter *filter,
+		       size_t index, size_t cap)
+{
+	size_t _index = index;
+
+	struct filter_block *curr;
+	size_t i;
+
+	for (curr = head; curr; curr = curr->next) {
+		for (i = 0; i < curr->len; i++) {
+			if (_index >= cap)
+				return -1;
+			filter[_index++] = curr->instrs[i];
+		}
+	}
+	return 0;
+}
+
+void free_block_list(struct filter_block *head)
+{
+	struct filter_block *current, *prev;
+
+	current = head;
+	while (current) {
+		free(current->instrs);
+		prev = current;
+		current = current->next;
+		free(prev);
+	}
+}
diff --git a/minijail/syscall_filter.h b/minijail/syscall_filter.h
new file mode 100644
index 0000000..09c6550
--- /dev/null
+++ b/minijail/syscall_filter.h
@@ -0,0 +1,48 @@
+/* syscall_filter.h
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Syscall filter functions.
+ */
+
+#ifndef SYSCALL_FILTER_H
+#define SYSCALL_FILTER_H
+
+#include "bpf.h"
+
+#define NO_LOGGING  0
+#define USE_LOGGING 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct filter_block {
+	struct sock_filter *instrs;
+	size_t len;
+
+	struct filter_block *next;
+	struct filter_block *last;
+	size_t total_len;
+};
+
+struct bpf_labels;
+
+struct filter_block *compile_section(int nr, const char *policy_line,
+				     unsigned int label_id,
+				     struct bpf_labels *labels,
+				     int log_failures);
+int compile_filter(FILE *policy_file, struct sock_fprog *prog, int log_failures);
+
+int flatten_block_list(struct filter_block *head, struct sock_filter *filter,
+		       size_t index, size_t cap);
+void free_block_list(struct filter_block *head);
+
+int seccomp_can_softfail();
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#endif /* SYSCALL_FILTER_H */
diff --git a/minijail/syscall_filter_unittest.c b/minijail/syscall_filter_unittest.c
new file mode 100644
index 0000000..603479e
--- /dev/null
+++ b/minijail/syscall_filter_unittest.c
@@ -0,0 +1,792 @@
+/* syscall_filter_unittest.c
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Test syscall filtering.
+ */
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h>	/* For O_WRONLY. */
+
+#include "test_harness.h"
+
+#include "bpf.h"
+#include "syscall_filter.h"
+
+#include "util.h"
+
+#include "syscall_filter_unittest_macros.h"
+
+FIXTURE(bpf) {};
+
+FIXTURE_SETUP(bpf) {}
+FIXTURE_TEARDOWN(bpf) {}
+
+/* Test that setting one BPF instruction works. */
+TEST_F(bpf, set_bpf_instr) {
+	struct sock_filter instr;
+	unsigned char code = BPF_LD+BPF_W+BPF_ABS;
+	unsigned int k = 4;
+	unsigned char jt = 1, jf = 2;
+
+	size_t len = set_bpf_instr(&instr, code, k, jt, jf);
+
+	EXPECT_EQ(len, 1U);
+	EXPECT_EQ_BLOCK(&instr, code, k, jt, jf);
+}
+
+TEST_F(bpf, bpf_load_arg) {
+	struct sock_filter load_arg[BPF_LOAD_ARG_LEN];
+	int argidx = 1;
+	size_t len = bpf_load_arg(load_arg, argidx);
+
+	EXPECT_EQ(len, BPF_LOAD_ARG_LEN);
+
+#if defined(BITS32)
+	EXPECT_EQ_STMT(&load_arg[0], BPF_LD+BPF_W+BPF_ABS, LO_ARG(argidx));
+#elif defined(BITS64)
+	EXPECT_EQ_STMT(&load_arg[0], BPF_LD+BPF_W+BPF_ABS, LO_ARG(argidx));
+	EXPECT_EQ_STMT(&load_arg[1], BPF_ST, 0);
+	EXPECT_EQ_STMT(&load_arg[2], BPF_LD+BPF_W+BPF_ABS, HI_ARG(argidx));
+	EXPECT_EQ_STMT(&load_arg[3], BPF_ST, 1);
+#endif
+}
+
+TEST_F(bpf, bpf_comp_jeq) {
+	struct sock_filter comp_jeq[BPF_COMP_LEN];
+	unsigned long c = 1;
+	unsigned char jt = 1;
+	unsigned char jf = 2;
+
+	size_t len = bpf_comp_jeq(comp_jeq, c, jt, jf);
+
+	EXPECT_EQ(len, BPF_COMP_LEN);
+
+#if defined(BITS32)
+	EXPECT_EQ_BLOCK(&comp_jeq[0],
+			BPF_JMP+BPF_JEQ+BPF_K, c, jt, jf);
+#elif defined(BITS64)
+	EXPECT_EQ_BLOCK(&comp_jeq[0],
+			BPF_JMP+BPF_JEQ+BPF_K, 0, 0, jf + 2);
+	EXPECT_EQ_STMT(&comp_jeq[1], BPF_LD+BPF_MEM, 0);
+	EXPECT_EQ_BLOCK(&comp_jeq[2],
+			BPF_JMP+BPF_JEQ+BPF_K, c, jt, jf);
+#endif
+}
+
+TEST_F(bpf, bpf_comp_jset) {
+	struct sock_filter comp_jset[BPF_COMP_LEN];
+	unsigned long mask = O_WRONLY;
+	unsigned char jt = 1;
+	unsigned char jf = 2;
+
+	size_t len = bpf_comp_jset(comp_jset, mask, jt, jf);
+
+	EXPECT_EQ(len, BPF_COMP_LEN);
+
+#if defined(BITS32)
+	EXPECT_EQ_BLOCK(&comp_jset[0],
+			BPF_JMP+BPF_JSET+BPF_K, mask, jt, jf);
+#elif defined(BITS64)
+	EXPECT_EQ_BLOCK(&comp_jset[0],
+			BPF_JMP+BPF_JSET+BPF_K, 0, jt + 2, 0);
+	EXPECT_EQ_STMT(&comp_jset[1], BPF_LD+BPF_MEM, 0);
+	EXPECT_EQ_BLOCK(&comp_jset[2],
+			BPF_JMP+BPF_JSET+BPF_K, mask, jt, jf);
+#endif
+}
+
+TEST_F(bpf, bpf_arg_comp) {
+	struct sock_filter *arg_comp;
+	int op = EQ;
+	int argidx = 1;
+	unsigned long c = 3;
+	unsigned int label_id = 0;
+
+	size_t len = bpf_arg_comp(&arg_comp, op, argidx, c, label_id);
+
+	EXPECT_EQ(len, BPF_ARG_COMP_LEN + 1);
+
+#if defined(BITS32)
+	EXPECT_EQ_STMT(&arg_comp[0],
+			BPF_LD+BPF_W+BPF_ABS, LO_ARG(argidx));
+	EXPECT_EQ_BLOCK(&arg_comp[1],
+			BPF_JMP+BPF_JEQ+BPF_K, c, 1, 0);
+	EXPECT_JUMP_LBL(&arg_comp[2]);
+#elif defined(BITS64)
+	EXPECT_EQ_STMT(&arg_comp[0],
+			BPF_LD+BPF_W+BPF_ABS, LO_ARG(argidx));
+	EXPECT_EQ_STMT(&arg_comp[1], BPF_ST, 0);
+	EXPECT_EQ_STMT(&arg_comp[2],
+			BPF_LD+BPF_W+BPF_ABS, HI_ARG(argidx));
+	EXPECT_EQ_STMT(&arg_comp[3], BPF_ST, 1);
+
+	EXPECT_EQ_BLOCK(&arg_comp[4],
+			BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2);
+	EXPECT_EQ_STMT(&arg_comp[5], BPF_LD+BPF_MEM, 0);
+	EXPECT_EQ_BLOCK(&arg_comp[6],
+			BPF_JMP+BPF_JEQ+BPF_K, c, 1, 0);
+	EXPECT_JUMP_LBL(&arg_comp[7]);
+#endif
+	free(arg_comp);
+}
+
+TEST_F(bpf, bpf_validate_arch) {
+	struct sock_filter validate_arch[ARCH_VALIDATION_LEN];
+
+	size_t len = bpf_validate_arch(validate_arch);
+
+	EXPECT_EQ(len, ARCH_VALIDATION_LEN);
+	EXPECT_ARCH_VALIDATION(validate_arch);
+}
+
+TEST_F(bpf, bpf_allow_syscall) {
+	struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
+	int nr = 1;
+
+	size_t len = bpf_allow_syscall(allow_syscall, nr);
+
+	EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
+	EXPECT_ALLOW_SYSCALL(allow_syscall, nr);
+}
+
+TEST_F(bpf, bpf_allow_syscall_args) {
+	struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
+	int nr = 1;
+	unsigned int id = 1024;
+
+	size_t len = bpf_allow_syscall_args(allow_syscall, nr, id);
+
+	EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
+	EXPECT_ALLOW_SYSCALL_ARGS(allow_syscall, nr, id, JUMP_JT, JUMP_JF);
+}
+
+FIXTURE(arg_filter) {
+	struct bpf_labels labels;
+};
+
+FIXTURE_SETUP(arg_filter) {}
+FIXTURE_TEARDOWN(arg_filter) {
+	free_label_strings(&self->labels);
+}
+
+TEST_F(arg_filter, arg0_equals) {
+	const char *fragment = "arg0 == 0";
+	int nr = 1;
+	unsigned int id = 0;
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison. */
+	curr_block = block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Third block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Fourth block is SECCOMP_RET_KILL. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_KILL(curr_block);
+
+	/* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+}
+
+TEST_F(arg_filter, arg0_mask) {
+	const char *fragment = "arg1 & O_RDWR";
+	int nr = 1;
+	unsigned int id = 0;
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison. */
+	curr_block = block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Third block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Fourth block is SECCOMP_RET_KILL. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_KILL(curr_block);
+
+	/* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+}
+
+TEST_F(arg_filter, arg0_eq_mask) {
+	const char *fragment = "arg1 == O_WRONLY|O_CREAT";
+	int nr = 1;
+	unsigned int id = 0;
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison. */
+	curr_block = block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+	EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN  - 1].k,
+		(unsigned int)(O_WRONLY | O_CREAT));
+
+	/* Third block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Fourth block is SECCOMP_RET_KILL. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_KILL(curr_block);
+
+	/* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+}
+
+TEST_F(arg_filter, and_or) {
+	const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
+	int nr = 1;
+	unsigned int id = 0;
+
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison ("arg0 == 0"). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Third block is a comparison ("arg1 == 0"). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Fourth block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Fifth block is a comparison ("arg0 == 1"). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Sixth block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Seventh block is SECCOMP_RET_KILL. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_KILL(curr_block);
+
+	/* Eigth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+	free_label_strings(&self->labels);
+}
+
+TEST_F(arg_filter, ret_errno) {
+	const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
+	int nr = 1;
+	unsigned int id = 0;
+
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison ("arg0 == 0"). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Third block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Fourth block is a comparison ("arg0 == 1"). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Fifth block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Sixth block is SECCOMP_RET_ERRNO. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(curr_block->len, 1U);
+	EXPECT_EQ_STMT(curr_block->instrs,
+			BPF_RET+BPF_K,
+			SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
+
+	/* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+	free_label_strings(&self->labels);
+}
+
+TEST_F(arg_filter, unconditional_errno) {
+	const char *fragment = "return 1";
+	int nr = 1;
+	unsigned int id = 0;
+
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is SECCOMP_RET_ERRNO. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(curr_block->len, 1U);
+	EXPECT_EQ_STMT(curr_block->instrs,
+			BPF_RET+BPF_K,
+			SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+	free_label_strings(&self->labels);
+}
+
+TEST_F(arg_filter, invalid) {
+	const char *fragment = "argnn == 0";
+	int nr = 1;
+	unsigned int id = 0;
+
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+	ASSERT_EQ(block, NULL);
+
+	fragment = "arg0 == 0 && arg1 == 1; return errno";
+	block = compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+	ASSERT_EQ(block, NULL);
+}
+
+TEST_F(arg_filter, log_no_ret_error) {
+	const char *fragment = "arg0 == 0";
+	int nr = 1;
+	unsigned int id = 0;
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, USE_LOGGING);
+
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison. */
+	curr_block = block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Third block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/* Fourth block is SECCOMP_RET_TRAP, with no errno. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_TRAP(curr_block);
+
+	/* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+	free_label_strings(&self->labels);
+}
+
+TEST_F(arg_filter, log_bad_ret_error) {
+	const char *fragment = "arg0 == 0; return";
+	int nr = 1;
+	unsigned int id = 0;
+
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison ("arg0 == 0"). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Third block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/*
+	 * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_KILL.
+	 */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_KILL(curr_block);
+
+	/* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+	free_label_strings(&self->labels);
+}
+
+TEST_F(arg_filter, no_log_bad_ret_error) {
+	const char *fragment = "arg0 == 0; return";
+	int nr = 1;
+	unsigned int id = 0;
+
+	struct filter_block *block =
+		compile_section(nr, fragment, id, &self->labels, USE_LOGGING);
+	ASSERT_NE(block, NULL);
+	size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+	EXPECT_EQ(block->total_len, exp_total_len);
+
+	/* First block is a label. */
+	struct filter_block *curr_block = block;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_EQ(block->len, 1U);
+	EXPECT_LBL(curr_block->instrs);
+
+	/* Second block is a comparison ("arg0 == 0"). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_COMP(curr_block);
+
+	/* Third block is a jump and a label (end of AND group). */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_GROUP_END(curr_block);
+
+	/*
+	 * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_TRAP.
+	 */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_TRAP(curr_block);
+
+	/* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+	curr_block = curr_block->next;
+	ASSERT_NE(curr_block, NULL);
+	EXPECT_ALLOW(curr_block);
+
+	EXPECT_EQ(curr_block->next, NULL);
+
+	free_block_list(block);
+	free_label_strings(&self->labels);
+}
+
+FIXTURE(filter) {};
+
+FIXTURE_SETUP(filter) {}
+FIXTURE_TEARDOWN(filter) {}
+
+FILE *write_policy_to_pipe(const char *policy, size_t len) {
+	int pipefd[2];
+	if (pipe(pipefd) == -1) {
+		pwarn("pipe(pipefd) failed");
+		return NULL;
+	}
+
+	size_t i = 0;
+	unsigned int attempts = 0;
+	ssize_t ret;
+	while (i < len) {
+		ret = write(pipefd[1], &policy[i], len - i);
+		if (ret == -1) {
+			close(pipefd[0]);
+			close(pipefd[1]);
+			return NULL;
+		}
+
+		/* If we write 0 bytes three times in a row, fail. */
+		if (ret == 0) {
+			if (++attempts >= 3) {
+				close(pipefd[0]);
+				close(pipefd[1]);
+				warn("write() returned 0 three times in a row");
+				return NULL;
+			}
+			continue;
+		}
+
+		attempts = 0;
+		i += (size_t)ret;
+	}
+
+	close(pipefd[1]);
+	return fdopen(pipefd[0], "r");
+}
+
+TEST_F(filter, seccomp_mode1) {
+	struct sock_fprog actual;
+	const char *policy =
+		"read: 1\n"
+		"write: 1\n"
+		"rt_sigreturn: 1\n"
+		"exit: 1\n";
+
+	FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+	ASSERT_NE(policy_file, NULL);
+
+	int res = compile_filter(policy_file, &actual, NO_LOGGING);
+	fclose(policy_file);
+
+	/*
+	 * Checks return value, filter length, and that the filter
+	 * validates arch, loads syscall number, and
+	 * only allows expected syscalls.
+	 */
+	ASSERT_EQ(res, 0);
+	EXPECT_EQ(actual.len, 13);
+	EXPECT_ARCH_VALIDATION(actual.filter);
+	EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
+			BPF_LD+BPF_W+BPF_ABS, syscall_nr);
+	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1,
+			__NR_read);
+	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3,
+			__NR_write);
+	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
+			__NR_rt_sigreturn);
+	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
+			__NR_exit);
+	EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
+			SECCOMP_RET_KILL);
+
+	free(actual.filter);
+}
+
+TEST_F(filter, seccomp_read_write) {
+	struct sock_fprog actual;
+	const char *policy =
+		"read: arg0 == 0\n"
+		"write: arg0 == 1 || arg0 == 2\n"
+		"rt_sigreturn: 1\n"
+		"exit: 1\n";
+
+	FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+	ASSERT_NE(policy_file, NULL);
+
+	int res = compile_filter(policy_file, &actual, NO_LOGGING);
+	fclose(policy_file);
+
+	/*
+	 * Checks return value, filter length, and that the filter
+	 * validates arch, loads syscall number, and
+	 * only allows expected syscalls, jumping to correct arg filter
+	 * offsets.
+	 */
+	ASSERT_EQ(res, 0);
+	size_t exp_total_len = 27 + 3 * (BPF_ARG_COMP_LEN + 1);
+	EXPECT_EQ(actual.len, exp_total_len);
+
+	EXPECT_ARCH_VALIDATION(actual.filter);
+	EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
+			BPF_LD+BPF_W+BPF_ABS, syscall_nr);
+	EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 1,
+			__NR_read, 7, 0, 0);
+	EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 3,
+			__NR_write, 12 + BPF_ARG_COMP_LEN, 0, 0);
+	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
+			__NR_rt_sigreturn);
+	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
+			__NR_exit);
+	EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
+			SECCOMP_RET_KILL);
+
+	free(actual.filter);
+}
+
+TEST_F(filter, invalid_name) {
+	struct sock_fprog actual;
+	const char *policy = "notasyscall: 1\n";
+
+	FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+	ASSERT_NE(policy_file, NULL);
+
+	int res = compile_filter(policy_file, &actual, NO_LOGGING);
+	fclose(policy_file);
+	ASSERT_NE(res, 0);
+}
+
+TEST_F(filter, invalid_arg) {
+	struct sock_fprog actual;
+	const char *policy = "open: argnn ==\n";
+
+	FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+	ASSERT_NE(policy_file, NULL);
+
+	int res = compile_filter(policy_file, &actual, NO_LOGGING);
+	fclose(policy_file);
+	ASSERT_NE(res, 0);
+}
+
+TEST_F(filter, nonexistent) {
+	struct sock_fprog actual;
+	int res = compile_filter(NULL, &actual, NO_LOGGING);
+	ASSERT_NE(res, 0);
+}
+
+TEST_F(filter, log) {
+	struct sock_fprog actual;
+	const char *policy =
+		"read: 1\n"
+		"write: 1\n"
+		"rt_sigreturn: 1\n"
+		"exit: 1\n";
+
+	FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+	ASSERT_NE(policy_file, NULL);
+
+	int res = compile_filter(policy_file, &actual, USE_LOGGING);
+	fclose(policy_file);
+
+	size_t i;
+	size_t index = 0;
+	/*
+	 * Checks return value, filter length, and that the filter
+	 * validates arch, loads syscall number, only allows expected syscalls,
+	 * and returns TRAP on failure.
+	 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
+	 * for logging.
+	 */
+	ASSERT_EQ(res, 0);
+	EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
+	EXPECT_ARCH_VALIDATION(actual.filter);
+	EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
+			BPF_LD+BPF_W+BPF_ABS, syscall_nr);
+
+	index = ARCH_VALIDATION_LEN + 1;
+	for (i = 0; i < log_syscalls_len; i++)
+		EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
+				     lookup_syscall(log_syscalls[i]));
+
+	index += 2 * log_syscalls_len;
+
+	EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
+	EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
+	EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
+	EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
+	EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET+BPF_K,
+			SECCOMP_RET_TRAP);
+
+	free(actual.filter);
+}
+
+TEST_HARNESS_MAIN
diff --git a/minijail/syscall_filter_unittest.cpp b/minijail/syscall_filter_unittest.cpp
new file mode 100644
index 0000000..09e98f6
--- /dev/null
+++ b/minijail/syscall_filter_unittest.cpp
@@ -0,0 +1,769 @@
+// syscall_filter_unittest.cpp
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Test syscall filtering using gtest.
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h> /* For O_WRONLY. */
+
+#include <gtest/gtest.h>
+
+#include "bpf.h"
+#include "syscall_filter.h"
+#include "syscall_filter_unittest_macros.h"
+#include "util.h"
+
+/* Test that setting one BPF instruction works. */
+TEST(bpf, set_bpf_instr) {
+  struct sock_filter instr;
+  unsigned char code = BPF_LD + BPF_W + BPF_ABS;
+  unsigned int k = 4;
+  unsigned char jt = 1, jf = 2;
+
+  size_t len = set_bpf_instr(&instr, code, k, jt, jf);
+
+  EXPECT_EQ(len, 1U);
+  EXPECT_EQ_BLOCK(&instr, code, k, jt, jf);
+}
+
+TEST(bpf, bpf_load_arg) {
+  struct sock_filter load_arg[BPF_LOAD_ARG_LEN];
+  int argidx = 1;
+  size_t len = bpf_load_arg(load_arg, argidx);
+
+  EXPECT_EQ(len, BPF_LOAD_ARG_LEN);
+
+#if defined(BITS32)
+  EXPECT_EQ_STMT(&load_arg[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
+#elif defined(BITS64)
+  EXPECT_EQ_STMT(&load_arg[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
+  EXPECT_EQ_STMT(&load_arg[1], BPF_ST, 0);
+  EXPECT_EQ_STMT(&load_arg[2], BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx));
+  EXPECT_EQ_STMT(&load_arg[3], BPF_ST, 1);
+#endif
+}
+
+TEST(bpf, bpf_comp_jeq) {
+  struct sock_filter comp_jeq[BPF_COMP_LEN];
+  unsigned long c = 1;
+  unsigned char jt = 1;
+  unsigned char jf = 2;
+
+  size_t len = bpf_comp_jeq(comp_jeq, c, jt, jf);
+
+  EXPECT_EQ(len, BPF_COMP_LEN);
+
+#if defined(BITS32)
+  EXPECT_EQ_BLOCK(&comp_jeq[0], BPF_JMP + BPF_JEQ + BPF_K, c, jt, jf);
+#elif defined(BITS64)
+  EXPECT_EQ_BLOCK(&comp_jeq[0], BPF_JMP + BPF_JEQ + BPF_K, 0, 0, jf + 2);
+  EXPECT_EQ_STMT(&comp_jeq[1], BPF_LD + BPF_MEM, 0);
+  EXPECT_EQ_BLOCK(&comp_jeq[2], BPF_JMP + BPF_JEQ + BPF_K, c, jt, jf);
+#endif
+}
+
+TEST(bpf, bpf_comp_jset) {
+  struct sock_filter comp_jset[BPF_COMP_LEN];
+  unsigned long mask = O_WRONLY;
+  unsigned char jt = 1;
+  unsigned char jf = 2;
+
+  size_t len = bpf_comp_jset(comp_jset, mask, jt, jf);
+
+  EXPECT_EQ(len, BPF_COMP_LEN);
+
+#if defined(BITS32)
+  EXPECT_EQ_BLOCK(&comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, mask, jt, jf);
+#elif defined(BITS64)
+  EXPECT_EQ_BLOCK(&comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, 0, jt + 2, 0);
+  EXPECT_EQ_STMT(&comp_jset[1], BPF_LD + BPF_MEM, 0);
+  EXPECT_EQ_BLOCK(&comp_jset[2], BPF_JMP + BPF_JSET + BPF_K, mask, jt, jf);
+#endif
+}
+
+TEST(bpf, bpf_arg_comp) {
+  struct sock_filter *arg_comp;
+  int op = EQ;
+  int argidx = 1;
+  unsigned long c = 3;
+  unsigned int label_id = 0;
+
+  size_t len = bpf_arg_comp(&arg_comp, op, argidx, c, label_id);
+
+  EXPECT_EQ(len, BPF_ARG_COMP_LEN + 1);
+
+#if defined(BITS32)
+  EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
+  EXPECT_EQ_BLOCK(&arg_comp[1], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
+  EXPECT_JUMP_LBL(&arg_comp[2]);
+#elif defined(BITS64)
+  EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
+  EXPECT_EQ_STMT(&arg_comp[1], BPF_ST, 0);
+  EXPECT_EQ_STMT(&arg_comp[2], BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx));
+  EXPECT_EQ_STMT(&arg_comp[3], BPF_ST, 1);
+
+  EXPECT_EQ_BLOCK(&arg_comp[4], BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 2);
+  EXPECT_EQ_STMT(&arg_comp[5], BPF_LD + BPF_MEM, 0);
+  EXPECT_EQ_BLOCK(&arg_comp[6], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
+  EXPECT_JUMP_LBL(&arg_comp[7]);
+#endif
+  free(arg_comp);
+}
+
+TEST(bpf, bpf_validate_arch) {
+  struct sock_filter validate_arch[ARCH_VALIDATION_LEN];
+
+  size_t len = bpf_validate_arch(validate_arch);
+
+  EXPECT_EQ(len, ARCH_VALIDATION_LEN);
+  EXPECT_ARCH_VALIDATION(validate_arch);
+}
+
+TEST(bpf, bpf_allow_syscall) {
+  struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
+  int nr = 1;
+
+  size_t len = bpf_allow_syscall(allow_syscall, nr);
+
+  EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
+  EXPECT_ALLOW_SYSCALL(allow_syscall, nr);
+}
+
+TEST(bpf, bpf_allow_syscall_args) {
+  struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
+  int nr = 1;
+  unsigned int id = 1024;
+
+  size_t len = bpf_allow_syscall_args(allow_syscall, nr, id);
+
+  EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
+  EXPECT_ALLOW_SYSCALL_ARGS(allow_syscall, nr, id, JUMP_JT, JUMP_JF);
+}
+
+class ArgFilterTest : public ::testing::Test {
+ protected:
+  virtual void TearDown() { free_label_strings(&labels_); }
+  struct bpf_labels labels_;
+};
+
+TEST_F(ArgFilterTest, arg0_equals) {
+  const char *fragment = "arg0 == 0";
+  int nr = 1;
+  unsigned int id = 0;
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison. */
+  curr_block = block->next;
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Fourth block is SECCOMP_RET_KILL. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_KILL(curr_block);
+
+  /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, arg0_mask) {
+  const char *fragment = "arg1 & O_RDWR";
+  int nr = 1;
+  unsigned int id = 0;
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison. */
+  curr_block = block->next;
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Fourth block is SECCOMP_RET_KILL. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_KILL(curr_block);
+
+  /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, arg0_eq_mask) {
+  const char *fragment = "arg1 == O_WRONLY|O_CREAT";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison. */
+  curr_block = block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+  EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
+            (unsigned int)(O_WRONLY | O_CREAT));
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Fourth block is SECCOMP_RET_KILL. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_KILL(curr_block);
+
+  /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, and_or) {
+  const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison ("arg0 == 0"). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a comparison ("arg1 == 0"). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Fourth block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Fifth block is a comparison ("arg0 == 1"). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Sixth block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Seventh block is SECCOMP_RET_KILL. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_KILL(curr_block);
+
+  /* Eigth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, ret_errno) {
+  const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison ("arg0 == 0"). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Fourth block is a comparison ("arg0 == 1"). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Fifth block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Sixth block is SECCOMP_RET_ERRNO. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(curr_block->len, 1U);
+  EXPECT_EQ_STMT(curr_block->instrs,
+                 BPF_RET + BPF_K,
+                 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
+
+  /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, unconditional_errno) {
+  const char *fragment = "return 1";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is SECCOMP_RET_ERRNO. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(curr_block->len, 1U);
+  EXPECT_EQ_STMT(curr_block->instrs,
+                 BPF_RET + BPF_K,
+                 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, invalid) {
+  const char *fragment = "argnn == 0";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+  ASSERT_TRUE(block == NULL);
+
+  fragment = "arg0 == 0 && arg1 == 1; return errno";
+  block = compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+  ASSERT_TRUE(block == NULL);
+}
+
+TEST_F(ArgFilterTest, log_no_ret_error) {
+  const char *fragment = "arg0 == 0";
+  int nr = 1;
+  unsigned int id = 0;
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, USE_LOGGING);
+
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison. */
+  curr_block = block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Fourth block is SECCOMP_RET_TRAP, with no errno. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_TRAP(curr_block);
+
+  /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, log_bad_ret_error) {
+  const char *fragment = "arg0 == 0; return";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison ("arg0 == 0"). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /*
+   * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_KILL.
+   */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_KILL(curr_block);
+
+  /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+TEST_F(ArgFilterTest, no_log_bad_ret_error) {
+  const char *fragment = "arg0 == 0; return";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block *block =
+      compile_section(nr, fragment, id, &labels_, USE_LOGGING);
+  ASSERT_TRUE(block != NULL);
+  size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+  EXPECT_EQ(block->total_len, exp_total_len);
+
+  /* First block is a label. */
+  struct filter_block *curr_block = block;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_EQ(block->len, 1U);
+  EXPECT_LBL(curr_block->instrs);
+
+  /* Second block is a comparison ("arg0 == 0"). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_GROUP_END(curr_block);
+
+  /*
+   * Sixth block is *not* SECCOMP_RET_ERRNO, it should be
+   * SECCOMP_RET_TRAP.
+   */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_TRAP(curr_block);
+
+  /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_TRUE(curr_block != NULL);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_TRUE(curr_block->next == NULL);
+
+  free_block_list(block);
+}
+
+FILE *write_policy_to_pipe(const char *policy, size_t len) {
+  int pipefd[2];
+  if (pipe(pipefd) == -1) {
+    pwarn("pipe(pipefd) failed");
+    return NULL;
+  }
+
+  size_t i = 0;
+  unsigned int attempts = 0;
+  ssize_t ret;
+  while (i < len) {
+    ret = write(pipefd[1], &policy[i], len - i);
+    if (ret == -1) {
+      close(pipefd[0]);
+      close(pipefd[1]);
+      return NULL;
+    }
+
+    /* If we write 0 bytes three times in a row, fail. */
+    if (ret == 0) {
+      if (++attempts >= 3) {
+        close(pipefd[0]);
+        close(pipefd[1]);
+        warn("write() returned 0 three times in a row");
+        return NULL;
+      }
+      continue;
+    }
+
+    attempts = 0;
+    i += (size_t)ret;
+  }
+
+  close(pipefd[1]);
+  return fdopen(pipefd[0], "r");
+}
+
+TEST(FilterTest, seccomp_mode1) {
+  struct sock_fprog actual;
+  const char *policy =
+      "read: 1\n"
+      "write: 1\n"
+      "rt_sigreturn: 1\n"
+      "exit: 1\n";
+
+  FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_TRUE(policy_file != NULL);
+
+  int res = compile_filter(policy_file, &actual, NO_LOGGING);
+  fclose(policy_file);
+
+  /*
+   * Checks return value, filter length, and that the filter
+   * validates arch, loads syscall number, and
+   * only allows expected syscalls.
+   */
+  ASSERT_EQ(res, 0);
+  EXPECT_EQ(actual.len, 13);
+  EXPECT_ARCH_VALIDATION(actual.filter);
+  EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
+                 BPF_LD + BPF_W + BPF_ABS,
+                 syscall_nr);
+  EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read);
+  EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3, __NR_write);
+  EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
+                       __NR_rt_sigreturn);
+  EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
+  EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
+                 BPF_RET + BPF_K,
+                 SECCOMP_RET_KILL);
+
+  free(actual.filter);
+}
+
+TEST(FilterTest, seccomp_read_write) {
+  struct sock_fprog actual;
+  const char *policy =
+      "read: arg0 == 0\n"
+      "write: arg0 == 1 || arg0 == 2\n"
+      "rt_sigreturn: 1\n"
+      "exit: 1\n";
+
+  FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_TRUE(policy_file != NULL);
+
+  int res = compile_filter(policy_file, &actual, NO_LOGGING);
+  fclose(policy_file);
+
+  /*
+   * Checks return value, filter length, and that the filter
+   * validates arch, loads syscall number, and
+   * only allows expected syscalls, jumping to correct arg filter
+   * offsets.
+   */
+  ASSERT_EQ(res, 0);
+  size_t exp_total_len = 27 + 3 * (BPF_ARG_COMP_LEN + 1);
+  EXPECT_EQ(actual.len, exp_total_len);
+
+  EXPECT_ARCH_VALIDATION(actual.filter);
+  EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
+                 BPF_LD + BPF_W + BPF_ABS,
+                 syscall_nr);
+  EXPECT_ALLOW_SYSCALL_ARGS(
+      actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read, 7, 0, 0);
+  EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 3,
+                            __NR_write,
+                            12 + BPF_ARG_COMP_LEN,
+                            0,
+                            0);
+  EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
+                       __NR_rt_sigreturn);
+  EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
+  EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
+                 BPF_RET + BPF_K,
+                 SECCOMP_RET_KILL);
+
+  free(actual.filter);
+}
+
+TEST(FilterTest, invalid_name) {
+  struct sock_fprog actual;
+  const char *policy = "notasyscall: 1\n";
+
+  FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_TRUE(policy_file != NULL);
+
+  int res = compile_filter(policy_file, &actual, NO_LOGGING);
+  fclose(policy_file);
+  ASSERT_NE(res, 0);
+}
+
+TEST(FilterTest, invalid_arg) {
+  struct sock_fprog actual;
+  const char *policy = "open: argnn ==\n";
+
+  FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_TRUE(policy_file != NULL);
+
+  int res = compile_filter(policy_file, &actual, NO_LOGGING);
+  fclose(policy_file);
+  ASSERT_NE(res, 0);
+}
+
+TEST(FilterTest, nonexistent) {
+  struct sock_fprog actual;
+  int res = compile_filter(NULL, &actual, NO_LOGGING);
+  ASSERT_NE(res, 0);
+}
+
+TEST(FilterTest, log) {
+  struct sock_fprog actual;
+  const char *policy =
+      "read: 1\n"
+      "write: 1\n"
+      "rt_sigreturn: 1\n"
+      "exit: 1\n";
+
+  FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_TRUE(policy_file != NULL);
+
+  int res = compile_filter(policy_file, &actual, USE_LOGGING);
+  fclose(policy_file);
+
+  size_t i;
+  size_t index = 0;
+  /*
+   * Checks return value, filter length, and that the filter
+   * validates arch, loads syscall number, only allows expected syscalls,
+   * and returns TRAP on failure.
+   * NOTE(jorgelo): the filter is longer since we add the syscalls needed
+   * for logging.
+   */
+  ASSERT_EQ(res, 0);
+  EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
+  EXPECT_ARCH_VALIDATION(actual.filter);
+  EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
+                 BPF_LD + BPF_W + BPF_ABS,
+                 syscall_nr);
+
+  index = ARCH_VALIDATION_LEN + 1;
+  for (i = 0; i < log_syscalls_len; i++)
+    EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
+                         lookup_syscall(log_syscalls[i]));
+
+  index += 2 * log_syscalls_len;
+
+  EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
+  EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
+  EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
+  EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
+  EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET + BPF_K, SECCOMP_RET_TRAP);
+
+  free(actual.filter);
+}
diff --git a/minijail/syscall_filter_unittest_macros.h b/minijail/syscall_filter_unittest_macros.h
new file mode 100644
index 0000000..ec86374
--- /dev/null
+++ b/minijail/syscall_filter_unittest_macros.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* BPF testing macros. */
+#define EXPECT_EQ_BLOCK(_block, _code, _k, _jt, _jf)	\
+do {	\
+	EXPECT_EQ((_block)->code, _code);		\
+	EXPECT_EQ((_block)->k, (unsigned int)(_k));	\
+	EXPECT_EQ((_block)->jt, _jt);			\
+	EXPECT_EQ((_block)->jf, _jf);			\
+} while (0)
+
+#define EXPECT_EQ_STMT(_block, _code, _k) \
+	EXPECT_EQ_BLOCK(_block, _code, _k, 0, 0)
+
+#define EXPECT_COMP(_block) \
+do {	\
+	EXPECT_EQ((_block)->len, BPF_ARG_COMP_LEN + 1);			\
+	EXPECT_EQ((_block)->instrs->code, BPF_LD+BPF_W+BPF_ABS);	\
+} while (0)
+
+#define EXPECT_LBL(_block) \
+do {	\
+	EXPECT_TRUE((_block)->code == (BPF_JMP+BPF_JA));	\
+	EXPECT_TRUE((_block)->jt == LABEL_JT);			\
+	EXPECT_TRUE((_block)->jf == LABEL_JF);			\
+} while (0)
+
+#define EXPECT_JUMP_LBL(_block) \
+do {	\
+	EXPECT_EQ((_block)->code, BPF_JMP+BPF_JA);	\
+	EXPECT_EQ((_block)->jt, JUMP_JT);		\
+	EXPECT_EQ((_block)->jf, JUMP_JF);		\
+} while (0)
+
+#define EXPECT_GROUP_END(_block) \
+do {	\
+	EXPECT_EQ((_block)->len, 2U);			\
+	EXPECT_JUMP_LBL(&(_block)->instrs[0]);		\
+	EXPECT_LBL(&(_block)->instrs[1]);		\
+} while (0)
+
+#define EXPECT_KILL(_block) \
+do {	\
+	EXPECT_EQ((_block)->len, 1U);				\
+	EXPECT_EQ_STMT((_block)->instrs,			\
+			BPF_RET+BPF_K, SECCOMP_RET_KILL);	\
+} while (0)
+
+#define EXPECT_TRAP(_block) \
+do {	\
+	EXPECT_EQ((_block)->len, 1U);				\
+	EXPECT_EQ_STMT((_block)->instrs,			\
+			BPF_RET+BPF_K, SECCOMP_RET_TRAP);	\
+} while (0)
+
+#define EXPECT_ALLOW(_block) \
+do {	\
+	EXPECT_EQ((_block)->len, 2U);				\
+	EXPECT_LBL(&(_block)->instrs[0]);			\
+	EXPECT_EQ_STMT(&(_block)->instrs[1],			\
+			BPF_RET+BPF_K, SECCOMP_RET_ALLOW);	\
+} while (0)
+
+#define EXPECT_ARCH_VALIDATION(_filter) \
+do {	\
+	EXPECT_EQ_STMT(&(_filter)[0], BPF_LD+BPF_W+BPF_ABS, arch_nr);	\
+	EXPECT_EQ_BLOCK(&(_filter)[1],					\
+			BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, SKIP, NEXT);	\
+	EXPECT_EQ_STMT(&(_filter)[2], BPF_RET+BPF_K, SECCOMP_RET_KILL);	\
+} while (0)
+
+#define EXPECT_ALLOW_SYSCALL(_filter, _nr) \
+do {	\
+	EXPECT_EQ_BLOCK(&(_filter)[0],					\
+			BPF_JMP+BPF_JEQ+BPF_K, (_nr), NEXT, SKIP);	\
+	EXPECT_EQ_STMT(&(_filter)[1],					\
+			BPF_RET+BPF_K, SECCOMP_RET_ALLOW);		\
+} while (0)
+
+#define EXPECT_ALLOW_SYSCALL_ARGS(_filter, _nr, _id, _jt, _jf) \
+do {	\
+	EXPECT_EQ_BLOCK(&(_filter)[0],					\
+			BPF_JMP+BPF_JEQ+BPF_K, (_nr), NEXT, SKIP);	\
+	EXPECT_EQ_BLOCK(&(_filter)[1],					\
+			BPF_JMP+BPF_JA, (_id), (_jt), (_jf));		\
+} while (0)
diff --git a/minijail/test/.clang-format b/minijail/test/.clang-format
new file mode 100644
index 0000000..c98efc2
--- /dev/null
+++ b/minijail/test/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+BinPackArguments: false
+BinPackParameters: false
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+PointerAlignment: Left
+TabWidth: 2
diff --git a/minijail/test/invalid_arg_filter.policy b/minijail/test/invalid_arg_filter.policy
new file mode 100644
index 0000000..b79b31a
--- /dev/null
+++ b/minijail/test/invalid_arg_filter.policy
@@ -0,0 +1 @@
+open: argnn ==
diff --git a/minijail/test/invalid_syscall_name.policy b/minijail/test/invalid_syscall_name.policy
new file mode 100644
index 0000000..3e6d403
--- /dev/null
+++ b/minijail/test/invalid_syscall_name.policy
@@ -0,0 +1 @@
+notasyscall: 1
diff --git a/minijail/test/libminijail_test.cpp b/minijail/test/libminijail_test.cpp
new file mode 100644
index 0000000..6499a37
--- /dev/null
+++ b/minijail/test/libminijail_test.cpp
@@ -0,0 +1,134 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <sys/capability.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libminijail.h>
+
+#include <android-base/logging.h>
+
+const uid_t kSystemUid = 1000U;
+
+gid_t groups[] = {kSystemUid + 1, kSystemUid + 2};
+
+size_t getgroups_with_alloc(gid_t** plist) {
+  *plist = NULL;
+
+  int nsupp_groups = getgroups(0, NULL);
+  if (nsupp_groups < 0) {
+    PLOG(ERROR) << "getgroups(0)";
+    return 0;
+  }
+  if (nsupp_groups == 0) {
+    LOG(INFO) << "No supplementary groups.";
+    return 0;
+  }
+
+  *plist = (gid_t*)calloc((size_t)nsupp_groups, sizeof(gid_t));
+  nsupp_groups = getgroups(nsupp_groups, *plist);
+  if (nsupp_groups < 0) {
+    PLOG(ERROR) << "getgroups(nsupp_groups)";
+    free(*plist);
+    return 0;
+  }
+  return nsupp_groups;
+}
+
+bool check_ugid(uid_t expected_id) {
+  bool success = true;
+
+  uid_t ruid = getuid();
+  if (ruid != expected_id) {
+    LOG(ERROR) << "rUID " << ruid << " is not " << expected_id;
+    success = false;
+  }
+  gid_t rgid = getgid();
+  if (rgid != expected_id) {
+    LOG(ERROR) << "rGID " << ruid << " is not " << expected_id;
+    success = false;
+  }
+  return success;
+}
+
+bool check_groups(size_t expected_size, gid_t* expected_list) {
+  bool success = true;
+
+  gid_t* actual_list;
+  size_t actual_size = getgroups_with_alloc(&actual_list);
+
+  if (expected_size != actual_size) {
+    LOG(ERROR) << "Mismatched supplementary group list size: expected "
+               << expected_size << ", actual " << actual_size;
+    success = false;
+  }
+
+  for (size_t i = 0; i < expected_size; i++) {
+    bool found = false;
+    for (size_t j = 0; j < actual_size; j++) {
+      if (expected_list[i] == actual_list[j]) {
+        // Test next expected GID.
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      LOG(ERROR) << "Expected GID " << expected_list[i] << " not found.";
+      success = false;
+    }
+  }
+  free(actual_list);
+  return success;
+}
+
+void log_resugid() {
+  uid_t ruid, euid, suid;
+  gid_t rgid, egid, sgid;
+  getresuid(&ruid, &euid, &suid);
+  getresgid(&rgid, &egid, &sgid);
+
+  LOG(INFO) << "ruid " << ruid << " euid " << euid << " suid " << suid;
+  LOG(INFO) << "rgid " << rgid << " egid " << egid << " sgid " << sgid;
+
+  gid_t* list;
+  size_t nsupp_groups = getgroups_with_alloc(&list);
+  for (size_t i = 0; i < (size_t)nsupp_groups; i++) {
+    LOG(INFO) << "supp gid " << i + 1 << " " << list[i];
+  }
+  free(list);
+}
+
+int main(void) {
+  minijail* j = minijail_new();
+  minijail_change_user(j, "system");
+  minijail_change_group(j, "system");
+  size_t num_groups = sizeof(groups) / sizeof(groups[0]);
+  minijail_set_supplementary_gids(j, num_groups, groups);
+  minijail_use_caps(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
+  minijail_enter(j);
+
+  bool success = check_ugid(kSystemUid);
+  success = success && check_groups(num_groups, groups);
+
+  minijail_destroy(j);
+  minijail* j2 = minijail_new();
+  minijail_change_uid(j2, 5 * kSystemUid);
+  minijail_change_gid(j2, 5 * kSystemUid);
+  minijail_enter(j2);
+
+  success = success && check_ugid(5 * kSystemUid);
+
+  return success ? 0 : 1;
+}
diff --git a/minijail/test/read_stdin b/minijail/test/read_stdin
new file mode 100755
index 0000000..29578a6
--- /dev/null
+++ b/minijail/test/read_stdin
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+read line
+
+if [ "$line" == "test" ]; then
+	exit 0
+else
+	exit 1
+fi
diff --git a/minijail/test/seccomp.policy b/minijail/test/seccomp.policy
new file mode 100644
index 0000000..b983631
--- /dev/null
+++ b/minijail/test/seccomp.policy
@@ -0,0 +1,4 @@
+read: 1
+write: 1
+rt_sigreturn: 1
+exit: 1
diff --git a/minijail/test/stdin_stdout.policy b/minijail/test/stdin_stdout.policy
new file mode 100644
index 0000000..874a5ca
--- /dev/null
+++ b/minijail/test/stdin_stdout.policy
@@ -0,0 +1,4 @@
+read: arg0 == 0
+write: arg0 == 1 || arg0 == 2
+rt_sigreturn: 1
+exit: 1
diff --git a/minijail/test_harness.h b/minijail/test_harness.h
new file mode 100644
index 0000000..c05f1a7
--- /dev/null
+++ b/minijail/test_harness.h
@@ -0,0 +1,439 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * test_harness.h: simple C unit test helper.
+ *
+ * Usage:
+ *   #include "test_harness.h"
+ *   TEST(standalone_test) {
+ *     do_some_stuff;
+ *     EXPECT_GT(10, stuff) {
+ *        stuff_state_t state;
+ *        enumerate_stuff_state(&state);
+ *        TH_LOG("expectation failed with state: %s", state.msg);
+ *     }
+ *     more_stuff;
+ *     ASSERT_NE(some_stuff, NULL) TH_LOG("how did it happen?!");
+ *     last_stuff;
+ *     EXPECT_EQ(0, last_stuff);
+ *   }
+ *
+ *   FIXTURE(my_fixture) {
+ *     mytype_t *data;
+ *     int awesomeness_level;
+ *   };
+ *   FIXTURE_SETUP(my_fixture) {
+ *     self->data = mytype_new();
+ *     ASSERT_NE(NULL, self->data);
+ *   }
+ *   FIXTURE_TEARDOWN(my_fixture) {
+ *     mytype_free(self->data);
+ *   }
+ *   TEST_F(my_fixture, data_is_good) {
+ *     EXPECT_EQ(1, is_my_data_good(self->data));
+ *   }
+ *
+ *   TEST_HARNESS_MAIN
+ *
+ * API inspired by code.google.com/p/googletest
+ */
+#ifndef TEST_HARNESS_H_
+#define TEST_HARNESS_H_
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/* All exported functionality should be declared through this macro. */
+#define TEST_API(x) _##x
+
+/*
+ * Exported APIs
+ */
+
+/* TEST(name) { implementation }
+ * Defines a test by name.
+ * Names must be unique and tests must not be run in parallel.  The
+ * implementation containing block is a function and scoping should be treated
+ * as such.  Returning early may be performed with a bare "return;" statement.
+ *
+ * EXPECT_* and ASSERT_* are valid in a TEST() { } context.
+ */
+#define TEST TEST_API(TEST)
+
+/* FIXTURE(datatype name) {
+ *   type property1;
+ *   ...
+ * };
+ * Defines the data provided to TEST_F()-defined tests as |self|.  It should be
+ * populated and cleaned up using FIXTURE_SETUP and FIXTURE_TEARDOWN.
+ */
+#define FIXTURE TEST_API(FIXTURE)
+
+/* FIXTURE_DATA(datatype name)
+ * This call may be used when the type of the fixture data
+ * is needed.  In general, this should not be needed unless
+ * the |self| is being passed to a helper directly.
+ */
+#define FIXTURE_DATA TEST_API(FIXTURE_DATA)
+
+/* FIXTURE_SETUP(fixture name) { implementation }
+ * Populates the required "setup" function for a fixture.  An instance of the
+ * datatype defined with _FIXTURE_DATA will be exposed as |self| for the
+ * implementation.
+ *
+ * ASSERT_* are valid for use in this context and will prempt the execution
+ * of any dependent fixture tests.
+ *
+ * A bare "return;" statement may be used to return early.
+ */
+#define FIXTURE_SETUP TEST_API(FIXTURE_SETUP)
+
+/* FIXTURE_TEARDOWN(fixture name) { implementation }
+ * Populates the required "teardown" function for a fixture.  An instance of the
+ * datatype defined with _FIXTURE_DATA will be exposed as |self| for the
+ * implementation to clean up.
+ *
+ * A bare "return;" statement may be used to return early.
+ */
+#define FIXTURE_TEARDOWN TEST_API(FIXTURE_TEARDOWN)
+
+/* TEST_F(fixture, name) { implementation }
+ * Defines a test that depends on a fixture (e.g., is part of a test case).
+ * Very similar to TEST() except that |self| is the setup instance of fixture's
+ * datatype exposed for use by the implementation.
+ */
+#define TEST_F TEST_API(TEST_F)
+
+/* Use once to append a main() to the test file. E.g.,
+ *   TEST_HARNESS_MAIN
+ */
+#define TEST_HARNESS_MAIN TEST_API(TEST_HARNESS_MAIN)
+
+/*
+ * Operators for use in TEST and TEST_F.
+ * ASSERT_* calls will stop test execution immediately.
+ * EXPECT_* calls will emit a failure warning, note it, and continue.
+ */
+
+/* ASSERT_EQ(expected, measured): expected == measured */
+#define ASSERT_EQ TEST_API(ASSERT_EQ)
+/* ASSERT_NE(expected, measured): expected != measured */
+#define ASSERT_NE TEST_API(ASSERT_NE)
+/* ASSERT_LT(expected, measured): expected < measured */
+#define ASSERT_LT TEST_API(ASSERT_LT)
+/* ASSERT_LE(expected, measured): expected <= measured */
+#define ASSERT_LE TEST_API(ASSERT_LE)
+/* ASSERT_GT(expected, measured): expected > measured */
+#define ASSERT_GT TEST_API(ASSERT_GT)
+/* ASSERT_GE(expected, measured): expected >= measured */
+#define ASSERT_GE TEST_API(ASSERT_GE)
+/* ASSERT_NULL(measured): NULL == measured */
+#define ASSERT_NULL TEST_API(ASSERT_NULL)
+/* ASSERT_TRUE(measured): measured != 0 */
+#define ASSERT_TRUE TEST_API(ASSERT_TRUE)
+/* ASSERT_FALSE(measured): measured == 0 */
+#define ASSERT_FALSE TEST_API(ASSERT_FALSE)
+/* ASSERT_STREQ(expected, measured): !strcmp(expected, measured) */
+#define ASSERT_STREQ TEST_API(ASSERT_STREQ)
+/* ASSERT_STRNE(expected, measured): strcmp(expected, measured) */
+#define ASSERT_STRNE TEST_API(ASSERT_STRNE)
+/* EXPECT_EQ(expected, measured): expected == measured */
+#define EXPECT_EQ TEST_API(EXPECT_EQ)
+/* EXPECT_NE(expected, measured): expected != measured */
+#define EXPECT_NE TEST_API(EXPECT_NE)
+/* EXPECT_LT(expected, measured): expected < measured */
+#define EXPECT_LT TEST_API(EXPECT_LT)
+/* EXPECT_LE(expected, measured): expected <= measured */
+#define EXPECT_LE TEST_API(EXPECT_LE)
+/* EXPECT_GT(expected, measured): expected > measured */
+#define EXPECT_GT TEST_API(EXPECT_GT)
+/* EXPECT_GE(expected, measured): expected >= measured */
+#define EXPECT_GE TEST_API(EXPECT_GE)
+/* EXPECT_NULL(measured): NULL == measured */
+#define EXPECT_NULL TEST_API(EXPECT_NULL)
+/* EXPECT_TRUE(measured): 0 != measured */
+#define EXPECT_TRUE TEST_API(EXPECT_TRUE)
+/* EXPECT_FALSE(measured): 0 == measured */
+#define EXPECT_FALSE TEST_API(EXPECT_FALSE)
+/* EXPECT_STREQ(expected, measured): !strcmp(expected, measured) */
+#define EXPECT_STREQ TEST_API(EXPECT_STREQ)
+/* EXPECT_STRNE(expected, measured): strcmp(expected, measured) */
+#define EXPECT_STRNE TEST_API(EXPECT_STRNE)
+
+/* TH_LOG(format, ...)
+ * Optional debug logging function available for use in tests.
+ * Logging may be enabled or disabled by defining TH_LOG_ENABLED.
+ * E.g., #define TH_LOG_ENABLED 1
+ * If no definition is provided, logging is enabled by default.
+ */
+#define TH_LOG  TEST_API(TH_LOG)
+
+/*
+ * Internal implementation.
+ *
+ */
+
+/* Utilities exposed to the test definitions */
+#ifndef TH_LOG_STREAM
+#  define TH_LOG_STREAM stderr
+#endif
+
+#ifndef TH_LOG_ENABLED
+#  define TH_LOG_ENABLED 1
+#endif
+
+#define _TH_LOG(fmt, ...) do { \
+  if (TH_LOG_ENABLED) \
+    __TH_LOG(fmt, ##__VA_ARGS__); \
+} while (0)
+
+/* Unconditional logger for internal use. */
+#define __TH_LOG(fmt, ...) \
+    fprintf(TH_LOG_STREAM, "%s:%d:%s:" fmt "\n", \
+            __FILE__, __LINE__, _metadata->name, ##__VA_ARGS__)
+
+/* Defines the test function and creates the registration stub. */
+#define _TEST(test_name) \
+  static void test_name(struct __test_metadata *_metadata); \
+  static struct __test_metadata _##test_name##_object = \
+    { .name= "global." #test_name, .fn= &(test_name) }; \
+  static void __attribute__((constructor)) _register_##test_name(void) { \
+    __register_test(&_##test_name##_object); \
+  } \
+  static void test_name( \
+    struct __test_metadata __attribute__((unused)) *_metadata)
+
+/* Wraps the struct name so we have one less argument to pass around. */
+#define _FIXTURE_DATA(fixture_name) struct _test_data_##fixture_name
+
+/* Called once per fixture to setup the data and register. */
+#define _FIXTURE(fixture_name) \
+  static void __attribute__((constructor)) \
+      _register_##fixture_name##_data(void) { \
+    __fixture_count++; \
+  } \
+  _FIXTURE_DATA(fixture_name)
+
+/* Prepares the setup function for the fixture.  |_metadata| is included
+ * so that ASSERT_* work as a convenience.
+ */
+#define _FIXTURE_SETUP(fixture_name) \
+  void fixture_name##_setup( \
+    struct __test_metadata __attribute__((unused)) *_metadata, \
+    _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self)
+#define _FIXTURE_TEARDOWN(fixture_name) \
+  void fixture_name##_teardown( \
+    struct __test_metadata __attribute__((unused)) *_metadata, \
+    _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self)
+
+/* Emits test registration and helpers for fixture-based test
+ * cases.
+ * TODO(wad) register fixtures on dedicated test lists.
+ */
+#define _TEST_F(fixture_name, test_name) \
+  static void fixture_name##_##test_name( \
+    struct __test_metadata *_metadata, \
+    _FIXTURE_DATA(fixture_name) *self); \
+  static inline void wrapper_##fixture_name##_##test_name( \
+    struct __test_metadata *_metadata) { \
+    /* fixture data is allocated, setup, and torn down per call. */ \
+    _FIXTURE_DATA(fixture_name) self; \
+    memset(&self, 0, sizeof(_FIXTURE_DATA(fixture_name))); \
+    fixture_name##_setup(_metadata, &self); \
+    /* Let setup failure terminate early. */ \
+    if (!_metadata->passed) return; \
+    fixture_name##_##test_name(_metadata, &self); \
+    fixture_name##_teardown(_metadata, &self); \
+  } \
+  static struct __test_metadata _##fixture_name##_##test_name##_object = { \
+    .name= #fixture_name "." #test_name, \
+    .fn= &wrapper_##fixture_name##_##test_name, \
+   }; \
+  static void __attribute__((constructor)) \
+      _register_##fixture_name##_##test_name(void) { \
+    __register_test(&_##fixture_name##_##test_name##_object); \
+  } \
+  static void fixture_name##_##test_name( \
+    struct __test_metadata __attribute__((unused)) *_metadata, \
+    _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self)
+
+/* Exports a simple wrapper to run the test harness. */
+#define _TEST_HARNESS_MAIN \
+  int main(int argc, char **argv) { return test_harness_run(argc, argv); }
+
+#define _ASSERT_EQ(_expected, _seen) \
+  __EXPECT(_expected, _seen, ==, 1)
+#define _ASSERT_NE(_expected, _seen) \
+  __EXPECT(_expected, _seen, !=, 1)
+#define _ASSERT_LT(_expected, _seen) \
+  __EXPECT(_expected, _seen, <, 1)
+#define _ASSERT_LE(_expected, _seen) \
+  __EXPECT(_expected, _seen, <=, 1)
+#define _ASSERT_GT(_expected, _seen) \
+  __EXPECT(_expected, _seen, >, 1)
+#define _ASSERT_GE(_expected, _seen) \
+  __EXPECT(_expected, _seen, >=, 1)
+#define _ASSERT_NULL(_seen) \
+  __EXPECT(NULL, _seen, ==, 1)
+
+#define _ASSERT_TRUE(_seen) \
+  _ASSERT_NE(0, _seen)
+#define _ASSERT_FALSE(_seen) \
+  _ASSERT_EQ(0, _seen)
+#define _ASSERT_STREQ(_expected, _seen) \
+  __EXPECT_STR(_expected, _seen, ==, 1)
+#define _ASSERT_STRNE(_expected, _seen) \
+  __EXPECT_STR(_expected, _seen, !=, 1)
+
+#define _EXPECT_EQ(_expected, _seen) \
+  __EXPECT(_expected, _seen, ==, 0)
+#define _EXPECT_NE(_expected, _seen) \
+  __EXPECT(_expected, _seen, !=, 0)
+#define _EXPECT_LT(_expected, _seen) \
+  __EXPECT(_expected, _seen, <, 0)
+#define _EXPECT_LE(_expected, _seen) \
+  __EXPECT(_expected, _seen, <=, 0)
+#define _EXPECT_GT(_expected, _seen) \
+  __EXPECT(_expected, _seen, >, 0)
+#define _EXPECT_GE(_expected, _seen) \
+  __EXPECT(_expected, _seen, >=, 0)
+
+#define _EXPECT_NULL(_seen) \
+  __EXPECT(NULL, _seen, ==, 0)
+#define _EXPECT_TRUE(_seen) \
+  _EXPECT_NE(0, _seen)
+#define _EXPECT_FALSE(_seen) \
+  _EXPECT_EQ(0, _seen)
+
+#define _EXPECT_STREQ(_expected, _seen) \
+  __EXPECT_STR(_expected, _seen, ==, 0)
+#define _EXPECT_STRNE(_expected, _seen) \
+  __EXPECT_STR(_expected, _seen, !=, 0)
+
+/* Support an optional handler after and ASSERT_* or EXPECT_*.  The approach is
+ * not thread-safe, but it should be fine in most sane test scenarios.
+ *
+ * Using __bail(), which optionally abort()s, is the easiest way to early
+ * return while still providing an optional block to the API consumer.
+ */
+#define OPTIONAL_HANDLER(_assert) \
+  for (; _metadata->trigger;  _metadata->trigger = __bail(_assert))
+
+#define __EXPECT(_expected, _seen, _t, _assert) do { \
+  /* Avoid multiple evaluation of the cases */ \
+  __typeof__(_expected) __exp = (_expected); \
+  __typeof__(_seen) __seen = (_seen); \
+  if (!(__exp _t __seen)) { \
+    unsigned long long __exp_print = 0; \
+    unsigned long long __seen_print = 0; \
+    /* Avoid casting complaints the scariest way we can. */ \
+    memcpy(&__exp_print, &__exp, sizeof(__exp)); \
+    memcpy(&__seen_print, &__seen, sizeof(__seen)); \
+    __TH_LOG("Expected %s (%llu) %s %s (%llu)", \
+            #_expected, __exp_print, #_t, \
+            #_seen, __seen_print); \
+    _metadata->passed = 0; \
+    /* Ensure the optional handler is triggered */ \
+    _metadata->trigger = 1; \
+  } \
+} while (0); OPTIONAL_HANDLER(_assert)
+
+/* NOLINT: clang-tidy adds wrong parentheses around _t. */
+#define __EXPECT_STR(_expected, _seen, _t, _assert) do { \
+  const char *__exp = (_expected); \
+  const char *__seen = (_seen); \
+  if (!(strcmp(__exp, __seen) _t 0))  { /* NOLINT */ \
+    __TH_LOG("Expected '%s' %s '%s'.", __exp, #_t, __seen); \
+    _metadata->passed = 0; \
+    _metadata->trigger = 1; \
+  } \
+} while (0); OPTIONAL_HANDLER(_assert)
+
+/* Contains all the information for test execution and status checking. */
+struct __test_metadata {
+  const char *name;
+  void (*fn)(struct __test_metadata *);
+  int passed;
+  int trigger; /* extra handler after the evaluation */
+  struct __test_metadata *prev, *next;
+};
+
+/* Storage for the (global) tests to be run. */
+static struct __test_metadata *__test_list = NULL;
+static unsigned int __test_count = 0;
+static unsigned int __fixture_count = 0;
+
+static inline void __register_test(struct __test_metadata *t) {
+  __test_count++;
+  /* Circular linked list where only prev is circular. */
+  if (__test_list == NULL) {
+    __test_list = t;
+    t->next = NULL;
+    t->prev = t;
+    return;
+  }
+  t->next = NULL;
+  t->prev = __test_list->prev;
+  t->prev->next = t;
+  __test_list->prev = t;
+}
+
+static inline int __bail(int for_realz) {
+  if (for_realz)
+    abort();
+  return 0;
+}
+
+static int test_harness_run(int __attribute__((unused)) argc,
+                            char __attribute__((unused)) **argv) {
+  struct __test_metadata *t;
+  int ret = 0;
+  unsigned int count = 0;
+
+  /* TODO(wad) add optional arguments similar to gtest. */
+  printf("[==========] Running %u tests from %u test cases.\n",
+          __test_count, __fixture_count + 1);
+  for (t = __test_list; t; t = t->next) {
+    pid_t child_pid;
+    int status;
+    count++;
+    t->passed = 1;
+    t->trigger = 0;
+    printf("[ RUN      ] %s\n", t->name);
+    child_pid = fork();
+    if (child_pid < 0) {
+      printf("ERROR SPAWNING TEST CHILD\n");
+      t->passed = 0;
+    } else if (child_pid == 0) {
+      t->fn(t);
+      _exit(t->passed);
+    } else {
+      /* TODO(wad) add timeout support. */
+      waitpid(child_pid, &status, 0);
+      if (WIFEXITED(status))
+        t->passed = WEXITSTATUS(status);
+      if (WIFSIGNALED(status)) {
+        t->passed = 0;
+        fprintf(TH_LOG_STREAM,
+                "%s: Test terminated unexpectedly by signal %d\n",
+               t->name,
+               WTERMSIG(status));
+      }
+    }
+    printf("[     %4s ] %s\n", (t->passed ? "OK" : "FAIL"), t->name);
+    if (!t->passed)
+      ret = 1;
+  }
+  /* TODO(wad) organize by fixtures since ordering is not guaranteed now. */
+  printf("[==========] %u tests ran.\n", count);
+  printf("[  %s  ]\n", (ret ? "FAILED" : "PASSED"));
+  return ret;
+}
+
+#endif  /* TEST_HARNESS_H_ */
diff --git a/minijail/tools/generate_seccomp_policy.py b/minijail/tools/generate_seccomp_policy.py
new file mode 100755
index 0000000..0b51e71
--- /dev/null
+++ b/minijail/tools/generate_seccomp_policy.py
@@ -0,0 +1,169 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script will take any number of trace files generated by strace(1)
+# and output a system call filtering policy suitable for use with Minijail.
+
+from collections import namedtuple
+import sys
+
+NOTICE = """# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+
+ALLOW = "%s: 1"
+
+SOCKETCALLS = ["accept", "bind", "connect", "getpeername", "getsockname",
+               "getsockopt", "listen", "recv", "recvfrom", "recvmsg", "send",
+               "sendmsg", "sendto", "setsockopt", "shutdown", "socket",
+               "socketpair"]
+
+# /* Protocol families.  */
+# #define PF_UNSPEC     0       /* Unspecified.  */
+# #define PF_LOCAL      1       /* Local to host (pipes and file-domain).  */
+# #define PF_UNIX       PF_LOCAL /* POSIX name for PF_LOCAL.  */
+# #define PF_FILE       PF_LOCAL /* Another non-standard name for PF_LOCAL.  */
+# #define PF_INET       2       /* IP protocol family.  */
+# #define PF_AX25       3       /* Amateur Radio AX.25.  */
+# #define PF_IPX        4       /* Novell Internet Protocol.  */
+# #define PF_APPLETALK  5       /* Appletalk DDP.  */
+# #define PF_NETROM     6       /* Amateur radio NetROM.  */
+# #define PF_BRIDGE     7       /* Multiprotocol bridge.  */
+# #define PF_ATMPVC     8       /* ATM PVCs.  */
+# #define PF_X25        9       /* Reserved for X.25 project.  */
+# #define PF_INET6     10      /* IP version 6.  */
+# #define PF_ROSE      11      /* Amateur Radio X.25 PLP.  */
+# #define PF_DECnet    12      /* Reserved for DECnet project.  */
+# #define PF_NETBEUI   13      /* Reserved for 802.2LLC project.  */
+# #define PF_SECURITY  14      /* Security callback pseudo AF.  */
+# #define PF_KEY       15      /* PF_KEY key management API.  */
+# #define PF_NETLINK   16
+
+ArgInspectionEntry = namedtuple("ArgInspectionEntry", "arg_index value_set")
+
+
+def usage(argv):
+    print "%s <trace file> [trace files...]" % argv[0]
+
+
+def main(traces):
+    syscalls = {}
+
+    uses_socketcall = False
+
+    basic_set = ["restart_syscall", "exit", "exit_group",
+                 "rt_sigreturn"]
+    frequent_set = []
+
+    syscall_sets = {}
+    syscall_set_list = [["sigreturn", "rt_sigreturn"],
+                        ["sigaction", "rt_sigaction"],
+                        ["sigprocmask", "rt_sigprocmask"],
+                        ["open", "openat"],
+                        ["mmap", "mremap"],
+                        ["mmap2", "mremap"]]
+
+    arg_inspection = {
+        "socket": ArgInspectionEntry(0, set([])),   # int domain
+        "ioctl": ArgInspectionEntry(1, set([])),    # int request
+        "prctl": ArgInspectionEntry(0, set([]))     # int option
+    }
+
+    for syscall_list in syscall_set_list:
+        for syscall in syscall_list:
+            other_syscalls = syscall_list[:]
+            other_syscalls.remove(syscall)
+            syscall_sets[syscall] = other_syscalls
+
+    for trace_filename in traces:
+        if "i386" in trace_filename or ("x86" in trace_filename and
+                                        "64" not in trace_filename):
+            uses_socketcall = True
+
+        trace_file = open(trace_filename)
+        for line in trace_file:
+            if "---" in line or '(' not in line:
+                continue
+
+            syscall, args = line.strip().split('(', 1)
+            if uses_socketcall and syscall in SOCKETCALLS:
+                syscall = "socketcall"
+
+            if syscall in syscalls:
+                syscalls[syscall] += 1
+            else:
+                syscalls[syscall] = 1
+
+            args = [arg.strip() for arg in args.split(')', 1)[0].split(',')]
+
+            if syscall in arg_inspection:
+                arg_value = args[arg_inspection[syscall].arg_index]
+                arg_inspection[syscall].value_set.add(arg_value)
+
+    sorted_syscalls = list(zip(*sorted(syscalls.iteritems(),
+                                       key=lambda pair: pair[1],
+                                       reverse=True))[0])
+
+    print NOTICE
+
+    # Add frequent syscalls first.
+    for frequent_syscall in frequent_set:
+        sorted_syscalls.remove(frequent_syscall)
+
+    all_syscalls = frequent_set + sorted_syscalls
+
+    # Add the basic set once the frequency drops below 2.
+    below_ten_index = -1
+    for sorted_syscall in sorted_syscalls:
+        if syscalls[sorted_syscall] < 2:
+            below_ten_index = all_syscalls.index(sorted_syscall)
+            break
+
+    first_half = all_syscalls[:below_ten_index]
+    for basic_syscall in basic_set:
+        if basic_syscall not in all_syscalls:
+            first_half.append(basic_syscall)
+
+    all_syscalls = first_half + all_syscalls[below_ten_index:]
+
+    for syscall in all_syscalls:
+        if syscall in arg_inspection:
+            arg_index = arg_inspection[syscall].arg_index
+            arg_values = arg_inspection[syscall].value_set
+            arg_filter = " || ".join(["arg%d == %s" % (arg_index, arg_value)
+                                      for arg_value in arg_values])
+            print syscall + ": " + arg_filter
+        else:
+            print ALLOW % syscall
+
+
+if __name__ == "__main__":
+    if len(sys.argv) < 2:
+        usage(sys.argv)
+        sys.exit(1)
+
+    main(sys.argv[1:])
diff --git a/minijail/util.c b/minijail/util.c
new file mode 100644
index 0000000..b82e308
--- /dev/null
+++ b/minijail/util.c
@@ -0,0 +1,289 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "util.h"
+
+#include "libconstants.h"
+#include "libsyscalls.h"
+
+/*
+ * These are syscalls used by the syslog() C library call.  You can find them
+ * by running a simple test program.  See below for x86_64 behavior:
+ * $ cat test.c
+ * #include <syslog.h>
+ * main() { syslog(0, "foo"); }
+ * $ gcc test.c -static
+ * $ strace ./a.out
+ * ...
+ * socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3 <- look for socket connection
+ * connect(...)                                    <- important
+ * sendto(...)                                     <- important
+ * exit_group(0)                                   <- finish!
+ */
+#if defined(__x86_64__)
+#if defined(__ANDROID__)
+const char *log_syscalls[] = {"socket", "connect", "fcntl", "writev"};
+#else
+const char *log_syscalls[] = {"connect", "sendto"};
+#endif
+#elif defined(__i386__)
+#if defined(__ANDROID__)
+const char *log_syscalls[] = {"socketcall", "writev", "fcntl64",
+			      "clock_gettime"};
+#else
+const char *log_syscalls[] = {"socketcall", "time"};
+#endif
+#elif defined(__arm__)
+#if defined(__ANDROID__)
+const char *log_syscalls[] = {"clock_gettime", "connect", "fcntl64", "socket",
+			      "writev"};
+#else
+const char *log_syscalls[] = {"connect", "gettimeofday", "send"};
+#endif
+#elif defined(__aarch64__)
+#if defined(__ANDROID__)
+const char *log_syscalls[] = {"connect", "fcntl", "sendto", "socket", "writev"};
+#else
+const char *log_syscalls[] = {"connect", "send"};
+#endif
+#elif defined(__powerpc__) || defined(__ia64__) || defined(__hppa__) ||        \
+      defined(__sparc__) || defined(__mips__)
+const char *log_syscalls[] = {"connect", "send"};
+#else
+#error "Unsupported platform"
+#endif
+
+const size_t log_syscalls_len = sizeof(log_syscalls)/sizeof(log_syscalls[0]);
+
+int lookup_syscall(const char *name)
+{
+	const struct syscall_entry *entry = syscall_table;
+	for (; entry->name && entry->nr >= 0; ++entry)
+		if (!strcmp(entry->name, name))
+			return entry->nr;
+	return -1;
+}
+
+const char *lookup_syscall_name(int nr)
+{
+	const struct syscall_entry *entry = syscall_table;
+	for (; entry->name && entry->nr >= 0; ++entry)
+		if (entry->nr == nr)
+			return entry->name;
+	return NULL;
+}
+
+long int parse_single_constant(char *constant_str, char **endptr)
+{
+	const struct constant_entry *entry = constant_table;
+	for (; entry->name; ++entry) {
+		if (!strcmp(entry->name, constant_str)) {
+			if (endptr)
+				*endptr = constant_str + strlen(constant_str);
+
+			return entry->value;
+		}
+	}
+
+	return strtol(constant_str, endptr, 0);
+}
+
+long int parse_constant(char *constant_str, char **endptr)
+{
+	long int value = 0;
+	char *group, *lastpos = constant_str;
+	char *original_constant_str = constant_str;
+
+	/*
+	 * Try to parse constants separated by pipes.  Note that since
+	 * |constant_str| is an atom, there can be no spaces between the
+	 * constant and the pipe.  Constants can be either a named constant
+	 * defined in libconstants.gen.c or a number parsed with strtol.
+	 *
+	 * If there is an error parsing any of the constants, the whole process
+	 * fails.
+	 */
+	while ((group = tokenize(&constant_str, "|")) != NULL) {
+		char *end = group;
+		value |= parse_single_constant(group, &end);
+		if (end == group) {
+			lastpos = original_constant_str;
+			value = 0;
+			break;
+		}
+		lastpos = end;
+	}
+	if (endptr)
+		*endptr = lastpos;
+	return value;
+}
+
+char *strip(char *s)
+{
+	char *end;
+	while (*s && isblank(*s))
+		s++;
+	end = s + strlen(s) - 1;
+	while (end >= s && *end && (isblank(*end) || *end == '\n'))
+		end--;
+	*(end + 1) = '\0';
+	return s;
+}
+
+char *tokenize(char **stringp, const char *delim)
+{
+	char *ret = NULL;
+
+	/* If the string is NULL or empty, there are no tokens to be found. */
+	if (stringp == NULL || *stringp == NULL || **stringp == '\0')
+		return NULL;
+
+	/*
+	 * If the delimiter is NULL or empty,
+	 * the full string makes up the only token.
+	 */
+	if (delim == NULL || *delim == '\0') {
+		ret = *stringp;
+		*stringp = NULL;
+		return ret;
+	}
+
+	char *found;
+	while (**stringp != '\0') {
+		found = strstr(*stringp, delim);
+
+		if (!found) {
+			/*
+			 * The delimiter was not found, so the full string
+			 * makes up the only token, and we're done.
+			 */
+			ret = *stringp;
+			*stringp = NULL;
+			break;
+		}
+
+		if (found != *stringp) {
+			/* There's a non-empty token before the delimiter. */
+			*found = '\0';
+			ret = *stringp;
+			*stringp = found + strlen(delim);
+			break;
+		}
+
+		/*
+		 * The delimiter was found at the start of the string,
+		 * skip it and keep looking for a non-empty token.
+		 */
+		*stringp += strlen(delim);
+	}
+
+	return ret;
+}
+
+int kernel_lessthan_3_8()
+{
+	int major, minor;
+	struct utsname uts;
+	return (uname(&uts) != -1 &&
+			sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
+			((major < 3) || ((major == 3) && (minor < 8))));
+}
+
+char *path_join(const char *external_path, const char *internal_path)
+{
+	char *path;
+	size_t pathlen;
+
+	/* One extra char for '/' and one for '\0', hence + 2. */
+	pathlen = strlen(external_path) + strlen(internal_path) + 2;
+	path = malloc(pathlen);
+	snprintf(path, pathlen, "%s/%s", external_path, internal_path);
+
+	return path;
+}
+
+int write_proc_file(pid_t pid, const char *content, const char *basename)
+{
+	int fd, ret;
+	size_t sz, len;
+	ssize_t written;
+	char filename[32];
+
+	sz = sizeof(filename);
+	ret = snprintf(filename, sz, "/proc/%d/%s", pid, basename);
+	if (ret < 0 || (size_t)ret >= sz) {
+		warn("failed to generate %s filename", basename);
+		return -1;
+	}
+
+	fd = open(filename, O_WRONLY | O_CLOEXEC);
+	if (fd < 0) {
+		pwarn("failed to open '%s'", filename);
+		return -errno;
+	}
+
+	len = strlen(content);
+	written = write(fd, content, len);
+	if (written < 0) {
+		pwarn("failed to write '%s'", filename);
+		return -1;
+	}
+
+	if ((size_t)written < len) {
+		warn("failed to write %zu bytes to '%s'", len, filename);
+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
+int write_pid_to_path(pid_t pid, const char *path)
+{
+	FILE *fp = fopen(path, "w");
+
+	if (!fp) {
+		pwarn("failed to open '%s'", path);
+		return -errno;
+	}
+	if (fprintf(fp, "%d\n", (int)pid) < 0) {
+		/* fprintf(3) does not set errno on failure. */
+		warn("fprintf(%s) failed", path);
+		return -1;
+	}
+	if (fclose(fp)) {
+		pwarn("fclose(%s) failed", path);
+		return -errno;
+	}
+
+	return 0;
+}
+
+void *consumebytes(size_t length, char **buf, size_t *buflength)
+{
+	char *p = *buf;
+	if (length > *buflength)
+		return NULL;
+	*buf += length;
+	*buflength -= length;
+	return p;
+}
+
+char *consumestr(char **buf, size_t *buflength)
+{
+	size_t len = strnlen(*buf, *buflength);
+	if (len == *buflength)
+		/* There's no null-terminator. */
+		return NULL;
+	return consumebytes(len + 1, buf, buflength);
+}
diff --git a/minijail/util.h b/minijail/util.h
new file mode 100644
index 0000000..faf6315
--- /dev/null
+++ b/minijail/util.h
@@ -0,0 +1,98 @@
+/* util.h
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Logging and other utility functions.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define die(_msg, ...) do { \
+	syslog(LOG_ERR, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__); \
+	abort(); \
+} while (0)
+
+#define pdie(_msg, ...) \
+	die(_msg ": %m", ## __VA_ARGS__)
+
+#define warn(_msg, ...) \
+	syslog(LOG_WARNING, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__)
+
+#define pwarn(_msg, ...) \
+	warn(_msg ": %m", ## __VA_ARGS__)
+
+#define info(_msg, ...) \
+	syslog(LOG_INFO, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__)
+
+extern const char *log_syscalls[];
+extern const size_t log_syscalls_len;
+
+static inline int is_android() {
+#if defined(__ANDROID__)
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static inline int running_with_asan() {
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(address_sanitizer)
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+int lookup_syscall(const char *name);
+const char *lookup_syscall_name(int nr);
+
+long int parse_constant(char *constant_str, char **endptr);
+
+char *strip(char *s);
+char *tokenize(char **stringp, const char *delim);
+
+int kernel_lessthan_3_8();
+
+char *path_join(const char *external_path, const char *internal_path);
+int write_proc_file(pid_t pid, const char *content, const char *basename);
+int write_pid_to_path(pid_t pid, const char *path);
+
+/*
+ * consumebytes: consumes @length bytes from a buffer @buf of length @buflength
+ * @length    Number of bytes to consume
+ * @buf       Buffer to consume from
+ * @buflength Size of @buf
+ *
+ * Returns a pointer to the base of the bytes, or NULL for errors.
+ */
+void *consumebytes(size_t length, char **buf, size_t *buflength);
+
+/*
+ * consumestr: consumes a C string from a buffer @buf of length @length
+ * @buf    Buffer to consume
+ * @length Length of buffer
+ *
+ * Returns a pointer to the base of the string, or NULL for errors.
+ */
+char *consumestr(char **buf, size_t *buflength);
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#endif /* _UTIL_H_ */