Port Minijail unit tests to Google Test.
Remove the duplicate unit test files.
Google Test is designed to be included directly with the project using
it, so add a simple shell script to get the sources.
Bug: 34520446
Test: Builds on Android, desktop Linux.
Change-Id: Iabc63fa1cb847b668645dbf5468454f025c93721
diff --git a/.gitignore b/.gitignore
index 0e5f062..ac10fcb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
*.depends
/*.gen.c
*.o
+*.a
# Shared libraries when compiling in-tree.
*.so
@@ -10,3 +11,6 @@
libminijail_unittest
minijail0
syscall_filter_unittest
+
+# Google Test.
+googletest-release*
diff --git a/Android.mk b/Android.mk
index 1a2e787..6a63e87 100644
--- a/Android.mk
+++ b/Android.mk
@@ -136,91 +136,58 @@
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 := \
- $(libminijailSrcFiles) \
- libminijail_unittest.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_CPP_EXTENSION := .cc
LOCAL_CFLAGS := $(minijailCommonCFlags) -Wno-writable-strings
LOCAL_CLANG := true
LOCAL_SRC_FILES := \
$(libminijailSrcFiles) \
- libminijail_unittest.cpp \
+ libminijail_unittest.cc \
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
-# TODO(b/31395668): Re-enable once the seccomp(2) syscall becomes available.
-# =========================================================
+# # libminijail native unit tests for the host. Run with:
+# # out/host/linux-x86/nativetest(64)/libminijail_unittest/libminijail_unittest_gtest
+# # TODO(b/31395668): Re-enable once the seccomp(2) syscall becomes available.
+# # =========================================================
# include $(CLEAR_VARS)
-# LOCAL_MODULE := libminijail_unittest
+# LOCAL_MODULE := libminijail_unittest_gtest
# LOCAL_MODULE_HOST_OS := linux
+# LOCAL_CPP_EXTENSION := .cc
# LOCAL_CFLAGS := $(minijailCommonCFlags) -DPRELOADPATH=\"/invalid\"
# LOCAL_CLANG := true
# LOCAL_SRC_FILES := \
# $(libminijailSrcFiles) \
-# libminijail_unittest.c \
+# libminijail_unittest.cc \
# $(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_CPP_EXTENSION := .cc
LOCAL_CFLAGS := $(minijailCommonCFlags)
LOCAL_CLANG := true
LOCAL_SRC_FILES := \
bpf.c \
syscall_filter.c \
util.c \
- syscall_filter_unittest.cpp \
+ syscall_filter_unittest.cc \
LOCAL_STATIC_LIBRARIES := libminijail_generated
LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
@@ -228,19 +195,20 @@
# Syscall filtering native unit tests for the host. Run with:
-# out/host/linux-x86/nativetest(64)/syscall_filter_unittest/syscall_filter_unittest
+# out/host/linux-x86/nativetest(64)/syscall_filter_unittest/syscall_filter_unittest_gtest
# =========================================================
include $(CLEAR_VARS)
-LOCAL_MODULE := syscall_filter_unittest
+LOCAL_MODULE := syscall_filter_unittest_gtest
LOCAL_MODULE_HOST_OS := linux
+LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS := $(minijailCommonCFlags)
LOCAL_CLANG := true
LOCAL_SRC_FILES := \
bpf.c \
syscall_filter.c \
- syscall_filter_unittest.c \
util.c \
+ syscall_filter_unittest.cc \
$(hostUnittestSrcFiles)
LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
diff --git a/Makefile b/Makefile
index 1a6601c..b9e7ad8 100644
--- a/Makefile
+++ b/Makefile
@@ -19,13 +19,25 @@
CFLAGS += -Wextra
CXXFLAGS += -Wextra
+USE_SYSTEM_GTEST ?= no
+ifeq ($(USE_SYSTEM_GTEST),no)
+GTEST_CXXFLAGS :=
+GTEST_MAIN := gtest_main.a
+GTEST_LIBS := gtest.a
+else
+GTEST_CXXFLAGS := $(gtest-config --cxxflags)
+GTEST_MAIN := -lgtest_main
+GTEST_LIBS := $(gtest-config --libs)
+endif
+
all: CC_BINARY(minijail0) CC_LIBRARY(libminijail.so) \
- CC_LIBRARY(libminijailpreload.so)
+ CC_LIBRARY(libminijailpreload.so)
parse_seccomp_policy: CXX_BINARY(parse_seccomp_policy)
# TODO(jorgelo): convert to TEST().
-tests: CC_BINARY(libminijail_unittest) CC_BINARY(syscall_filter_unittest)
+tests: CXX_BINARY(libminijail_unittest) CXX_BINARY(syscall_filter_unittest)
+
CC_BINARY(minijail0): LDLIBS += -lcap -ldl
CC_BINARY(minijail0): libconstants.gen.o libsyscalls.gen.o libminijail.o \
@@ -33,32 +45,50 @@
syscall_wrapper.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 syscall_wrapper.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 \
+
+CXX_BINARY(libminijail_unittest): CXXFLAGS += -Wno-write-strings \
+ $(GTEST_CXXFLAGS)
+CXX_BINARY(libminijail_unittest): LDLIBS += -lcap $(GTEST_MAIN)
+ifeq ($(USE_SYSTEM_GTEST),no)
+CXX_BINARY(libminijail_unittest): $(GTEST_MAIN)
+endif
+CXX_BINARY(libminijail_unittest): libminijail_unittest.o libminijail.o \
syscall_filter.o signal_handler.o bpf.o util.o \
syscall_wrapper.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 syscall_wrapper.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
+
+CXX_BINARY(syscall_filter_unittest): CXXFLAGS += -Wno-write-strings \
+ $(GTEST_CXXFLAGS)
+CXX_BINARY(syscall_filter_unittest): LDLIBS += -lcap $(GTEST_MAIN)
+ifeq ($(USE_SYSTEM_GTEST),no)
+CXX_BINARY(syscall_filter_unittest): $(GTEST_MAIN)
+endif
+CXX_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)
+
CXX_BINARY(parse_seccomp_policy): parse_seccomp_policy.o syscall_filter.o \
bpf.o util.o libconstants.gen.o libsyscalls.gen.o
clean: CLEAN(parse_policy)
+
libsyscalls.gen.o: CPPFLAGS += -I$(SRC)
libsyscalls.gen.o.depends: libsyscalls.gen.c
@@ -86,3 +116,58 @@
clean: CLEAN(libconstants.gen.c)
$(eval $(call add_object_rules,libconstants.gen.o,CC,c,CFLAGS))
+
+
+################################################################################
+# Google Test
+
+ifeq ($(USE_SYSTEM_GTEST),no)
+# Points to the root of Google Test, relative to where this file is.
+# Remember to tweak this if you move this file.
+GTEST_DIR = googletest-release-1.8.0/googletest
+
+# Flags passed to the preprocessor.
+# Set Google Test's header directory as a system directory, such that
+# the compiler doesn't generate warnings in Google Test headers.
+CPPFLAGS += -isystem $(GTEST_DIR)/include
+
+# Flags passed to the C++ compiler.
+GTEST_CXXFLAGS := -pthread
+
+# All Google Test headers. Usually you shouldn't change this
+# definition.
+GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
+ $(GTEST_DIR)/include/gtest/internal/*.h
+
+# House-keeping build targets.
+clean: clean_gtest
+
+clean_gtest:
+ rm -f gtest.a gtest_main.a *.o
+
+# Builds gtest.a and gtest_main.a.
+
+# Usually you shouldn't tweak such internal variables, indicated by a
+# trailing _.
+GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
+
+# For simplicity and to avoid depending on Google Test's
+# implementation details, the dependencies specified below are
+# conservative and not optimized. This is fine as Google Test
+# compiles fast and for ordinary users its source rarely changes.
+gtest-all.o : $(GTEST_SRCS_)
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) $(GTEST_CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest-all.cc -o $@
+
+gtest_main.o : $(GTEST_SRCS_)
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) $(GTEST_CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest_main.cc -o $@
+
+gtest.a : gtest-all.o
+ $(AR) $(ARFLAGS) $@ $^
+
+gtest_main.a : gtest-all.o gtest_main.o
+ $(AR) $(ARFLAGS) $@ $^
+
+endif
+################################################################################
diff --git a/common.mk b/common.mk
index 4e47f2a..58252f9 100644
--- a/common.mk
+++ b/common.mk
@@ -319,8 +319,8 @@
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))
+CXXFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CXXDRIVER)) -std=gnu++11
+CFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CDRIVER)) -std=gnu11
CPPFLAGS += -D_FORTIFY_SOURCE=2
# Enable large file support.
diff --git a/get_googletest.sh b/get_googletest.sh
new file mode 100755
index 0000000..1708dcb
--- /dev/null
+++ b/get_googletest.sh
@@ -0,0 +1,6 @@
+#/bin/bash
+
+PV="1.8.0"
+
+wget -q -nc --secure-protocol=TLSv1 "https://github.com/google/googletest/archive/release-${PV}.tar.gz" -O "googletest-release-${PV}.tar.gz"
+tar zxvf "googletest-release-${PV}.tar.gz"
diff --git a/libminijail_unittest.c b/libminijail_unittest.c
deleted file mode 100644
index 199b658..0000000
--- a/libminijail_unittest.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/* 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 <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "test_harness.h"
-
-#include "libminijail-private.h"
-#include "libminijail.h"
-#include "util.h"
-
-#if defined(__ANDROID__)
-const char *kShellPath = "/system/bin/sh";
-#else
-const char *kShellPath = "/bin/sh";
-#endif
-
-/* 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);
-
- argv[0] = (char *)kShellPath;
- 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(test_minijail_no_fd_leaks)
-{
- pid_t pid;
- int child_stdout;
- int mj_run_ret;
- ssize_t read_ret;
- const size_t buf_len = 128;
- char buf[buf_len];
- char script[buf_len];
- int status;
- char *argv[4];
-
- int dev_null = open("/dev/null", O_RDONLY);
- ASSERT_NE(dev_null, -1);
- snprintf(script, sizeof(script),
- "[ -e /proc/self/fd/%d ] && echo yes || echo no", dev_null);
-
- struct minijail *j = minijail_new();
-
- argv[0] = (char *)kShellPath;
- argv[1] = "-c";
- argv[2] = script;
- argv[3] = NULL;
- mj_run_ret = minijail_run_pid_pipes_no_preload(
- j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
- EXPECT_EQ(mj_run_ret, 0);
-
- read_ret = read(child_stdout, buf, buf_len);
- EXPECT_GE(read_ret, 0);
- buf[read_ret] = '\0';
- EXPECT_STREQ(buf, "yes\n");
-
- waitpid(pid, &status, 0);
- ASSERT_TRUE(WIFEXITED(status));
- EXPECT_EQ(WEXITSTATUS(status), 0);
-
- minijail_close_open_fds(j);
- mj_run_ret = minijail_run_pid_pipes_no_preload(
- j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
- EXPECT_EQ(mj_run_ret, 0);
-
- read_ret = read(child_stdout, buf, buf_len);
- EXPECT_GE(read_ret, 0);
- buf[read_ret] = '\0';
- EXPECT_STREQ(buf, "no\n");
-
- waitpid(pid, &status, 0);
- ASSERT_TRUE(WIFEXITED(status));
- EXPECT_EQ(WEXITSTATUS(status), 0);
-
- minijail_destroy(j);
-
- close(dev_null);
-}
-
-TEST_HARNESS_MAIN
diff --git a/libminijail_unittest.cpp b/libminijail_unittest.cc
similarity index 100%
rename from libminijail_unittest.cpp
rename to libminijail_unittest.cc
diff --git a/syscall_filter_unittest.c b/syscall_filter_unittest.c
deleted file mode 100644
index 814b3cb..0000000
--- a/syscall_filter_unittest.c
+++ /dev/null
@@ -1,1266 +0,0 @@
-/* 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(util){};
-
-FIXTURE_SETUP(util)
-{
-}
-FIXTURE_TEARDOWN(util)
-{
-}
-
-TEST_F(util, parse_constant_unsigned)
-{
- char *end;
- long int c = 0;
-
-#if defined(BITS32)
- c = parse_constant("0x80000000", &end);
- EXPECT_EQ((unsigned long int)c, 0x80000000U);
-
-#elif defined(BITS64)
- c = parse_constant("0x8000000000000000", &end);
- EXPECT_EQ((unsigned long int)c, 0x8000000000000000UL);
-#endif
-}
-
-TEST_F(util, parse_constant_unsigned_toobig)
-{
- char *end;
- long int c = 0;
-
-#if defined(BITS32)
- /* Error case should return 0. */
- c = parse_constant("0x100000000", &end);
- EXPECT_EQ(c, 0);
-
-#elif defined(BITS64)
- /* Error case should return 0. */
- c = parse_constant("0x10000000000000000", &end);
- EXPECT_EQ(c, 0);
-#endif
-}
-
-TEST_F(util, parse_constant_signed)
-{
- char *end;
- long int c = 0;
- c = parse_constant("-1", &end);
- EXPECT_EQ(c, -1);
-
-#if defined(BITS32)
- c = parse_constant("-0x80000001", &end);
- /* Error case should return 0. */
- EXPECT_EQ(c, 0);
-#elif defined(BITS64)
- c = parse_constant("-0x8000000000000001", &end);
- /* Error case should return 0. */
- EXPECT_EQ(c, 0);
-#endif
-}
-
-TEST_F(util, parse_constant_signed_toonegative)
-{
- char *end;
- long int c = 0;
-
-#if defined(BITS32)
- c = parse_constant("-0x80000001", &end);
- /* Error case should return 0. */
- EXPECT_EQ(c, 0);
-
-#elif defined(BITS64)
- c = parse_constant("-0x8000000000000001", &end);
- /* Error case should return 0. */
- EXPECT_EQ(c, 0);
-#endif
-}
-
-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 =
- (1UL << (sizeof(unsigned long) * 8 - 1)) | 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, 0x80000000,
- 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, O_WRONLY, jt,
- jf);
-#endif
-}
-
-TEST_F(bpf, bpf_comp_jin)
-{
- struct sock_filter comp_jin[BPF_COMP_LEN];
- unsigned long mask =
- (1UL << (sizeof(unsigned long) * 8 - 1)) | O_WRONLY;
- unsigned char jt = 10;
- unsigned char jf = 20;
-
- size_t len = bpf_comp_jin(comp_jin, mask, jt, jf);
-
- EXPECT_EQ(len, BPF_COMP_LEN);
-
-#if defined(BITS32)
- EXPECT_EQ_BLOCK(&comp_jin[0], BPF_JMP + BPF_JSET + BPF_K, ~mask, jf,
- jt);
-#elif defined(BITS64)
- EXPECT_EQ_BLOCK(&comp_jin[0], BPF_JMP + BPF_JSET + BPF_K, 0x7FFFFFFF,
- jf + 2, 0);
- EXPECT_EQ_STMT(&comp_jin[1], BPF_LD + BPF_MEM, 0);
- EXPECT_EQ_BLOCK(&comp_jin[2], BPF_JMP + BPF_JSET + BPF_K, ~O_WRONLY, jf,
- jt);
-#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(bpf_label)
-{
- struct bpf_labels labels;
-};
-
-FIXTURE_SETUP(bpf_label)
-{
-}
-FIXTURE_TEARDOWN(bpf_label)
-{
- free_label_strings(&self->labels);
-}
-
-TEST_F(bpf_label, zero_length_filter)
-{
- int res = bpf_resolve_jumps(&self->labels, NULL, 0);
-
- EXPECT_EQ(res, 0);
- EXPECT_EQ(self->labels.count, 0U);
-}
-
-TEST_F(bpf_label, single_label)
-{
- struct sock_filter test_label[1];
-
- int id = bpf_label_id(&self->labels, "test");
- set_bpf_lbl(test_label, id);
- int res = bpf_resolve_jumps(&self->labels, test_label, 1);
-
- EXPECT_EQ(res, 0);
- EXPECT_EQ(self->labels.count, 1U);
-}
-
-TEST_F(bpf_label, repeated_label)
-{
- struct sock_filter test_label[2];
-
- int id = bpf_label_id(&self->labels, "test");
- set_bpf_lbl(&test_label[0], id);
- set_bpf_lbl(&test_label[1], id);
- int res = bpf_resolve_jumps(&self->labels, test_label, 2);
-
- EXPECT_EQ(res, -1);
-}
-
-TEST_F(bpf_label, jump_with_no_label)
-{
- struct sock_filter test_jump[1];
-
- set_bpf_jump_lbl(test_jump, 14831);
- int res = bpf_resolve_jumps(&self->labels, test_jump, 1);
-
- EXPECT_EQ(res, -1);
-}
-
-TEST_F(bpf_label, jump_to_valid_label)
-{
- struct sock_filter test_jump[2];
-
- int id = bpf_label_id(&self->labels, "test");
- set_bpf_jump_lbl(&test_jump[0], id);
- set_bpf_lbl(&test_jump[1], id);
-
- int res = bpf_resolve_jumps(&self->labels, test_jump, 2);
- EXPECT_EQ(res, 0);
- EXPECT_EQ(self->labels.count, 1U);
-}
-
-TEST_F(bpf_label, jump_to_invalid_label)
-{
- struct sock_filter test_jump[2];
-
- int id = bpf_label_id(&self->labels, "test");
- set_bpf_jump_lbl(&test_jump[0], id + 1);
- set_bpf_lbl(&test_jump[1], id);
-
- int res = bpf_resolve_jumps(&self->labels, test_jump, 2);
- EXPECT_EQ(res, -1);
-}
-
-TEST_F(bpf_label, jump_to_unresolved_label)
-{
- struct sock_filter test_jump[2];
-
- int id = bpf_label_id(&self->labels, "test");
- /* Notice the order of the instructions is reversed. */
- set_bpf_lbl(&test_jump[0], id);
- set_bpf_jump_lbl(&test_jump[1], id);
-
- int res = bpf_resolve_jumps(&self->labels, test_jump, 2);
- EXPECT_EQ(res, -1);
-}
-
-TEST_F(bpf_label, too_many_labels)
-{
- unsigned int i;
- char label[20];
-
- for (i = 0; i < BPF_LABELS_MAX; i++) {
- snprintf(label, 20, "test%u", i);
- (void)bpf_label_id(&self->labels, label);
- }
- int id = bpf_label_id(&self->labels, "test");
-
- /* Insertion failed. */
- EXPECT_EQ(id, -1);
- /* Because label lookup table is full. */
- EXPECT_EQ(self->labels.count, BPF_LABELS_MAX);
-}
-
-FIXTURE(arg_filter)
-{
- struct bpf_labels labels;
-};
-
-FIXTURE_SETUP(arg_filter)
-{
-}
-FIXTURE_TEARDOWN(arg_filter)
-{
- free_label_strings(&self->labels);
-}
-
-TEST_F(arg_filter, empty_atom)
-{
- const char *fragment = "";
- int nr = 1;
- unsigned int id = 0;
-
- struct filter_block *block =
- compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
- ASSERT_EQ(block, NULL);
-}
-
-TEST_F(arg_filter, no_comparison)
-{
- const char *fragment = "arg0";
- int nr = 1;
- unsigned int id = 0;
-
- struct filter_block *block =
- compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
- ASSERT_EQ(block, NULL);
-}
-
-TEST_F(arg_filter, no_constant)
-{
- const char *fragment = "arg0 ==";
- int nr = 1;
- unsigned int id = 0;
-
- struct filter_block *block =
- compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
- ASSERT_EQ(block, NULL);
-}
-
-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_flag_set_inclusion)
-{
- const char *fragment = "arg0 in O_RDONLY|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);
-
- /* 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_arg_token)
-{
- const char *fragment = "org0 == 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);
-}
-
-TEST_F(arg_filter, invalid_arg_number)
-{
- 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);
-}
-
-TEST_F(arg_filter, extra_chars_in_arg_token)
-{
- const char *fragment = "arg0n == 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);
-}
-
-TEST_F(arg_filter, invalid_operator)
-{
- const char *fragment = "arg0 invalidop 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);
-}
-
-TEST_F(arg_filter, invalid_constant)
-{
- const char *fragment = "arg0 == INVALIDCONSTANT";
- int nr = 1;
- unsigned int id = 0;
-
- struct filter_block *block =
- compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
- ASSERT_EQ(block, NULL);
-}
-
-TEST_F(arg_filter, extra_tokens)
-{
- const char *fragment = "arg0 == 0 EXTRATOKEN";
- int nr = 1;
- unsigned int id = 0;
-
- struct filter_block *block =
- compile_section(nr, fragment, id, &self->labels, NO_LOGGING);
- ASSERT_EQ(block, NULL);
-}
-
-TEST_F(arg_filter, invalid_errno)
-{
- const char *fragment = "arg0 == 0 && arg1 == 1; return errno";
- int nr = 1;
- unsigned int id = 0;
-
- struct filter_block *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, USE_RET_KILL, 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_mode1_trap)
-{
- 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_RET_TRAP, 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_TRAP);
-
- 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, USE_RET_KILL, 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, missing_atom)
-{
- struct sock_fprog actual;
- const char *policy = "open:\n";
-
- FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
- ASSERT_NE(policy_file, NULL);
-
- int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
- fclose(policy_file);
- ASSERT_NE(res, 0);
-}
-
-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, 0, 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, 0, NO_LOGGING);
- fclose(policy_file);
- ASSERT_NE(res, 0);
-}
-
-TEST_F(filter, nonexistent)
-{
- struct sock_fprog actual;
- int res = compile_filter(NULL, &actual, 0, 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_RET_TRAP, 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_F(filter, allow_log_but_kill)
-{
- 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_RET_KILL, 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_KILL);
-
- free(actual.filter);
-}
-
-TEST_HARNESS_MAIN
diff --git a/syscall_filter_unittest.cpp b/syscall_filter_unittest.cc
similarity index 99%
rename from syscall_filter_unittest.cpp
rename to syscall_filter_unittest.cc
index 3b99b02..98a1835 100644
--- a/syscall_filter_unittest.cpp
+++ b/syscall_filter_unittest.cc
@@ -105,7 +105,7 @@
TEST(bpf, bpf_load_arg) {
struct sock_filter load_arg[BPF_LOAD_ARG_LEN];
- int argidx = 1;
+ const int argidx = 1;
size_t len = bpf_load_arg(load_arg, argidx);
EXPECT_EQ(len, BPF_LOAD_ARG_LEN);
@@ -182,7 +182,7 @@
TEST(bpf, bpf_arg_comp) {
struct sock_filter *arg_comp;
int op = EQ;
- int argidx = 1;
+ const int argidx = 1;
unsigned long c = 3;
unsigned int label_id = 0;
@@ -240,6 +240,7 @@
class BpfLabelTest : public ::testing::Test {
protected:
+ virtual void SetUp() { labels_.count = 0; }
virtual void TearDown() { free_label_strings(&labels_); }
struct bpf_labels labels_;
};
@@ -335,6 +336,7 @@
class ArgFilterTest : public ::testing::Test {
protected:
+ virtual void SetUp() { labels_.count = 0; }
virtual void TearDown() { free_label_strings(&labels_); }
struct bpf_labels labels_;
};