diff options
author | Mike Frysinger <vapier@google.com> | 2019-03-15 01:39:31 -0400 |
---|---|---|
committer | Treehugger Robot <treehugger-gerrit@google.com> | 2019-03-25 14:55:56 +0000 |
commit | 29c72343333ef5218d5ed3cdab2ab21e51458056 (patch) | |
tree | 339b9122dc1427f93693d451c5c494eb67fb85de | |
parent | 05392b860471a48539953cf1b373aa4f81a3270c (diff) | |
download | minijail-29c72343333ef5218d5ed3cdab2ab21e51458056.tar.gz |
syscall_filter: support long lines
This adds support for \ at the end of lines in policy files. This
allows people to line wrap long lines which can come up with ioctl.
Bug: None
Test: make check
Change-Id: I077f8f8186bb7ae1db94e672271cbe47d24e1aa9
-rw-r--r-- | minijail0.5 | 2 | ||||
-rw-r--r-- | syscall_filter.c | 41 | ||||
-rw-r--r-- | syscall_filter_unittest.cc | 35 |
3 files changed, 77 insertions, 1 deletions
diff --git a/minijail0.5 b/minijail0.5 index bf6d0d7..f7b411a 100644 --- a/minijail0.5 +++ b/minijail0.5 @@ -34,6 +34,8 @@ The policy file supplied to the \fB-S\fR argument supports the following syntax: \fB<empty line>\fR \fB# any single line comment\fR +Long lines may be broken up using \\ at the end. + A policy that emulates \fBseccomp\fR(2) in mode 1 may look like: read: 1 write: 1 diff --git a/syscall_filter.c b/syscall_filter.c index c1526a4..049797a 100644 --- a/syscall_filter.c +++ b/syscall_filter.c @@ -499,6 +499,45 @@ int parse_include_statement(struct parser_state *state, char *policy_line, return 0; } +/* + * This is like getline() but supports line wrapping with \. + */ +static ssize_t getmultiline(char **lineptr, size_t *n, FILE *stream) +{ + ssize_t ret = getline(lineptr, n, stream); + if (ret < 0) + return ret; + + char *line = *lineptr; + /* Eat the newline to make processing below easier. */ + if (ret > 0 && line[ret - 1] == '\n') + line[--ret] = '\0'; + + /* If the line doesn't end in a backslash, we're done. */ + if (ret <= 0 || line[ret - 1] != '\\') + return ret; + + /* This line ends in a backslash. Get the nextline. */ + line[--ret] = '\0'; + size_t next_n = 0; + char *next_line = NULL; + ssize_t next_ret = getmultiline(&next_line, &next_n, stream); + if (next_ret == -1) { + free(next_line); + /* We couldn't fully read the line, so return an error. */ + return -1; + } + + /* Merge the lines. */ + *n = ret + next_ret + 2; + line = realloc(line, *n); + line[ret] = ' '; + memcpy(&line[ret + 1], next_line, next_ret + 1); + free(next_line); + *lineptr = line; + return ret; +} + int compile_file(const char *filename, FILE *policy_file, struct filter_block *head, struct filter_block **arg_blocks, struct bpf_labels *labels, int use_ret_trap, int allow_logging, @@ -522,7 +561,7 @@ int compile_file(const char *filename, FILE *policy_file, size_t len = 0; int ret = 0; - while (getline(&line, &len, policy_file) != -1) { + while (getmultiline(&line, &len, policy_file) != -1) { char *policy_line = line; policy_line = strip(policy_line); diff --git a/syscall_filter_unittest.cc b/syscall_filter_unittest.cc index 8a0b19a..aca5f54 100644 --- a/syscall_filter_unittest.cc +++ b/syscall_filter_unittest.cc @@ -1261,6 +1261,41 @@ TEST_F(FileTest, seccomp_read) { EXPECT_EQ(curr_block->next, nullptr); } +TEST_F(FileTest, multiline) { + std::string policy = + "read:\\\n1\n" + "openat:arg0 in\\\n5"; + + const int LABEL_ID = 0; + + FILE* policy_file = write_policy_to_pipe(policy); + ASSERT_NE(policy_file, nullptr); + int res = test_compile_file("policy", policy_file, head_, &arg_blocks_, + &labels_); + fclose(policy_file); + + /* + * Policy should be valid. + */ + ASSERT_EQ(res, 0); + + /* First block is the read. */ + struct filter_block *curr_block = head_; + ASSERT_NE(curr_block, nullptr); + EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_read); + + /* Second block is the open. */ + curr_block = curr_block->next; + ASSERT_NE(curr_block, nullptr); + EXPECT_ALLOW_SYSCALL_ARGS(curr_block->instrs, + __NR_openat, + LABEL_ID, + JUMP_JT, + JUMP_JF); + + EXPECT_EQ(curr_block->next, nullptr); +} + TEST(FilterTest, seccomp_mode1) { struct sock_fprog actual; std::string policy = |