aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuis Hector Chavez <lhchavez@google.com>2019-03-05 16:44:08 -0800
committerLuis Hector Chavez <lhchavez@google.com>2019-03-25 17:02:26 -0700
commit524da3bc428e5b6bb5e3de78a4a3f2acdc77f32a (patch)
tree1196868f01114fc16578b4dd66d5601489330ea2
parenta54812b1dff7d7d66fb914bd6d8c8cdf5b66cedf (diff)
downloadminijail-524da3bc428e5b6bb5e3de78a4a3f2acdc77f32a.tar.gz
tools/compile_seccomp_policy: Add support for syscall groups
This change adds support for the 'function@libc' and 'group@systemd' syntax to make writing policy files much easier. Bug: chromium:856315 Test: ./tools/parser_unittest.py Change-Id: Ia1d51d30c68346b4390b0e5c23d0f7e929f08c70
-rw-r--r--tools/arch.py8
-rw-r--r--tools/parser.py23
-rwxr-xr-xtools/parser_unittest.py23
-rw-r--r--tools/testdata/arch_64.json14
4 files changed, 62 insertions, 6 deletions
diff --git a/tools/arch.py b/tools/arch.py
index 6f2dfb2..ac2f32b 100644
--- a/tools/arch.py
+++ b/tools/arch.py
@@ -21,9 +21,10 @@ import json
class Arch(
- collections.namedtuple(
- 'Arch',
- ['arch_nr', 'arch_name', 'bits', 'syscalls', 'constants'])):
+ collections.namedtuple('Arch', [
+ 'arch_nr', 'arch_name', 'bits', 'syscalls', 'constants',
+ 'syscall_groups'
+ ])):
"""Holds architecture-specific information."""
def truncate_word(self, value):
@@ -51,4 +52,5 @@ class Arch(
bits=constants['bits'],
syscalls=constants['syscalls'],
constants=constants['constants'],
+ syscall_groups=constants.get('syscall_groups', {}),
)
diff --git a/tools/parser.py b/tools/parser.py
index 41d2f52..65297f9 100644
--- a/tools/parser.py
+++ b/tools/parser.py
@@ -57,7 +57,7 @@ _TOKEN_SPECIFICATION = (
('ARGUMENT', r'arg[0-9]+'),
('RETURN', r'return'),
('ACTION', r'allow|kill-process|kill-thread|kill|trap|trace|log'),
- ('IDENTIFIER', r'[a-zA-Z_][a-zA-Z_0-9@]*'),
+ ('IDENTIFIER', r'[a-zA-Z_][a-zA-Z_0-9-@]*'),
)
_TOKEN_RE = re.compile('|'.join(
r'(?P<%s>%s)' % pair for pair in _TOKEN_SPECIFICATION))
@@ -481,7 +481,7 @@ class PolicyParser:
return metadata
# syscall-descriptor = syscall-name , [ metadata ]
- # | libc-function , [ metadata ]
+ # | syscall-group-name , [ metadata ]
# ;
def _parse_syscall_descriptor(self, tokens):
if not tokens:
@@ -490,11 +490,28 @@ class PolicyParser:
if syscall_descriptor.type != 'IDENTIFIER':
self._parser_state.error(
'invalid syscall descriptor', token=syscall_descriptor)
- # TODO(lhchavez): Support libc function names.
if tokens and tokens[0].type == 'LBRACKET':
metadata = self._parse_metadata(tokens)
if 'arch' in metadata and self._arch.arch_name not in metadata['arch']:
return ()
+ if '@' in syscall_descriptor.value:
+ # This is a syscall group.
+ subtokens = syscall_descriptor.value.split('@')
+ if len(subtokens) != 2:
+ self._parser_state.error(
+ 'invalid syscall group name', token=syscall_descriptor)
+ syscall_group_name, syscall_namespace_name = subtokens
+ if syscall_namespace_name not in self._arch.syscall_groups:
+ self._parser_state.error(
+ 'nonexistent syscall group namespace',
+ token=syscall_descriptor)
+ syscall_namespace = self._arch.syscall_groups[
+ syscall_namespace_name]
+ if syscall_group_name not in syscall_namespace:
+ self._parser_state.error(
+ 'nonexistent syscall group', token=syscall_descriptor)
+ return (Syscall(name, self._arch.syscalls[name])
+ for name in syscall_namespace[syscall_group_name])
if syscall_descriptor.value not in self._arch.syscalls:
self._parser_state.error(
'nonexistent syscall', token=syscall_descriptor)
diff --git a/tools/parser_unittest.py b/tools/parser_unittest.py
index 4fba590..f13a109 100755
--- a/tools/parser_unittest.py
+++ b/tools/parser_unittest.py
@@ -398,6 +398,24 @@ class ParseFilterStatementTests(unittest.TestCase):
), [
parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
]))
+ self.assertEqual(
+ self.parser.parse_filter_statement(
+ self._tokenize('io@libc: arg0 == 0')),
+ parser.ParsedFilterStatement((
+ parser.Syscall('read', 0),
+ parser.Syscall('write', 1),
+ ), [
+ parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
+ ]))
+ self.assertEqual(
+ self.parser.parse_filter_statement(
+ self._tokenize('file-io@systemd: arg0 == 0')),
+ parser.ParsedFilterStatement((
+ parser.Syscall('read', 0),
+ parser.Syscall('write', 1),
+ ), [
+ parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
+ ]))
def test_parse_metadata(self):
"""Accept valid filter statements with metadata."""
@@ -418,6 +436,11 @@ class ParseFilterStatementTests(unittest.TestCase):
def test_parse_unclosed_brace(self):
"""Reject unclosed brace."""
with self.assertRaisesRegex(parser.ParseException, 'unclosed brace'):
+ self.parser.parse_filter(self._tokenize('{ allow'))
+
+ def test_parse_invalid_syscall_group(self):
+ """Reject invalid syscall groups."""
+ with self.assertRaisesRegex(parser.ParseException, 'unclosed brace'):
self.parser.parse_filter_statement(
self._tokenize('{ read, write: arg0 == 0'))
diff --git a/tools/testdata/arch_64.json b/tools/testdata/arch_64.json
index 10c9855..385da94 100644
--- a/tools/testdata/arch_64.json
+++ b/tools/testdata/arch_64.json
@@ -109,5 +109,19 @@
"O_RDONLY": 0,
"PROT_WRITE": 2,
"PROT_EXEC": 4
+ },
+ "syscall_groups": {
+ "libc": {
+ "io": [
+ "read",
+ "write"
+ ]
+ },
+ "systemd": {
+ "file-io": [
+ "read",
+ "write"
+ ]
+ }
}
}