aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2019-03-15 01:39:31 -0400
committerTreehugger Robot <treehugger-gerrit@google.com>2019-03-25 14:55:56 +0000
commit29c72343333ef5218d5ed3cdab2ab21e51458056 (patch)
tree339b9122dc1427f93693d451c5c494eb67fb85de
parent05392b860471a48539953cf1b373aa4f81a3270c (diff)
downloadminijail-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.52
-rw-r--r--syscall_filter.c41
-rw-r--r--syscall_filter_unittest.cc35
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 =