aboutsummaryrefslogtreecommitdiff
path: root/syscall_filter_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'syscall_filter_unittest.cc')
-rw-r--r--syscall_filter_unittest.cc245
1 files changed, 240 insertions, 5 deletions
diff --git a/syscall_filter_unittest.cc b/syscall_filter_unittest.cc
index 4a80976..85c8a55 100644
--- a/syscall_filter_unittest.cc
+++ b/syscall_filter_unittest.cc
@@ -948,7 +948,6 @@ class FileTest : public ::testing::Test {
};
TEST_F(FileTest, seccomp_mode1) {
- // struct sock_fprog actual;
const char *policy =
"read: 1\n"
"write: 1\n"
@@ -958,7 +957,7 @@ TEST_F(FileTest, seccomp_mode1) {
FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
ASSERT_NE(policy_file, nullptr);
int res = compile_file(
- policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING);
+ policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
fclose(policy_file);
/*
@@ -993,7 +992,7 @@ TEST_F(FileTest, seccomp_read) {
FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
ASSERT_NE(policy_file, nullptr);
int res = compile_file(
- policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING);
+ policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
fclose(policy_file);
/*
@@ -1174,7 +1173,7 @@ TEST(FilterTest, missing_atom) {
struct sock_fprog actual;
const char* policy = "open:\n";
- FILE* policy_file = write_policy_to_pipe(policy, strlen(policy));
+ FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
ASSERT_NE(policy_file, nullptr);
int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
@@ -1186,7 +1185,7 @@ TEST(FilterTest, whitespace_atom) {
struct sock_fprog actual;
const char* policy = "open:\t \n";
- FILE* policy_file = write_policy_to_pipe(policy, strlen(policy));
+ FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
ASSERT_NE(policy_file, nullptr);
int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
@@ -1315,3 +1314,239 @@ TEST(FilterTest, allow_log_but_kill) {
free(actual.filter);
}
+
+TEST(FilterTest, include_invalid_token) {
+ struct sock_fprog actual;
+ const char *invalid_token = "@unclude ./test/seccomp.policy\n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(invalid_token, strlen(invalid_token));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_no_space) {
+ struct sock_fprog actual;
+ const char *no_space = "@includetest/seccomp.policy\n";
+
+ FILE *policy_file = write_policy_to_pipe(no_space, strlen(no_space));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_double_token) {
+ struct sock_fprog actual;
+ const char *double_token = "@includeinclude ./test/seccomp.policy\n";
+
+ FILE *policy_file = write_policy_to_pipe(double_token, strlen(double_token));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_no_file) {
+ struct sock_fprog actual;
+ const char *no_file = "@include\n";
+
+ FILE *policy_file = write_policy_to_pipe(no_file, strlen(no_file));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_space_no_file) {
+ struct sock_fprog actual;
+ const char *space_no_file = "@include \n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(space_no_file, strlen(space_no_file));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_implicit_relative_path) {
+ struct sock_fprog actual;
+ const char *implicit_relative_path = "@include test/seccomp.policy\n";
+
+ FILE *policy_file = write_policy_to_pipe(implicit_relative_path,
+ strlen(implicit_relative_path));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_extra_text) {
+ struct sock_fprog actual;
+ const char *extra_text = "@include /some/file: sneaky comment\n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(extra_text, strlen(extra_text));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_split_filename) {
+ struct sock_fprog actual;
+ const char *split_filename = "@include /some/file:colon.policy\n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(split_filename, strlen(split_filename));
+ ASSERT_NE(policy_file, nullptr);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ EXPECT_NE(res, 0);
+}
+
+TEST(FilterTest, include_nonexistent_file) {
+ struct sock_fprog actual;
+ const char *include_policy = "@include ./nonexistent.policy\n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(include_policy, strlen(include_policy));
+ ASSERT_NE(policy_file, nullptr);
+
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+
+ ASSERT_NE(res, 0);
+}
+
+// TODO(jorgelo): Android unit tests don't currently support data files.
+// Re-enable by creating a temporary policy file at runtime.
+#if !defined(__ANDROID__)
+
+TEST(FilterTest, include) {
+ struct sock_fprog compiled_plain;
+ struct sock_fprog compiled_with_include;
+
+ const char *policy_plain =
+ "read: 1\n"
+ "write: 1\n"
+ "rt_sigreturn: 1\n"
+ "exit: 1\n";
+
+ const char *policy_with_include = "@include ./test/seccomp.policy\n";
+
+ FILE *file_plain = write_policy_to_pipe(policy_plain, strlen(policy_plain));
+ ASSERT_NE(file_plain, nullptr);
+ int res_plain =
+ compile_filter(file_plain, &compiled_plain, USE_RET_KILL, NO_LOGGING);
+ fclose(file_plain);
+
+ FILE *file_with_include =
+ write_policy_to_pipe(policy_with_include, strlen(policy_with_include));
+ ASSERT_NE(file_with_include, nullptr);
+ int res_with_include = compile_filter(
+ file_with_include, &compiled_with_include, USE_RET_KILL, NO_LOGGING);
+ fclose(file_with_include);
+
+ /*
+ * Checks that filter length is the same for a plain policy and an equivalent
+ * policy with an @include statement. Also checks that the filter generated
+ * from the policy with an @include statement is exactly the same as one
+ * generated from a plain policy.
+ */
+ ASSERT_EQ(res_plain, 0);
+ ASSERT_EQ(res_with_include, 0);
+
+ EXPECT_EQ(compiled_plain.len, 13);
+ EXPECT_EQ(compiled_with_include.len, 13);
+
+ EXPECT_ARCH_VALIDATION(compiled_with_include.filter);
+ EXPECT_EQ_STMT(compiled_with_include.filter + ARCH_VALIDATION_LEN,
+ BPF_LD + BPF_W + BPF_ABS,
+ syscall_nr);
+ EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 1,
+ __NR_read);
+ EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 3,
+ __NR_write);
+ EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 5,
+ __NR_rt_sigreturn);
+ EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 7,
+ __NR_exit);
+ EXPECT_EQ_STMT(compiled_with_include.filter + ARCH_VALIDATION_LEN + 9,
+ BPF_RET + BPF_K,
+ SECCOMP_RET_KILL);
+
+ free(compiled_plain.filter);
+ free(compiled_with_include.filter);
+}
+
+TEST(FilterTest, include_same_syscalls) {
+ struct sock_fprog actual;
+ const char *policy =
+ "read: 1\n"
+ "write: 1\n"
+ "rt_sigreturn: 1\n"
+ "exit: 1\n"
+ "@include ./test/seccomp.policy\n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(policy, strlen(policy));
+ ASSERT_NE(policy_file, nullptr);
+
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+
+ ASSERT_EQ(res, 0);
+ EXPECT_EQ(actual.len,
+ ARCH_VALIDATION_LEN + 1 /* load syscall nr */ +
+ 2 * 8 /* check syscalls twice */ + 1 /* filter return */);
+ free(actual.filter);
+}
+
+TEST(FilterTest, include_invalid_policy) {
+ struct sock_fprog actual;
+ const char *policy =
+ "read: 1\n"
+ "write: 1\n"
+ "rt_sigreturn: 1\n"
+ "exit: 1\n"
+ "@include ./test/invalid_syscall_name.policy\n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(policy, strlen(policy));
+ ASSERT_NE(policy_file, nullptr);
+
+ /* Ensure the included (invalid) policy file exists. */
+ FILE *included_file = fopen("./test/invalid_syscall_name.policy", "r");
+ ASSERT_NE(included_file, nullptr);
+ fclose(included_file);
+
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+
+ ASSERT_NE(res, 0);
+}
+
+TEST(FilterTest, include_nested) {
+ struct sock_fprog actual;
+ const char *policy = "@include ./test/nested.policy\n";
+
+ FILE *policy_file =
+ write_policy_to_pipe(policy, strlen(policy));
+ ASSERT_NE(policy_file, nullptr);
+
+ /* Ensure the policy file exists. */
+ FILE *included_file = fopen("./test/nested.policy", "r");
+ ASSERT_NE(included_file, nullptr);
+ fclose(included_file);
+
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+
+ ASSERT_NE(res, 0);
+}
+
+#endif // !__ANDROID__