Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python3
      2 # -*- coding: utf-8 -*-
      3 #
      4 # Copyright (C) 2018 The Android Open Source Project
      5 #
      6 # Licensed under the Apache License, Version 2.0 (the "License");
      7 # you may not use this file except in compliance with the License.
      8 # You may obtain a copy of the License at
      9 #
     10 #      http://www.apache.org/licenses/LICENSE-2.0
     11 #
     12 # Unless required by applicable law or agreed to in writing, software
     13 # distributed under the License is distributed on an "AS IS" BASIS,
     14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 # See the License for the specific language governing permissions and
     16 # limitations under the License.
     17 """Helper tool to compile a BPF program from a Minijail seccomp filter.
     18 
     19 This script will take a Minijail seccomp policy file and compile it into a
     20 BPF program suitable for use with Minijail in the current architecture.
     21 """
     22 
     23 from __future__ import print_function
     24 
     25 import argparse
     26 import sys
     27 
     28 import arch
     29 import bpf
     30 import compiler
     31 import parser
     32 
     33 
     34 def parse_args(argv):
     35     """Return the parsed CLI arguments for this tool."""
     36     parser = argparse.ArgumentParser(description=__doc__)
     37     parser.add_argument(
     38         '--optimization-strategy',
     39         default=compiler.OptimizationStrategy.BST,
     40         type=compiler.OptimizationStrategy,
     41         choices=list(compiler.OptimizationStrategy))
     42     parser.add_argument('--include-depth-limit', default=10)
     43     parser.add_argument('--arch-json', default='constants.json')
     44     parser.add_argument(
     45         '--default-action',
     46         type=str,
     47         help=('Use the specified default action, overriding any @default '
     48               'action found in the .policy files. '
     49               'This allows the use of permissive actions (allow, log, trace) '
     50               'since it is not valid to specify a permissive action in '
     51               '.policy files. This is useful for debugging.'))
     52     parser.add_argument(
     53         '--use-kill-process',
     54         action='store_true',
     55         help=('Use SECCOMP_RET_KILL_PROCESS instead of '
     56               'SECCOMP_RET_KILL_THREAD (requires Linux v4.14+).'))
     57     parser.add_argument(
     58         'policy', help='The seccomp policy.', type=argparse.FileType('r'))
     59     parser.add_argument(
     60         'output', help='The BPF program.', type=argparse.FileType('wb'))
     61     return parser.parse_args(argv)
     62 
     63 
     64 def main(argv):
     65     """Main entrypoint."""
     66     opts = parse_args(argv)
     67     parsed_arch = arch.Arch.load_from_json(opts.arch_json)
     68     policy_compiler = compiler.PolicyCompiler(parsed_arch)
     69     if opts.use_kill_process:
     70         kill_action = bpf.KillProcess()
     71     else:
     72         kill_action = bpf.KillThread()
     73     override_default_action = None
     74     if opts.default_action:
     75         parser_state = parser.ParserState('<memory>')
     76         parser_state.set_line(opts.default_action)
     77         override_default_action = parser.PolicyParser(
     78             parsed_arch, kill_action=bpf.KillProcess()).parse_action(
     79                 parser_state.tokenize())
     80     with opts.output as outf:
     81         outf.write(
     82             policy_compiler.compile_file(
     83                 opts.policy.name,
     84                 optimization_strategy=opts.optimization_strategy,
     85                 kill_action=kill_action,
     86                 include_depth_limit=opts.include_depth_limit,
     87                 override_default_action=override_default_action).opcodes)
     88     return 0
     89 
     90 
     91 if __name__ == '__main__':
     92     sys.exit(main(sys.argv[1:]))
     93