tools/compile_seccomp_policy: Support arch metadata attributes
am: 571e958364
Change-Id: I43ba6868a6189eee3169dab58a84ad8e199125cb
diff --git a/tools/parser.py b/tools/parser.py
index 99b2e99..6f6ea06 100644
--- a/tools/parser.py
+++ b/tools/parser.py
@@ -403,6 +403,57 @@
filters.append(self._parse_single_filter(tokens))
return filters
+ # key-value-pair = identifier , '=', identifier , [ { ',' , identifier } ]
+ # ;
+ def _parse_key_value_pair(self, tokens):
+ if not tokens:
+ self._parser_state.error('missing key')
+ key = tokens.pop(0)
+ if key.type != 'IDENTIFIER':
+ self._parser_state.error('invalid key', token=key)
+ if not tokens:
+ self._parser_state.error('missing equal')
+ if tokens[0].type != 'EQUAL':
+ self._parser_state.error('invalid equal', token=tokens[0])
+ tokens.pop(0)
+ value_list = []
+ while tokens:
+ value = tokens.pop(0)
+ if value.type != 'IDENTIFIER':
+ self._parser_state.error('invalid value', token=value)
+ value_list.append(value.value)
+ if not tokens or tokens[0].type != 'COMMA':
+ break
+ tokens.pop(0)
+ else:
+ self._parser_state.error('empty value')
+ return (key.value, value_list)
+
+ # metadata = '[' , key-value-pair , [ { ';' , key-value-pair } ] , ']'
+ # ;
+ def _parse_metadata(self, tokens):
+ if not tokens:
+ self._parser_state.error('missing opening bracket')
+ opening_bracket = tokens.pop(0)
+ if opening_bracket.type != 'LBRACKET':
+ self._parser_state.error(
+ 'invalid opening bracket', token=opening_bracket)
+ metadata = {}
+ while tokens:
+ first_token = tokens[0]
+ key, value = self._parse_key_value_pair(tokens)
+ if key in metadata:
+ self._parser_state.error(
+ 'duplicate metadata key: "%s"' % key, token=first_token)
+ metadata[key] = value
+ if not tokens or tokens[0].type != 'SEMICOLON':
+ break
+ tokens.pop(0)
+ if not tokens or tokens[0].type != 'RBRACKET':
+ self._parser_state.error('unclosed bracket', token=opening_bracket)
+ tokens.pop(0)
+ return metadata
+
# syscall-descriptor = syscall-name , [ metadata ]
# | libc-function , [ metadata ]
# ;
@@ -413,11 +464,14 @@
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 syscall_descriptor.value not in self._arch.syscalls:
self._parser_state.error(
'nonexistent syscall', token=syscall_descriptor)
- # TODO(lhchavez): Support libc function names.
- # TODO(lhchavez): Support metadata.
return (Syscall(syscall_descriptor.value,
self._arch.syscalls[syscall_descriptor.value]), )
@@ -495,7 +549,12 @@
statements.extend(
self._parse_include_statement(tokens))
else:
- statements.append(self.parse_filter_statement(tokens))
+ statement = self.parse_filter_statement(tokens)
+ if statement is None:
+ # If all the syscalls in the statement are for
+ # another arch, skip the whole statement.
+ continue
+ statements.append(statement)
if tokens:
self._parser_state.error(
diff --git a/tools/parser_unittest.py b/tools/parser_unittest.py
index ba0fedd..570f8a2 100755
--- a/tools/parser_unittest.py
+++ b/tools/parser_unittest.py
@@ -399,6 +399,22 @@
parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
]))
+ def test_parse_metadata(self):
+ """Accept valid filter statements with metadata."""
+ self.assertEqual(
+ self.parser.parse_filter_statement(
+ self._tokenize('read[arch=test]: arg0 == 0')),
+ parser.ParsedFilterStatement((parser.Syscall('read', 0), ), [
+ parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
+ ]))
+ self.assertEqual(
+ self.parser.parse_filter_statement(
+ self._tokenize(
+ '{read, nonexistent[arch=nonexistent]}: arg0 == 0')),
+ parser.ParsedFilterStatement((parser.Syscall('read', 0), ), [
+ parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
+ ]))
+
def test_parse_unclosed_brace(self):
"""Reject unclosed brace."""
with self.assertRaisesRegex(parser.ParseException, 'unclosed brace'):