Пример #1
0
def get_names(syscall_files, architecture):
    syscalls = []
    for syscall_file in syscall_files:
        parser = SysCallsTxtParser()
        parser.parse_open_file(syscall_file)
        syscalls += parser.syscalls

    # Select only elements matching required architecture
    syscalls = [x for x in syscalls if architecture in x and x[architecture]]

    # We only want the name
    names = [x["name"] for x in syscalls]

    # Check for duplicates
    dups = [
        name for name, count in collections.Counter(names).items() if count > 1
    ]

    # x86 has duplicate socketcall entries, so hard code for this
    if architecture == "x86":
        dups.remove("socketcall")

    if len(dups) > 0:
        print "Duplicate entries found - aborting ", dups
        exit(-1)

    # Remove remaining duplicates
    return list(set(names))
def load_syscall_names_from_file(file_path, architecture):
    parser = SysCallsTxtParser()
    parser.parse_open_file(open(file_path))
    arch_map = {}
    for syscall in parser.syscalls:
        if syscall.get(architecture):
            arch_map[syscall["func"]] = syscall["name"]

    return arch_map
def load_syscall_names_from_file(file_path, architecture):
  parser = SysCallsTxtParser()
  parser.parse_open_file(open(file_path))
  arch_map = {}
  for syscall in parser.syscalls:
    if syscall.get(architecture):
      arch_map[syscall["func"]] = syscall["name"];

  return arch_map
Пример #4
0
def get_names(syscall_files, architecture):
    syscalls = []
    for syscall_file in syscall_files:
        parser = SysCallsTxtParser()
        parser.parse_open_file(syscall_file)
        syscalls += parser.syscalls

    # Select only elements matching required architecture
    syscalls = [x for x in syscalls if architecture in x and x[architecture]]

    # We only want the name
    return [x["name"] for x in syscalls]
Пример #5
0
def get_names(syscall_files, architecture, global_policy):
    syscall_lists = []
    for syscall_file in syscall_files:
        parser = SysCallsTxtParser()
        parser.parse_open_file(syscall_file)
        syscall_lists.append(parser.syscalls)

    bionic, whitelist, blacklist = syscall_lists[0], syscall_lists[
        1], syscall_lists[2]
    if global_policy:
        global_whitelist = syscall_lists[-1]
    else:
        global_whitelist = []

    for x in blacklist:
        if not x in bionic:
            raise RuntimeError("Blacklist item not in bionic - aborting " +
                               str(x))

        if x in whitelist:
            raise RuntimeError("Blacklist item in whitelist - aborting " +
                               str(x))

    bionic_minus_blacklist = [x for x in bionic if x not in blacklist]
    syscalls = bionic_minus_blacklist + whitelist + global_whitelist

    # Select only elements matching required architecture
    syscalls = [x for x in syscalls if architecture in x and x[architecture]]

    # We only want the name
    names = [x["name"] for x in syscalls]

    # Check for duplicates
    dups = [
        name for name, count in collections.Counter(names).items() if count > 1
    ]

    # x86 has duplicate socketcall entries, so hard code for this
    if architecture == "x86":
        dups.remove("socketcall")

    if len(dups) > 0:
        raise RuntimeError("Duplicate entries found - aborting " + str(dups))

    # Remove remaining duplicates
    return list(set(names))
Пример #6
0
def load_syscall_names_from_file(file_path, architecture):
    parser = SysCallsTxtParser()
    parser.parse_open_file(open(file_path))
    return set([x["name"] for x in parser.syscalls if x.get(architecture)])
Пример #7
0
def construct_bpf(architecture, header_dir, output_path):
    parser = SysCallsTxtParser()
    parser.parse_file(syscall_file)
    syscalls = parser.syscalls

    # Select only elements matching required architecture
    syscalls = [x for x in syscalls if architecture in x and x[architecture]]

    # We only want the name
    names = [x["name"] for x in syscalls]

    # Run preprocessor over the __NR_syscall symbols, including unistd.h,
    # to get the actual numbers
    prefix = "__SECCOMP_"  # prefix to ensure no name collisions
    cpp = Popen([
        "../../prebuilts/clang/host/linux-x86/clang-stable/bin/clang", "-E",
        "-nostdinc", "-I" + header_dir, "-Ikernel/uapi/", "-"
    ],
                stdin=PIPE,
                stdout=PIPE)
    cpp.stdin.write("#include <asm/unistd.h>\n")
    for name in names:
        # In SYSCALLS.TXT, there are two arm-specific syscalls whose names start
        # with __ARM__NR_. These we must simply write out as is.
        if not name.startswith("__ARM_NR_"):
            cpp.stdin.write(prefix + name + ", __NR_" + name + "\n")
        else:
            cpp.stdin.write(prefix + name + ", " + name + "\n")
    content = cpp.communicate()[0].split("\n")

    # The input is now the preprocessed source file. This will contain a lot
    # of junk from the preprocessor, but our lines will be in the format:
    #
    #     __SECCOMP_${NAME}, (0 + value)

    syscalls = []
    for line in content:
        if not line.startswith(prefix):
            continue

        # We might pick up extra whitespace during preprocessing, so best to strip.
        name, value = [w.strip() for w in line.split(",")]
        name = name[len(prefix):]

        # Note that some of the numbers were expressed as base + offset, so we
        # need to eval, not just int
        value = eval(value)
        syscalls.append((name, value))

    # Sort the values so we convert to ranges and binary chop
    syscalls = sorted(syscalls, lambda x, y: cmp(x[1], y[1]))

    # Turn into a list of ranges. Keep the names for the comments
    ranges = []
    for name, value in syscalls:
        if not ranges:
            ranges.append(SyscallRange(name, value))
            continue

        last_range = ranges[-1]
        if last_range.end == value:
            last_range.add(name, value)
        else:
            ranges.append(SyscallRange(name, value))

    bpf = convert_to_bpf(ranges)

    # Now we know the size of the tree, we can substitute the {fail} and {allow}
    # placeholders
    for i, statement in enumerate(bpf):
        # Replace placeholder with
        # "distance to jump to fail, distance to jump to allow"
        # We will add a kill statement and an allow statement after the tree
        # With bpfs jmp 0 means the next statement, so the distance to the end is
        # len(bpf) - i - 1, which is where we will put the kill statement, and
        # then the statement after that is the allow statement
        if "{fail}" in statement and "{allow}" in statement:
            bpf[i] = statement.format(fail=str(len(bpf) - i),
                                      allow=str(len(bpf) - i - 1))

    # Add check that we aren't off the bottom of the syscalls
    bpf.insert(
        0, "BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, " + str(ranges[0].begin) +
        ", 0, " + str(len(bpf)) + "),")

    # Add the allow calls at the end. If the syscall is not matched, we will
    # continue. This allows the user to choose to match further syscalls, and
    # also to choose the action when we want to block
    bpf.append("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),")

    # And output policy
    header = textwrap.dedent("""\
    // Autogenerated file - edit at your peril!!

    #include <linux/filter.h>
    #include <errno.h>

    #include "seccomp_policy.h"
    const struct sock_filter {architecture}_filter[] = {{
    """).format(architecture=architecture)

    footer = textwrap.dedent("""\

    }};

    const size_t {architecture}_filter_size = sizeof({architecture}_filter) / sizeof(struct sock_filter);
    """).format(architecture=architecture)
    output = header + "\n".join(bpf) + footer

    existing = ""
    if os.path.isfile(output_path):
        existing = open(output_path).read()
    if output == existing:
        print "File " + output_path + " not changed."
    else:
        with open(output_path, "w") as output_file:
            output_file.write(output)

        print "Generated file " + output_path
Пример #8
0
def load_syscall_names_from_file(file_path, architecture):
  parser = SysCallsTxtParser()
  parser.parse_open_file(open(file_path))
  return set([x["name"] for x in parser.syscalls if x.get(architecture)])