xref: /aosp_15_r20/bionic/libc/tools/genseccomp.py (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*8d67ca89SAndroid Build Coastguard Worker
3*8d67ca89SAndroid Build Coastguard Workerimport argparse
4*8d67ca89SAndroid Build Coastguard Workerimport logging
5*8d67ca89SAndroid Build Coastguard Workerimport operator
6*8d67ca89SAndroid Build Coastguard Workerimport os
7*8d67ca89SAndroid Build Coastguard Workerimport re
8*8d67ca89SAndroid Build Coastguard Workerimport sys
9*8d67ca89SAndroid Build Coastguard Workerimport textwrap
10*8d67ca89SAndroid Build Coastguard Worker
11*8d67ca89SAndroid Build Coastguard Workerfrom gensyscalls import SysCallsTxtParser
12*8d67ca89SAndroid Build Coastguard Worker
13*8d67ca89SAndroid Build Coastguard Worker
14*8d67ca89SAndroid Build Coastguard WorkerBPF_JGE = "BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, {0}, {1}, {2})"
15*8d67ca89SAndroid Build Coastguard WorkerBPF_JEQ = "BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, {0}, {1}, {2})"
16*8d67ca89SAndroid Build Coastguard WorkerBPF_ALLOW = "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)"
17*8d67ca89SAndroid Build Coastguard Worker
18*8d67ca89SAndroid Build Coastguard Worker
19*8d67ca89SAndroid Build Coastguard Workerclass SyscallRange:
20*8d67ca89SAndroid Build Coastguard Worker  def __init__(self, name, value):
21*8d67ca89SAndroid Build Coastguard Worker    self.names = [name]
22*8d67ca89SAndroid Build Coastguard Worker    self.begin = value
23*8d67ca89SAndroid Build Coastguard Worker    self.end = self.begin + 1
24*8d67ca89SAndroid Build Coastguard Worker
25*8d67ca89SAndroid Build Coastguard Worker  def __str__(self):
26*8d67ca89SAndroid Build Coastguard Worker    return "(%s, %s, %s)" % (self.begin, self.end, self.names)
27*8d67ca89SAndroid Build Coastguard Worker
28*8d67ca89SAndroid Build Coastguard Worker  def add(self, name, value):
29*8d67ca89SAndroid Build Coastguard Worker    if value != self.end:
30*8d67ca89SAndroid Build Coastguard Worker      raise ValueError
31*8d67ca89SAndroid Build Coastguard Worker    self.end += 1
32*8d67ca89SAndroid Build Coastguard Worker    self.names.append(name)
33*8d67ca89SAndroid Build Coastguard Worker
34*8d67ca89SAndroid Build Coastguard Worker
35*8d67ca89SAndroid Build Coastguard Workerdef load_syscall_names_from_file(file_path, architecture):
36*8d67ca89SAndroid Build Coastguard Worker  parser = SysCallsTxtParser()
37*8d67ca89SAndroid Build Coastguard Worker  parser.parse_open_file(open(file_path))
38*8d67ca89SAndroid Build Coastguard Worker  return {x["name"] for x in parser.syscalls if x.get(architecture)}
39*8d67ca89SAndroid Build Coastguard Worker
40*8d67ca89SAndroid Build Coastguard Worker
41*8d67ca89SAndroid Build Coastguard Workerdef load_syscall_priorities_from_file(file_path):
42*8d67ca89SAndroid Build Coastguard Worker  format_re = re.compile(r'^\s*([A-Za-z_][A-Za-z0-9_]+)\s*$')
43*8d67ca89SAndroid Build Coastguard Worker  priorities = []
44*8d67ca89SAndroid Build Coastguard Worker  with open(file_path) as priority_file:
45*8d67ca89SAndroid Build Coastguard Worker    for line in priority_file:
46*8d67ca89SAndroid Build Coastguard Worker      match = format_re.match(line)
47*8d67ca89SAndroid Build Coastguard Worker      if match is None:
48*8d67ca89SAndroid Build Coastguard Worker        continue
49*8d67ca89SAndroid Build Coastguard Worker      try:
50*8d67ca89SAndroid Build Coastguard Worker        name = match.group(1)
51*8d67ca89SAndroid Build Coastguard Worker        priorities.append(name)
52*8d67ca89SAndroid Build Coastguard Worker      except IndexError:
53*8d67ca89SAndroid Build Coastguard Worker        # TODO: This should be impossible becauase it wouldn't have matched?
54*8d67ca89SAndroid Build Coastguard Worker        logging.exception('Failed to parse %s from %s', line, file_path)
55*8d67ca89SAndroid Build Coastguard Worker
56*8d67ca89SAndroid Build Coastguard Worker  return priorities
57*8d67ca89SAndroid Build Coastguard Worker
58*8d67ca89SAndroid Build Coastguard Worker
59*8d67ca89SAndroid Build Coastguard Workerdef merge_names(base_names, allowlist_names, blocklist_names):
60*8d67ca89SAndroid Build Coastguard Worker  if bool(blocklist_names - base_names):
61*8d67ca89SAndroid Build Coastguard Worker    raise RuntimeError("blocklist item not in bionic - aborting " + str(
62*8d67ca89SAndroid Build Coastguard Worker        blocklist_names - base_names))
63*8d67ca89SAndroid Build Coastguard Worker
64*8d67ca89SAndroid Build Coastguard Worker  return (base_names - blocklist_names) | allowlist_names
65*8d67ca89SAndroid Build Coastguard Worker
66*8d67ca89SAndroid Build Coastguard Worker
67*8d67ca89SAndroid Build Coastguard Workerdef extract_priority_syscalls(syscalls, priorities):
68*8d67ca89SAndroid Build Coastguard Worker  # Extract syscalls that are not in the priority list
69*8d67ca89SAndroid Build Coastguard Worker  other_syscalls = \
70*8d67ca89SAndroid Build Coastguard Worker    [syscall for syscall in syscalls if syscall[0] not in priorities]
71*8d67ca89SAndroid Build Coastguard Worker  # For prioritized syscalls, keep the order in which they appear in th
72*8d67ca89SAndroid Build Coastguard Worker  # priority list
73*8d67ca89SAndroid Build Coastguard Worker  syscall_dict = {syscall[0]: syscall[1] for syscall in syscalls}
74*8d67ca89SAndroid Build Coastguard Worker  priority_syscalls = []
75*8d67ca89SAndroid Build Coastguard Worker  for name in priorities:
76*8d67ca89SAndroid Build Coastguard Worker    if name in syscall_dict.keys():
77*8d67ca89SAndroid Build Coastguard Worker      priority_syscalls.append((name, syscall_dict[name]))
78*8d67ca89SAndroid Build Coastguard Worker  return priority_syscalls, other_syscalls
79*8d67ca89SAndroid Build Coastguard Worker
80*8d67ca89SAndroid Build Coastguard Worker
81*8d67ca89SAndroid Build Coastguard Workerdef parse_syscall_NRs(names_path):
82*8d67ca89SAndroid Build Coastguard Worker  # The input is now the preprocessed source file. This will contain a lot
83*8d67ca89SAndroid Build Coastguard Worker  # of junk from the preprocessor, but our lines will be in the format:
84*8d67ca89SAndroid Build Coastguard Worker  #
85*8d67ca89SAndroid Build Coastguard Worker  #    #define __(ARM_)?NR_${NAME} ${VALUE}
86*8d67ca89SAndroid Build Coastguard Worker  #
87*8d67ca89SAndroid Build Coastguard Worker  # Where ${VALUE} is a preprocessor expression.
88*8d67ca89SAndroid Build Coastguard Worker  #
89*8d67ca89SAndroid Build Coastguard Worker  # Newer architectures have things like this though:
90*8d67ca89SAndroid Build Coastguard Worker  #
91*8d67ca89SAndroid Build Coastguard Worker  #    #define __NR3264_fcntl 25
92*8d67ca89SAndroid Build Coastguard Worker  #    #define __NR_fcntl __NR3264_fcntl
93*8d67ca89SAndroid Build Coastguard Worker  #
94*8d67ca89SAndroid Build Coastguard Worker  # So we need to keep track of the __NR3264_* constants and substitute them.
95*8d67ca89SAndroid Build Coastguard Worker
96*8d67ca89SAndroid Build Coastguard Worker  line_re = re.compile(r'^# \d+ ".*".*')
97*8d67ca89SAndroid Build Coastguard Worker  undef_re = re.compile(r'^#undef\s.*')
98*8d67ca89SAndroid Build Coastguard Worker  define_re = re.compile(r'^\s*#define\s+([A-Za-z0-9_(,)]+)(?:\s+(.+))?\s*$')
99*8d67ca89SAndroid Build Coastguard Worker  token_re = re.compile(r'\b[A-Za-z_][A-Za-z0-9_]+\b')
100*8d67ca89SAndroid Build Coastguard Worker  constants = {}
101*8d67ca89SAndroid Build Coastguard Worker  nr3264s = {}
102*8d67ca89SAndroid Build Coastguard Worker  with open(names_path) as f:
103*8d67ca89SAndroid Build Coastguard Worker    for line in f:
104*8d67ca89SAndroid Build Coastguard Worker      line = line.strip()
105*8d67ca89SAndroid Build Coastguard Worker      m = define_re.match(line)
106*8d67ca89SAndroid Build Coastguard Worker      if m:
107*8d67ca89SAndroid Build Coastguard Worker        name = m.group(1)
108*8d67ca89SAndroid Build Coastguard Worker        value = m.group(2)
109*8d67ca89SAndroid Build Coastguard Worker        if name.startswith('__NR3264'):
110*8d67ca89SAndroid Build Coastguard Worker          nr3264s[name] = value
111*8d67ca89SAndroid Build Coastguard Worker        elif name.startswith('__NR_') or name.startswith('__ARM_NR_'):
112*8d67ca89SAndroid Build Coastguard Worker          if value in nr3264s:
113*8d67ca89SAndroid Build Coastguard Worker            value = nr3264s[value]
114*8d67ca89SAndroid Build Coastguard Worker          # eval() takes care of any arithmetic that may be done
115*8d67ca89SAndroid Build Coastguard Worker          value = eval(token_re.sub(lambda x: str(constants[x.group(0)]), value))
116*8d67ca89SAndroid Build Coastguard Worker
117*8d67ca89SAndroid Build Coastguard Worker          constants[name] = value
118*8d67ca89SAndroid Build Coastguard Worker      else:
119*8d67ca89SAndroid Build Coastguard Worker        if not line_re.match(line) and not undef_re.match(line) and line:
120*8d67ca89SAndroid Build Coastguard Worker          print('%s: failed to parse line `%s`' % (names_path, line))
121*8d67ca89SAndroid Build Coastguard Worker          sys.exit(1)
122*8d67ca89SAndroid Build Coastguard Worker
123*8d67ca89SAndroid Build Coastguard Worker  syscalls = {}
124*8d67ca89SAndroid Build Coastguard Worker  for name, value in constants.items():
125*8d67ca89SAndroid Build Coastguard Worker    # Remove the __NR_ prefix.
126*8d67ca89SAndroid Build Coastguard Worker    # TODO: why not __ARM_NR too?
127*8d67ca89SAndroid Build Coastguard Worker    if name.startswith("__NR_"):
128*8d67ca89SAndroid Build Coastguard Worker      name = name[len("__NR_"):]
129*8d67ca89SAndroid Build Coastguard Worker    syscalls[name] = value
130*8d67ca89SAndroid Build Coastguard Worker
131*8d67ca89SAndroid Build Coastguard Worker  return syscalls
132*8d67ca89SAndroid Build Coastguard Worker
133*8d67ca89SAndroid Build Coastguard Worker
134*8d67ca89SAndroid Build Coastguard Workerdef convert_NRs_to_ranges(syscalls):
135*8d67ca89SAndroid Build Coastguard Worker  # Sort the values so we convert to ranges and binary chop
136*8d67ca89SAndroid Build Coastguard Worker  syscalls = sorted(syscalls, key=operator.itemgetter(1))
137*8d67ca89SAndroid Build Coastguard Worker
138*8d67ca89SAndroid Build Coastguard Worker  # Turn into a list of ranges. Keep the names for the comments
139*8d67ca89SAndroid Build Coastguard Worker  ranges = []
140*8d67ca89SAndroid Build Coastguard Worker  for name, value in syscalls:
141*8d67ca89SAndroid Build Coastguard Worker    if not ranges:
142*8d67ca89SAndroid Build Coastguard Worker      ranges.append(SyscallRange(name, value))
143*8d67ca89SAndroid Build Coastguard Worker      continue
144*8d67ca89SAndroid Build Coastguard Worker
145*8d67ca89SAndroid Build Coastguard Worker    last_range = ranges[-1]
146*8d67ca89SAndroid Build Coastguard Worker    if last_range.end == value:
147*8d67ca89SAndroid Build Coastguard Worker      last_range.add(name, value)
148*8d67ca89SAndroid Build Coastguard Worker    else:
149*8d67ca89SAndroid Build Coastguard Worker      ranges.append(SyscallRange(name, value))
150*8d67ca89SAndroid Build Coastguard Worker  return ranges
151*8d67ca89SAndroid Build Coastguard Worker
152*8d67ca89SAndroid Build Coastguard Worker
153*8d67ca89SAndroid Build Coastguard Worker# Converts the sorted ranges of allowed syscalls to a binary tree bpf
154*8d67ca89SAndroid Build Coastguard Worker# For a single range, output a simple jump to {fail} or {allow}. We can't set
155*8d67ca89SAndroid Build Coastguard Worker# the jump ranges yet, since we don't know the size of the filter, so use a
156*8d67ca89SAndroid Build Coastguard Worker# placeholder
157*8d67ca89SAndroid Build Coastguard Worker# For multiple ranges, split into two, convert the two halves and output a jump
158*8d67ca89SAndroid Build Coastguard Worker# to the correct half
159*8d67ca89SAndroid Build Coastguard Workerdef convert_to_intermediate_bpf(ranges):
160*8d67ca89SAndroid Build Coastguard Worker  if len(ranges) == 1:
161*8d67ca89SAndroid Build Coastguard Worker    # We will replace {fail} and {allow} with appropriate range jumps later
162*8d67ca89SAndroid Build Coastguard Worker    return [BPF_JGE.format(ranges[0].end, "{fail}", "{allow}") +
163*8d67ca89SAndroid Build Coastguard Worker            ", //" + "|".join(ranges[0].names)]
164*8d67ca89SAndroid Build Coastguard Worker
165*8d67ca89SAndroid Build Coastguard Worker  half = (len(ranges) + 1) // 2
166*8d67ca89SAndroid Build Coastguard Worker  first = convert_to_intermediate_bpf(ranges[:half])
167*8d67ca89SAndroid Build Coastguard Worker  second = convert_to_intermediate_bpf(ranges[half:])
168*8d67ca89SAndroid Build Coastguard Worker  jump = [BPF_JGE.format(ranges[half].begin, len(first), 0) + ","]
169*8d67ca89SAndroid Build Coastguard Worker  return jump + first + second
170*8d67ca89SAndroid Build Coastguard Worker
171*8d67ca89SAndroid Build Coastguard Worker
172*8d67ca89SAndroid Build Coastguard Worker# Converts the prioritized syscalls to a bpf list that  is prepended to the
173*8d67ca89SAndroid Build Coastguard Worker# tree generated by convert_to_intermediate_bpf(). If we hit one of these
174*8d67ca89SAndroid Build Coastguard Worker# syscalls, shortcut to the allow statement at the bottom of the tree
175*8d67ca89SAndroid Build Coastguard Worker# immediately
176*8d67ca89SAndroid Build Coastguard Workerdef convert_priority_to_intermediate_bpf(priority_syscalls):
177*8d67ca89SAndroid Build Coastguard Worker  result = []
178*8d67ca89SAndroid Build Coastguard Worker  for syscall in priority_syscalls:
179*8d67ca89SAndroid Build Coastguard Worker    result.append(BPF_JEQ.format(syscall[1], "{allow}", 0) +
180*8d67ca89SAndroid Build Coastguard Worker                  ", //" + syscall[0])
181*8d67ca89SAndroid Build Coastguard Worker  return result
182*8d67ca89SAndroid Build Coastguard Worker
183*8d67ca89SAndroid Build Coastguard Worker
184*8d67ca89SAndroid Build Coastguard Workerdef convert_ranges_to_bpf(ranges, priority_syscalls):
185*8d67ca89SAndroid Build Coastguard Worker  bpf = convert_priority_to_intermediate_bpf(priority_syscalls) + \
186*8d67ca89SAndroid Build Coastguard Worker    convert_to_intermediate_bpf(ranges)
187*8d67ca89SAndroid Build Coastguard Worker
188*8d67ca89SAndroid Build Coastguard Worker  # Now we know the size of the tree, we can substitute the {fail} and {allow}
189*8d67ca89SAndroid Build Coastguard Worker  # placeholders
190*8d67ca89SAndroid Build Coastguard Worker  for i, statement in enumerate(bpf):
191*8d67ca89SAndroid Build Coastguard Worker    # Replace placeholder with
192*8d67ca89SAndroid Build Coastguard Worker    # "distance to jump to fail, distance to jump to allow"
193*8d67ca89SAndroid Build Coastguard Worker    # We will add a kill statement and an allow statement after the tree
194*8d67ca89SAndroid Build Coastguard Worker    # With bpfs jmp 0 means the next statement, so the distance to the end is
195*8d67ca89SAndroid Build Coastguard Worker    # len(bpf) - i - 1, which is where we will put the kill statement, and
196*8d67ca89SAndroid Build Coastguard Worker    # then the statement after that is the allow statement
197*8d67ca89SAndroid Build Coastguard Worker    bpf[i] = statement.format(fail=str(len(bpf) - i),
198*8d67ca89SAndroid Build Coastguard Worker                              allow=str(len(bpf) - i - 1))
199*8d67ca89SAndroid Build Coastguard Worker
200*8d67ca89SAndroid Build Coastguard Worker  # Add the allow calls at the end. If the syscall is not matched, we will
201*8d67ca89SAndroid Build Coastguard Worker  # continue. This allows the user to choose to match further syscalls, and
202*8d67ca89SAndroid Build Coastguard Worker  # also to choose the action when we want to block
203*8d67ca89SAndroid Build Coastguard Worker  bpf.append(BPF_ALLOW + ",")
204*8d67ca89SAndroid Build Coastguard Worker
205*8d67ca89SAndroid Build Coastguard Worker  # Add check that we aren't off the bottom of the syscalls
206*8d67ca89SAndroid Build Coastguard Worker  bpf.insert(0, BPF_JGE.format(ranges[0].begin, 0, str(len(bpf))) + ',')
207*8d67ca89SAndroid Build Coastguard Worker  return bpf
208*8d67ca89SAndroid Build Coastguard Worker
209*8d67ca89SAndroid Build Coastguard Worker
210*8d67ca89SAndroid Build Coastguard Workerdef convert_bpf_to_output(bpf, architecture, name_modifier):
211*8d67ca89SAndroid Build Coastguard Worker  if name_modifier:
212*8d67ca89SAndroid Build Coastguard Worker    name_modifier = name_modifier + "_"
213*8d67ca89SAndroid Build Coastguard Worker  else:
214*8d67ca89SAndroid Build Coastguard Worker    name_modifier = ""
215*8d67ca89SAndroid Build Coastguard Worker  header = textwrap.dedent("""\
216*8d67ca89SAndroid Build Coastguard Worker    // File autogenerated by {self_path} - edit at your peril!!
217*8d67ca89SAndroid Build Coastguard Worker
218*8d67ca89SAndroid Build Coastguard Worker    #include <linux/filter.h>
219*8d67ca89SAndroid Build Coastguard Worker    #include <errno.h>
220*8d67ca89SAndroid Build Coastguard Worker
221*8d67ca89SAndroid Build Coastguard Worker    #include "seccomp/seccomp_bpfs.h"
222*8d67ca89SAndroid Build Coastguard Worker    const sock_filter {architecture}_{suffix}filter[] = {{
223*8d67ca89SAndroid Build Coastguard Worker    """).format(self_path=os.path.basename(__file__), architecture=architecture,
224*8d67ca89SAndroid Build Coastguard Worker                suffix=name_modifier)
225*8d67ca89SAndroid Build Coastguard Worker
226*8d67ca89SAndroid Build Coastguard Worker  footer = textwrap.dedent("""\
227*8d67ca89SAndroid Build Coastguard Worker
228*8d67ca89SAndroid Build Coastguard Worker    }};
229*8d67ca89SAndroid Build Coastguard Worker
230*8d67ca89SAndroid Build Coastguard Worker    const size_t {architecture}_{suffix}filter_size = sizeof({architecture}_{suffix}filter) / sizeof(struct sock_filter);
231*8d67ca89SAndroid Build Coastguard Worker    """).format(architecture=architecture,suffix=name_modifier)
232*8d67ca89SAndroid Build Coastguard Worker  return header + "\n".join(bpf) + footer
233*8d67ca89SAndroid Build Coastguard Worker
234*8d67ca89SAndroid Build Coastguard Worker
235*8d67ca89SAndroid Build Coastguard Workerdef construct_bpf(syscalls, architecture, name_modifier, priorities):
236*8d67ca89SAndroid Build Coastguard Worker  priority_syscalls, other_syscalls = \
237*8d67ca89SAndroid Build Coastguard Worker    extract_priority_syscalls(syscalls, priorities)
238*8d67ca89SAndroid Build Coastguard Worker  ranges = convert_NRs_to_ranges(other_syscalls)
239*8d67ca89SAndroid Build Coastguard Worker  bpf = convert_ranges_to_bpf(ranges, priority_syscalls)
240*8d67ca89SAndroid Build Coastguard Worker  return convert_bpf_to_output(bpf, architecture, name_modifier)
241*8d67ca89SAndroid Build Coastguard Worker
242*8d67ca89SAndroid Build Coastguard Worker
243*8d67ca89SAndroid Build Coastguard Workerdef gen_policy(name_modifier, out_dir, base_syscall_file, syscall_files,
244*8d67ca89SAndroid Build Coastguard Worker               syscall_NRs, priority_file):
245*8d67ca89SAndroid Build Coastguard Worker  for arch in syscall_NRs.keys():
246*8d67ca89SAndroid Build Coastguard Worker    base_names = load_syscall_names_from_file(base_syscall_file, arch)
247*8d67ca89SAndroid Build Coastguard Worker    allowlist_names = set()
248*8d67ca89SAndroid Build Coastguard Worker    blocklist_names = set()
249*8d67ca89SAndroid Build Coastguard Worker    for f in syscall_files:
250*8d67ca89SAndroid Build Coastguard Worker      if "blocklist" in f.lower():
251*8d67ca89SAndroid Build Coastguard Worker        blocklist_names |= load_syscall_names_from_file(f, arch)
252*8d67ca89SAndroid Build Coastguard Worker      else:
253*8d67ca89SAndroid Build Coastguard Worker        allowlist_names |= load_syscall_names_from_file(f, arch)
254*8d67ca89SAndroid Build Coastguard Worker    priorities = []
255*8d67ca89SAndroid Build Coastguard Worker    if priority_file:
256*8d67ca89SAndroid Build Coastguard Worker      priorities = load_syscall_priorities_from_file(priority_file)
257*8d67ca89SAndroid Build Coastguard Worker
258*8d67ca89SAndroid Build Coastguard Worker    allowed_syscalls = []
259*8d67ca89SAndroid Build Coastguard Worker    for name in sorted(merge_names(base_names, allowlist_names, blocklist_names)):
260*8d67ca89SAndroid Build Coastguard Worker      try:
261*8d67ca89SAndroid Build Coastguard Worker        allowed_syscalls.append((name, syscall_NRs[arch][name]))
262*8d67ca89SAndroid Build Coastguard Worker      except:
263*8d67ca89SAndroid Build Coastguard Worker        logging.exception("Failed to find %s in %s (%s)", name, arch, syscall_NRs[arch])
264*8d67ca89SAndroid Build Coastguard Worker        raise
265*8d67ca89SAndroid Build Coastguard Worker    output = construct_bpf(allowed_syscalls, arch, name_modifier, priorities)
266*8d67ca89SAndroid Build Coastguard Worker
267*8d67ca89SAndroid Build Coastguard Worker    # And output policy
268*8d67ca89SAndroid Build Coastguard Worker    filename_modifier = "_" + name_modifier if name_modifier else ""
269*8d67ca89SAndroid Build Coastguard Worker    output_path = os.path.join(out_dir,
270*8d67ca89SAndroid Build Coastguard Worker                               "{}{}_policy.cpp".format(arch, filename_modifier))
271*8d67ca89SAndroid Build Coastguard Worker    with open(output_path, "w") as output_file:
272*8d67ca89SAndroid Build Coastguard Worker      output_file.write(output)
273*8d67ca89SAndroid Build Coastguard Worker
274*8d67ca89SAndroid Build Coastguard Worker
275*8d67ca89SAndroid Build Coastguard Workerdef main():
276*8d67ca89SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(
277*8d67ca89SAndroid Build Coastguard Worker      description="Generates a seccomp-bpf policy")
278*8d67ca89SAndroid Build Coastguard Worker  parser.add_argument("--verbose", "-v", help="Enables verbose logging.")
279*8d67ca89SAndroid Build Coastguard Worker  parser.add_argument("--name-modifier",
280*8d67ca89SAndroid Build Coastguard Worker                      help=("Specifies the name modifier for the policy. "
281*8d67ca89SAndroid Build Coastguard Worker                            "One of {app,system}."))
282*8d67ca89SAndroid Build Coastguard Worker  parser.add_argument("--out-dir",
283*8d67ca89SAndroid Build Coastguard Worker                      help="The output directory for the policy files")
284*8d67ca89SAndroid Build Coastguard Worker  parser.add_argument("base_file", metavar="base-file", type=str,
285*8d67ca89SAndroid Build Coastguard Worker                      help="The path of the base syscall list (SYSCALLS.TXT).")
286*8d67ca89SAndroid Build Coastguard Worker  parser.add_argument("files", metavar="FILE", type=str, nargs="+",
287*8d67ca89SAndroid Build Coastguard Worker                      help=("The path of the input files. In order to "
288*8d67ca89SAndroid Build Coastguard Worker                            "simplify the build rules, it can take any of the "
289*8d67ca89SAndroid Build Coastguard Worker                            "following files: \n"
290*8d67ca89SAndroid Build Coastguard Worker                            "* /blocklist.*\\.txt$/ syscall blocklist.\n"
291*8d67ca89SAndroid Build Coastguard Worker                            "* /allowlist.*\\.txt$/ syscall allowlist.\n"
292*8d67ca89SAndroid Build Coastguard Worker                            "* /priority.txt$/ priorities for bpf rules.\n"
293*8d67ca89SAndroid Build Coastguard Worker                            "* otherwise, syscall name-number mapping.\n"))
294*8d67ca89SAndroid Build Coastguard Worker  args = parser.parse_args()
295*8d67ca89SAndroid Build Coastguard Worker
296*8d67ca89SAndroid Build Coastguard Worker  if args.verbose:
297*8d67ca89SAndroid Build Coastguard Worker    logging.basicConfig(level=logging.DEBUG)
298*8d67ca89SAndroid Build Coastguard Worker  else:
299*8d67ca89SAndroid Build Coastguard Worker    logging.basicConfig(level=logging.INFO)
300*8d67ca89SAndroid Build Coastguard Worker
301*8d67ca89SAndroid Build Coastguard Worker  syscall_files = []
302*8d67ca89SAndroid Build Coastguard Worker  priority_file = None
303*8d67ca89SAndroid Build Coastguard Worker  syscall_NRs = {}
304*8d67ca89SAndroid Build Coastguard Worker  for filename in args.files:
305*8d67ca89SAndroid Build Coastguard Worker    if filename.lower().endswith('.txt'):
306*8d67ca89SAndroid Build Coastguard Worker      if filename.lower().endswith('priority.txt'):
307*8d67ca89SAndroid Build Coastguard Worker        priority_file = filename
308*8d67ca89SAndroid Build Coastguard Worker      else:
309*8d67ca89SAndroid Build Coastguard Worker        syscall_files.append(filename)
310*8d67ca89SAndroid Build Coastguard Worker    else:
311*8d67ca89SAndroid Build Coastguard Worker      m = re.search(r"libseccomp_gen_syscall_nrs_([^/]+)", filename)
312*8d67ca89SAndroid Build Coastguard Worker      syscall_NRs[m.group(1)] = parse_syscall_NRs(filename)
313*8d67ca89SAndroid Build Coastguard Worker
314*8d67ca89SAndroid Build Coastguard Worker  gen_policy(name_modifier=args.name_modifier, out_dir=args.out_dir,
315*8d67ca89SAndroid Build Coastguard Worker             syscall_NRs=syscall_NRs, base_syscall_file=args.base_file,
316*8d67ca89SAndroid Build Coastguard Worker             syscall_files=syscall_files, priority_file=priority_file)
317*8d67ca89SAndroid Build Coastguard Worker
318*8d67ca89SAndroid Build Coastguard Worker
319*8d67ca89SAndroid Build Coastguard Workerif __name__ == "__main__":
320*8d67ca89SAndroid Build Coastguard Worker  main()
321