예제 #1
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()),
                        ]),
                ]))
 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('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 main(argv):
    """Main entrypoint."""
    opts = parse_args(argv)
    parsed_arch = arch.Arch.load_from_json(opts.arch_json)
    policy_compiler = compiler.PolicyCompiler(parsed_arch)
    if 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])))
    with opts.output as outf:
        outf.write(
            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).opcodes)
    return 0
예제 #4
0
    def test_compile_empty_file(self):
        """Accept empty files."""
        path = self._write_file(
            'test.policy', """
            @default kill-thread
        """)

        for strategy in list(compiler.OptimizationStrategy):
            program = self.compiler.compile_file(
                path,
                optimization_strategy=strategy,
                kill_action=bpf.KillProcess())
            self.assertEqual(
                bpf.simulate(program.instructions, self.arch.arch_nr,
                             self.arch.syscalls['read'], 0)[1], 'KILL_THREAD')
예제 #5
0
 def _parse_default_action(self, tokens):
     if not tokens:
         self._parser_state.error('missing default action')
     action_token = tokens.pop(0)
     if action_token.type != 'ACTION':
         return self._parser_state.error(
             'invalid default action', token=action_token)
     if action_token.value == 'kill-process':
         return bpf.KillProcess()
     if action_token.value == 'kill-thread':
         return bpf.KillThread()
     if action_token.value == 'kill':
         return self._kill_action
     if action_token.value == 'trap':
         return bpf.Trap()
     return self._parser_state.error(
         'invalid permissive default action', token=action_token)
예제 #6
0
    def test_parse_other_arch(self):
        """Allow entries that only target another architecture."""
        path = self._write_file(
            'test.policy', """
            # Comment.
            read[arch=nonexistent]: allow
            write: allow
        """)

        self.assertEqual(
            self.parser.parse_file(path),
            parser.ParsedPolicy(default_action=bpf.KillProcess(),
                                filter_statements=[
                                    parser.FilterStatement(
                                        syscall=parser.Syscall('write', 1),
                                        frequency=1,
                                        filters=[
                                            parser.Filter(None, bpf.Allow()),
                                        ]),
                                ]))
예제 #7
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)
예제 #8
0
    def test_parse_frequency(self):
        """Allow including frequency files."""
        self._write_file(
            'test.frequency', """
            read: 2
            write: 3
        """)
        path = self._write_file(
            'test.policy', """
            @frequency ./test.frequency
            read: allow
        """)

        self.assertEqual(
            self.parser.parse_file(path),
            parser.ParsedPolicy(default_action=bpf.KillProcess(),
                                filter_statements=[
                                    parser.FilterStatement(
                                        syscall=parser.Syscall('read', 0),
                                        frequency=2,
                                        filters=[
                                            parser.Filter(None, bpf.Allow()),
                                        ]),
                                ]))
예제 #9
0
    def test_compile(self):
        """Ensure compilation works with all strategies."""
        self._write_file(
            'test.frequency', """
            read: 1
            close: 10
        """)
        path = self._write_file(
            'test.policy', """
            @frequency ./test.frequency
            read: 1
            close: 1
        """)

        program = self.compiler.compile_file(
            path,
            optimization_strategy=compiler.OptimizationStrategy.LINEAR,
            kill_action=bpf.KillProcess())
        self.assertGreater(
            bpf.simulate(program.instructions, self.arch.arch_nr,
                         self.arch.syscalls['read'], 0)[0],
            bpf.simulate(program.instructions, self.arch.arch_nr,
                         self.arch.syscalls['close'], 0)[0],
        )
예제 #10
0
 def setUp(self):
     self.arch = ARCH_64
     self.parser = parser.PolicyParser(self.arch,
                                       kill_action=bpf.KillProcess())
     self.tempdir = tempfile.mkdtemp()
예제 #11
0
 def setUp(self):
     self.arch = ARCH_64
     self.parser = parser.PolicyParser(self.arch,
                                       kill_action=bpf.KillProcess())
예제 #12
0
 def setUp(self):
     self.arch = ARCH_64
     self.kill_action = bpf.KillProcess()
     self.parser = parser.PolicyParser(self.arch,
                                       kill_action=self.kill_action,
                                       denylist=True)
예제 #13
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