예제 #1
0
    def test_parse_simple_with_arg(self):
        """Allow simple denylist policy files."""
        path = self._write_file(
            'test.policy', """
            # Comment.
            @denylist
            read: return ENOSYS
            write: arg0 == 0 ; return ENOSYS
        """)

        self.assertEqual(
            self.parser.parse_file(path),
            parser.ParsedPolicy(
                default_action=bpf.Allow(),
                filter_statements=[
                    parser.FilterStatement(
                        syscall=parser.Syscall('read', 0),
                        frequency=1,
                        filters=[
                            parser.Filter(
                                None,
                                bpf.ReturnErrno(
                                    self.arch.constants['ENOSYS'])),
                        ]),
                    parser.FilterStatement(
                        syscall=parser.Syscall('write', 1),
                        frequency=1,
                        filters=[
                            parser.Filter([[parser.Atom(0, '==', 0)]],
                                          bpf.ReturnErrno(
                                              self.arch.constants['ENOSYS'])),
                            parser.Filter(None, bpf.Allow()),
                        ]),
                ]))
예제 #2
0
 def test_parse_filter(self):
     """Accept valid filters."""
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('arg0 == 0')), [
             parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('kill-process')), [
             parser.Filter(None, bpf.KillProcess()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('kill-thread')), [
             parser.Filter(None, bpf.KillThread()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('trap')), [
             parser.Filter(None, bpf.Trap()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('return ENOSYS')), [
             parser.Filter(None,
                           bpf.ReturnErrno(self.arch.constants['ENOSYS'])),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('trace')), [
             parser.Filter(None, bpf.Trace()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('user-notify')), [
             parser.Filter(None, bpf.UserNotify()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('log')), [
             parser.Filter(None, bpf.Log()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('allow')), [
             parser.Filter(None, bpf.Allow()),
         ])
     self.assertEqual(
         self.parser.parse_filter(self._tokenize('1')), [
             parser.Filter(None, bpf.Allow()),
         ])
     self.assertEqual(
         self.parser.parse_filter(
             self._tokenize(
                 '{ arg0 == 0, arg0 == 1; return ENOSYS, trap }')),
         [
             parser.Filter([[parser.Atom(0, '==', 0)]], bpf.Allow()),
             parser.Filter([[parser.Atom(0, '==', 1)]],
                           bpf.ReturnErrno(self.arch.constants['ENOSYS'])),
             parser.Filter(None, bpf.Trap()),
         ])
예제 #3
0
 def parse_action(self, tokens):
     if not tokens:
         self._parser_state.error('missing action')
     action_token = tokens.pop(0)
     if action_token.type == 'ACTION':
         if action_token.value == 'allow':
             return bpf.Allow()
         if action_token.value == 'kill':
             return self._kill_action
         if action_token.value == 'kill-process':
             return bpf.KillProcess()
         if action_token.value == 'kill-thread':
             return bpf.KillThread()
         if action_token.value == 'trap':
             return bpf.Trap()
         if action_token.value == 'trace':
             return bpf.Trace()
         if action_token.value == 'log':
             return bpf.Log()
     elif action_token.type == 'NUMERIC_CONSTANT':
         constant = self._parse_single_constant(action_token)
         if constant == 1:
             return bpf.Allow()
     elif action_token.type == 'RETURN':
         if not tokens:
             self._parser_state.error('missing return value')
         return bpf.ReturnErrno(self._parse_single_constant(tokens.pop(0)))
     return self._parser_state.error('invalid action', token=action_token)
예제 #4
0
 def test_parse_filter(self):
     """Accept only filters that return an errno."""
     self.assertEqual(
         self.parser.parse_filter(
             self._tokenize('arg0 == 0; return ENOSYS')),
         [
             parser.Filter([[parser.Atom(0, '==', 0)]],
                           bpf.ReturnErrno(self.arch.constants['ENOSYS'])),
         ])
예제 #5
0
파일: parser.py 프로젝트: google/minijail
    def parse_action(self, tokens):
        if not tokens:
            self._parser_state.error('missing action')
        action_token = tokens.pop(0)
        # denylist policies must specify a return for every line.
        if self._denylist:
            if action_token.type != 'RETURN':
                self._parser_state.error('invalid denylist policy')

        if action_token.type == 'ACTION':
            if action_token.value == 'allow':
                return bpf.Allow()
            if action_token.value == 'kill':
                return self._kill_action
            if action_token.value == 'kill-process':
                return bpf.KillProcess()
            if action_token.value == 'kill-thread':
                return bpf.KillThread()
            if action_token.value == 'trap':
                return bpf.Trap()
            if action_token.value == 'trace':
                return bpf.Trace()
            if action_token.value == 'user-notify':
                return bpf.UserNotify()
            if action_token.value == 'log':
                return bpf.Log()
        elif action_token.type == 'NUMERIC_CONSTANT':
            constant = self._parse_single_constant(action_token)
            if constant == 1:
                return bpf.Allow()
        elif action_token.type == 'RETURN':
            if not tokens:
                self._parser_state.error('missing return value')
            if self._ret_log:
                tokens.pop(0)
                return bpf.Log()
            else:
                return bpf.ReturnErrno(
                    self._parse_single_constant(tokens.pop(0)))
        return self._parser_state.error('invalid action', token=action_token)
예제 #6
0
    def test_parse_include(self):
        """Allow including policy files."""
        path = self._write_file(
            'test.include.policy', """
            {read, write}: arg0 == 0; allow
        """)
        path = self._write_file(
            'test.policy', """
            @include ./test.include.policy
            read: return ENOSYS
        """)

        self.assertEqual(
            self.parser.parse_file(path),
            parser.ParsedPolicy(
                default_action=bpf.KillProcess(),
                filter_statements=[
                    parser.FilterStatement(
                        syscall=parser.Syscall('read', 0),
                        frequency=1,
                        filters=[
                            parser.Filter([[parser.Atom(0, '==', 0)]],
                                          bpf.Allow()),
                            parser.Filter(
                                None,
                                bpf.ReturnErrno(
                                    self.arch.constants['ENOSYS'])),
                        ]),
                    parser.FilterStatement(
                        syscall=parser.Syscall('write', 1),
                        frequency=1,
                        filters=[
                            parser.Filter([[parser.Atom(0, '==', 0)]],
                                          bpf.Allow()),
                            parser.Filter(None, bpf.KillProcess()),
                        ]),
                ]))
예제 #7
0
def main(argv=None):
    """Main entrypoint."""

    if argv is None:
        argv = sys.argv[1:]

    opts, arg_parser = parse_args(argv)
    if not os.path.exists(opts.arch_json):
        arg_parser.error(CONSTANTS_ERR_MSG)

    parsed_arch = arch.Arch.load_from_json(opts.arch_json)
    policy_compiler = compiler.PolicyCompiler(parsed_arch)
    # Set ret_log to true if the MINIJAIL_DEFAULT_RET_LOG environment variable
    # is present.
    if 'MINIJAIL_DEFAULT_RET_LOG' in os.environ:
        print("""
            \n**********************
Warning: MINJAIL_DEFAULT_RET_LOG is on, policy will not have any effect
**********************\n
""")
        opts.use_ret_log = True
    if opts.use_ret_log:
        kill_action = bpf.Log()
    elif opts.denylist:
        # Default action for a denylist policy is return EPERM
        kill_action = bpf.ReturnErrno(parsed_arch.constants['EPERM'])
    elif opts.use_kill_process:
        kill_action = bpf.KillProcess()
    else:
        kill_action = bpf.KillThread()
    override_default_action = None
    if opts.default_action:
        parser_state = parser.ParserState('<memory>')
        override_default_action = parser.PolicyParser(
            parsed_arch, kill_action=bpf.KillProcess()).parse_action(
                next(parser_state.tokenize([opts.default_action])))

    compiled_policy = policy_compiler.compile_file(
        opts.policy.name,
        optimization_strategy=opts.optimization_strategy,
        kill_action=kill_action,
        include_depth_limit=opts.include_depth_limit,
        override_default_action=override_default_action,
        denylist=opts.denylist,
        ret_log=opts.use_ret_log)
    # Outputs the bpf binary to a c header file instead of a binary file.
    if opts.output_header_file:
        output_file_base = opts.output
        with open(output_file_base + '.h', 'w') as output_file:
            program = ', '.join('%i' % x for x in compiled_policy.opcodes)
            output_file.write(
                HEADER_TEMPLATE % {
                    'upper_name': output_file_base.upper(),
                    'name': output_file_base,
                    'program': program,
                })

    else:
        with open(opts.output, 'wb') as outf:
            outf.write(compiled_policy.opcodes)
    return 0