aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJorge Lucangeli Obes <jorgelo@google.com>2017-03-21 18:32:59 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-03-21 18:32:59 +0000
commit19cbdd29f9cec75d39ec304bc16c31f72d20971e (patch)
treea0301307d81a286b5c4577e9ab9b3912c6266168
parentf9d1827377770395b8cd4e01253dbe959124164d (diff)
parent45932a51abc18f3daddba7776fcfe7d3517da68c (diff)
downloadminijail-19cbdd29f9cec75d39ec304bc16c31f72d20971e.tar.gz
syscall_filter: Refactor 'compile_file' out of 'compile_filter'.
am: 45932a51ab Change-Id: I64ebb2949590f8132bd9652105af5fe6a9933c8a
-rw-r--r--Android.mk2
-rw-r--r--bpf.c4
-rw-r--r--parse_seccomp_policy.cc2
-rw-r--r--syscall_filter.c127
-rw-r--r--syscall_filter.h14
-rw-r--r--syscall_filter_unittest.cc220
-rw-r--r--syscall_filter_unittest_macros.h8
7 files changed, 274 insertions, 103 deletions
diff --git a/Android.mk b/Android.mk
index 6a63e87..ecc5e97 100644
--- a/Android.mk
+++ b/Android.mk
@@ -195,7 +195,7 @@ 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_gtest
+# out/host/linux-x86/nativetest(64)/syscall_filter_unittest_gtest/syscall_filter_unittest_gtest
# =========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := syscall_filter_unittest_gtest
diff --git a/bpf.c b/bpf.c
index b618866..8f5a08d 100644
--- a/bpf.c
+++ b/bpf.c
@@ -267,8 +267,9 @@ int bpf_label_id(struct bpf_labels *labels, const char *label)
}
end = begin + labels->count;
for (id = 0; begin < end; ++begin, ++id) {
- if (!strcmp(label, begin->label))
+ if (!strcmp(label, begin->label)) {
return id;
+ }
}
/* The label wasn't found. Insert it only if there's space. */
@@ -284,7 +285,6 @@ int bpf_label_id(struct bpf_labels *labels, const char *label)
return id;
}
-/* Free label strings. */
void free_label_strings(struct bpf_labels *labels)
{
if (labels->count == 0)
diff --git a/parse_seccomp_policy.cc b/parse_seccomp_policy.cc
index c50b79e..a9daed0 100644
--- a/parse_seccomp_policy.cc
+++ b/parse_seccomp_policy.cc
@@ -32,7 +32,7 @@ int main(int argc, char **argv) {
}
struct sock_fprog fp;
- int res = compile_filter(f, &fp, 0);
+ int res = compile_filter(f, &fp, 0, 0);
if (res != 0) {
die("compile_filter failed");
}
diff --git a/syscall_filter.c b/syscall_filter.c
index ad84921..3318052 100644
--- a/syscall_filter.c
+++ b/syscall_filter.c
@@ -12,14 +12,13 @@
#include "util.h"
/* clang-format off */
-#define MAX_LINE_LENGTH 1024
#define MAX_POLICY_LINE_LENGTH 1024
#define ONE_INSTR 1
#define TWO_INSTRS 2
/* clang-format on */
-int seccomp_can_softfail()
+int seccomp_can_softfail(void)
{
#if defined(USE_SECCOMP_SOFTFAIL)
return 1;
@@ -51,7 +50,7 @@ struct sock_filter *new_instr_buf(size_t count)
return buf;
}
-struct filter_block *new_filter_block()
+struct filter_block *new_filter_block(void)
{
struct filter_block *block = calloc(1, sizeof(struct filter_block));
if (!block)
@@ -278,10 +277,10 @@ int compile_errno(struct filter_block *head, char *ret_errno, int use_ret_trap)
return 0;
}
-struct filter_block *compile_section(int nr, const char *policy_line,
- unsigned int entry_lbl_id,
- struct bpf_labels *labels,
- int use_ret_trap)
+struct filter_block *compile_policy_line(int nr, const char *policy_line,
+ unsigned int entry_lbl_id,
+ struct bpf_labels *labels,
+ int use_ret_trap)
{
/*
* |policy_line| should be an expression of the form:
@@ -429,35 +428,10 @@ struct filter_block *compile_section(int nr, const char *policy_line,
return head;
}
-int compile_filter(FILE *policy_file, struct sock_fprog *prog, int use_ret_trap,
- int allow_logging)
+int compile_file(FILE *policy_file, struct filter_block *head,
+ struct filter_block **arg_blocks, struct bpf_labels *labels,
+ int use_ret_trap, int allow_logging)
{
- 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 logging failures, allow the necessary syscalls first. */
- if (allow_logging)
- allow_logging_syscalls(head);
-
/*
* Loop through all the lines in the policy file.
* Build a jump table for the syscall number.
@@ -466,8 +440,9 @@ int compile_filter(FILE *policy_file, struct sock_fprog *prog, int use_ret_trap,
* 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 *line = NULL;
+ size_t len = 0;
+ while (getline(&line, &len, policy_file) != -1) {
char *policy_line = line;
char *syscall_name = strsep(&policy_line, ":");
int nr = -1;
@@ -475,18 +450,21 @@ int compile_filter(FILE *policy_file, struct sock_fprog *prog, int use_ret_trap,
syscall_name = strip(syscall_name);
/* Allow comments and empty lines. */
- if (*syscall_name == '#' || *syscall_name == '\0')
+ if (*syscall_name == '#' || *syscall_name == '\0') {
+ /* Reuse |line| in the next getline() call. */
continue;
+ }
- if (strlen(policy_line) == 0) {
- warn("compile_filter: empty policy line");
- free_block_list(head);
+ policy_line = strip(policy_line);
+ if (*policy_line == '\0') {
+ warn("compile_file: empty policy line");
+ free(line);
return -1;
}
nr = lookup_syscall(syscall_name);
if (nr < 0) {
- warn("compile_filter: nonexistent syscall '%s'",
+ warn("compile_file: nonexistent syscall '%s'",
syscall_name);
if (allow_logging) {
/*
@@ -500,14 +478,13 @@ int compile_filter(FILE *policy_file, struct sock_fprog *prog, int use_ret_trap,
* syscall is made, so there's no added attack
* surface.
*/
+ /* Reuse |line| in the next getline() call. */
continue;
}
- free_block_list(head);
+ free(line);
return -1;
}
- policy_line = strip(policy_line);
-
/*
* For each syscall, add either a simple ALLOW,
* or an arg filter block.
@@ -520,31 +497,71 @@ int compile_filter(FILE *policy_file, struct sock_fprog *prog, int use_ret_trap,
* Create and jump to the label that will hold
* the arg filter block.
*/
- unsigned int id = bpf_label_id(&labels, syscall_name);
+ 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, use_ret_trap);
+ struct filter_block *block = compile_policy_line(
+ nr, policy_line, id, labels, use_ret_trap);
if (!block) {
- if (arg_blocks) {
- free_block_list(arg_blocks);
+ if (*arg_blocks) {
+ free_block_list(*arg_blocks);
}
- free_label_strings(&labels);
- free_block_list(head);
+ free(line);
return -1;
}
- if (arg_blocks) {
- extend_filter_block_list(arg_blocks, block);
+ if (*arg_blocks) {
+ extend_filter_block_list(*arg_blocks, block);
} else {
- arg_blocks = block;
+ *arg_blocks = block;
}
}
+ /* Reuse |line| in the next getline() call. */
+ }
+ free(line);
+ return 0;
+}
+
+int compile_filter(FILE *initial_file, struct sock_fprog *prog,
+ int use_ret_trap, int allow_logging)
+{
+ struct bpf_labels labels;
+ labels.count = 0;
+
+ if (!initial_file) {
+ warn("compile_filter: |initial_file| is NULL");
+ 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 logging failures, allow the necessary syscalls first. */
+ if (allow_logging)
+ allow_logging_syscalls(head);
+
+ if (compile_file(initial_file, head, &arg_blocks, &labels, use_ret_trap,
+ allow_logging) != 0) {
+ warn("compile_filter: compile_file() failed");
+ free_block_list(head);
+ free_block_list(arg_blocks);
+ free_label_strings(&labels);
+ return -1;
}
/*
diff --git a/syscall_filter.h b/syscall_filter.h
index 4625d80..3bfbfee 100644
--- a/syscall_filter.h
+++ b/syscall_filter.h
@@ -26,18 +26,22 @@ struct filter_block {
struct bpf_labels;
-struct filter_block *compile_section(int nr, const char *policy_line,
- unsigned int label_id,
- struct bpf_labels *labels,
- int do_ret_trap);
+struct filter_block *compile_policy_line(int nr, const char *policy_line,
+ unsigned int label_id,
+ struct bpf_labels *labels,
+ int do_ret_trap);
+int compile_file(FILE *policy_file, struct filter_block *head,
+ struct filter_block **arg_blocks, struct bpf_labels *labels,
+ int use_ret_trap, int allow_logging);
int compile_filter(FILE *policy_file, struct sock_fprog *prog, int do_ret_trap,
int add_logging_syscalls);
+struct filter_block *new_filter_block(void);
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();
+int seccomp_can_softfail(void);
#ifdef __cplusplus
}; /* extern "C" */
diff --git a/syscall_filter_unittest.cc b/syscall_filter_unittest.cc
index 98a1835..4a80976 100644
--- a/syscall_filter_unittest.cc
+++ b/syscall_filter_unittest.cc
@@ -347,7 +347,17 @@ TEST_F(ArgFilterTest, empty_atom) {
unsigned int id = 0;
struct filter_block* block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+ ASSERT_EQ(block, nullptr);
+}
+
+TEST_F(ArgFilterTest, whitespace_atom) {
+ const char* fragment = "\t ";
+ int nr = 1;
+ unsigned int id = 0;
+
+ struct filter_block* block =
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -357,7 +367,7 @@ TEST_F(ArgFilterTest, no_comparison) {
unsigned int id = 0;
struct filter_block* block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -367,7 +377,7 @@ TEST_F(ArgFilterTest, no_constant) {
unsigned int id = 0;
struct filter_block* block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -376,7 +386,7 @@ TEST_F(ArgFilterTest, arg0_equals) {
int nr = 1;
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -385,11 +395,11 @@ TEST_F(ArgFilterTest, arg0_equals) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison. */
- curr_block = block->next;
+ curr_block = curr_block->next;
EXPECT_COMP(curr_block);
/* Third block is a jump and a label (end of AND group). */
@@ -417,7 +427,7 @@ TEST_F(ArgFilterTest, arg0_mask) {
int nr = 1;
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -426,11 +436,11 @@ TEST_F(ArgFilterTest, arg0_mask) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison. */
- curr_block = block->next;
+ curr_block = curr_block->next;
EXPECT_COMP(curr_block);
/* Third block is a jump and a label (end of AND group). */
@@ -458,7 +468,7 @@ TEST_F(ArgFilterTest, arg0_flag_set_inclusion) {
int nr = 1;
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -467,11 +477,11 @@ TEST_F(ArgFilterTest, arg0_flag_set_inclusion) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison. */
- curr_block = block->next;
+ curr_block = curr_block->next;
ASSERT_NE(curr_block, nullptr);
EXPECT_COMP(curr_block);
@@ -501,7 +511,7 @@ TEST_F(ArgFilterTest, arg0_eq_mask) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -510,11 +520,11 @@ TEST_F(ArgFilterTest, arg0_eq_mask) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison. */
- curr_block = block->next;
+ curr_block = curr_block->next;
ASSERT_NE(curr_block, nullptr);
EXPECT_COMP(curr_block);
EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
@@ -546,7 +556,7 @@ TEST_F(ArgFilterTest, and_or) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
EXPECT_EQ(block->total_len, exp_total_len);
@@ -554,7 +564,7 @@ TEST_F(ArgFilterTest, and_or) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison ("arg0 == 0"). */
@@ -603,7 +613,7 @@ TEST_F(ArgFilterTest, ret_errno) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
EXPECT_EQ(block->total_len, exp_total_len);
@@ -611,7 +621,7 @@ TEST_F(ArgFilterTest, ret_errno) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison ("arg0 == 0"). */
@@ -658,7 +668,7 @@ TEST_F(ArgFilterTest, unconditional_errno) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 2;
EXPECT_EQ(block->total_len, exp_total_len);
@@ -666,7 +676,7 @@ TEST_F(ArgFilterTest, unconditional_errno) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is SECCOMP_RET_ERRNO. */
@@ -688,7 +698,7 @@ TEST_F(ArgFilterTest, invalid_arg_token) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -698,7 +708,7 @@ TEST_F(ArgFilterTest, invalid_arg_number) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -708,7 +718,7 @@ TEST_F(ArgFilterTest, extra_chars_in_arg_token) {
unsigned int id = 0;
struct filter_block* block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -718,7 +728,7 @@ TEST_F(ArgFilterTest, invalid_operator) {
unsigned int id = 0;
struct filter_block* block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -728,7 +738,7 @@ TEST_F(ArgFilterTest, invalid_constant) {
unsigned int id = 0;
struct filter_block* block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -738,7 +748,7 @@ TEST_F(ArgFilterTest, extra_tokens) {
unsigned int id = 0;
struct filter_block* block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -748,7 +758,7 @@ TEST_F(ArgFilterTest, invalid_errno) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_EQ(block, nullptr);
}
@@ -757,7 +767,7 @@ TEST_F(ArgFilterTest, log_no_ret_error) {
int nr = 1;
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, USE_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -766,11 +776,11 @@ TEST_F(ArgFilterTest, log_no_ret_error) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison. */
- curr_block = block->next;
+ curr_block = curr_block->next;
ASSERT_NE(curr_block, nullptr);
EXPECT_COMP(curr_block);
@@ -800,7 +810,7 @@ TEST_F(ArgFilterTest, log_bad_ret_error) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
EXPECT_EQ(block->total_len, exp_total_len);
@@ -808,7 +818,7 @@ TEST_F(ArgFilterTest, log_bad_ret_error) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison ("arg0 == 0"). */
@@ -844,7 +854,7 @@ TEST_F(ArgFilterTest, no_log_bad_ret_error) {
unsigned int id = 0;
struct filter_block *block =
- compile_section(nr, fragment, id, &labels_, USE_LOGGING);
+ compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
ASSERT_NE(block, nullptr);
size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
EXPECT_EQ(block->total_len, exp_total_len);
@@ -852,7 +862,7 @@ TEST_F(ArgFilterTest, no_log_bad_ret_error) {
/* First block is a label. */
struct filter_block *curr_block = block;
ASSERT_NE(curr_block, nullptr);
- EXPECT_EQ(block->len, 1U);
+ EXPECT_EQ(curr_block->len, 1U);
EXPECT_LBL(curr_block->instrs);
/* Second block is a comparison ("arg0 == 0"). */
@@ -920,6 +930,126 @@ FILE *write_policy_to_pipe(const char *policy, size_t len) {
return fdopen(pipefd[0], "r");
}
+class FileTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ labels_.count = 0;
+ head_ = new_filter_block();
+ arg_blocks_ = NULL;
+ }
+ virtual void TearDown() {
+ free_label_strings(&labels_);
+ free_block_list(head_);
+ free_block_list(arg_blocks_);
+ }
+ struct bpf_labels labels_;
+ struct filter_block *head_;
+ struct filter_block *arg_blocks_;
+};
+
+TEST_F(FileTest, 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, nullptr);
+ int res = compile_file(
+ policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+
+ /*
+ * Checks return value and that the blocks only allow expected syscalls.
+ */
+ ASSERT_EQ(res, 0);
+ struct filter_block *curr_block = head_;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_read);
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_write);
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_rt_sigreturn);
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_exit);
+
+ EXPECT_EQ(curr_block->next, nullptr);
+}
+
+TEST_F(FileTest, seccomp_read) {
+ const char *policy =
+ "read: arg0 == 0\n"
+ "write: 1\n"
+ "rt_sigreturn: 1\n"
+ "exit: 1\n";
+
+ const int LABEL_ID = 0;
+
+ 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);
+ fclose(policy_file);
+
+ /*
+ * Checks return value, that the blocks only allow expected syscalls, and that
+ * labels between |head_| and |arg_blocks_| match.
+ */
+ ASSERT_EQ(res, 0);
+ struct filter_block *curr_block = head_;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL_ARGS(curr_block->instrs,
+ __NR_read,
+ LABEL_ID,
+ JUMP_JT,
+ JUMP_JF);
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_write);
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_rt_sigreturn);
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_exit);
+
+ ASSERT_NE(arg_blocks_, nullptr);
+ size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+ EXPECT_EQ(arg_blocks_->total_len, exp_total_len);
+
+ /* First block is a label. */
+ curr_block = arg_blocks_;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_EQ(curr_block->len, 1U);
+ EXPECT_ACTUAL_LBL(curr_block->instrs, LABEL_ID);
+
+ /* Second block is a comparison. */
+ curr_block = curr_block->next;
+ 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, nullptr);
+ EXPECT_GROUP_END(curr_block);
+
+ /* Fourth block is SECCOMP_RET_KILL. */
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_KILL(curr_block);
+
+ /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+ curr_block = curr_block->next;
+ ASSERT_NE(curr_block, nullptr);
+ EXPECT_ALLOW(curr_block);
+
+ EXPECT_EQ(curr_block->next, nullptr);
+}
+
TEST(FilterTest, seccomp_mode1) {
struct sock_fprog actual;
const char *policy =
@@ -1047,7 +1177,19 @@ TEST(FilterTest, missing_atom) {
FILE* policy_file = write_policy_to_pipe(policy, strlen(policy));
ASSERT_NE(policy_file, nullptr);
- int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+ fclose(policy_file);
+ ASSERT_NE(res, 0);
+}
+
+TEST(FilterTest, whitespace_atom) {
+ struct sock_fprog actual;
+ const char* policy = "open:\t \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_NE(res, 0);
}
@@ -1059,7 +1201,7 @@ TEST(FilterTest, invalid_name) {
FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
ASSERT_NE(policy_file, nullptr);
- int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
fclose(policy_file);
ASSERT_NE(res, 0);
}
@@ -1071,14 +1213,14 @@ TEST(FilterTest, invalid_arg) {
FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
ASSERT_NE(policy_file, nullptr);
- int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
+ int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
fclose(policy_file);
ASSERT_NE(res, 0);
}
TEST(FilterTest, nonexistent) {
struct sock_fprog actual;
- int res = compile_filter(NULL, &actual, 0, NO_LOGGING);
+ int res = compile_filter(NULL, &actual, USE_RET_KILL, NO_LOGGING);
ASSERT_NE(res, 0);
}
diff --git a/syscall_filter_unittest_macros.h b/syscall_filter_unittest_macros.h
index 81ec67c..02bac89 100644
--- a/syscall_filter_unittest_macros.h
+++ b/syscall_filter_unittest_macros.h
@@ -44,6 +44,14 @@ do { \
EXPECT_TRUE((_block)->jf == LABEL_JF); \
} while (0)
+#define EXPECT_ACTUAL_LBL(_block, _id) \
+do { \
+ EXPECT_TRUE((_block)->code == (BPF_JMP+BPF_JA)); \
+ EXPECT_TRUE((_block)->k == (_id)); \
+ 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); \