#!/bin/python # This program records syscalls. Either from a specific point in your program # or just from the start. # # It works in two steps: Recording syscalls and creating an white-list, ready to paste into your # Jai code. # # In case you want to only restrict syscalls from a specific point on, set this marker # in any place of your program: # # ``` # log("---- SECCOMP BOUNDARY ----"); # ``` # # # First step, recording: # # ``` # ./seccomp_collect_syscalls.py -r your_program # ``` # # After that, it depends if you have a boundary marker in your program. # With boundary marker: # # ``` # ./seccomp_collect_syscalls.py -p strace.txt # ``` # # Without boundary marker: # # ``` # ./seccomp_collect_syscalls.py -i -p strace.txt # ``` # # Well, you can pass `-i` even with a boundary marker, it will ignore it anyway. import subprocess import os from sys import exit, argv from pathlib import Path ignore_marker = False HELP = """Usage: syscalls.py [OPTIONS] [FP] OPTIONS -r Records syscalls -p Prints the used syscalls from your 'strace.txt'. If the path is omitted, it looks after 'strace.txt' in your current directory. -i Ignore boundary marker when using `-p` """ STRACE_OUTPUT_FP = Path("strace.txt") SCMP_BOUNDARY_MARKER = "---- SECCOMP BOUNDARY ----" def main(args): global ignore_marker if len(args) == 1: print(HELP) exit(1) if "h" in args[1] or "help" in args[1]: print(HELP) exit(0) if args[1] == "-r": if len(args) < 3: print("Need filepath to program") exit(1) strace_run(args[2:]) if args[1] == "-p": fp = STRACE_OUTPUT_FP if len(args) == 2 else args[2] fp = Path(fp) ignore_marker = "-i" in args gather_unique_syscalls(fp) print("Unknown argument") exit(1) def strace_run(program): cmd = [ "strace", "-o", STRACE_OUTPUT_FP, *program ] run_command(cmd) exit(0) def gather_unique_syscalls(fp): global ignore_marker if not fp.exists(): print("File does not exist:", fp) exit(1) content = open_file_or_exit(fp) boundary_idx = next( (i for i, s in enumerate(content) if SCMP_BOUNDARY_MARKER in s), None ) if not ignore_marker: if boundary_idx == None: print("Cannot find seccomp boundary marker") exit(1) boundary_idx += 1 content = content[boundary_idx:] else: boundary_idx = 0 syscalls = set() for i, line in enumerate(content): idx = line.find("(") if idx == -1: syscall = f"[ERR: at line {i + boundary_idx}]" continue else: syscall = line[:idx] syscalls.add(syscall) program_fn = os.path.basename(__file__) print(f"/** Copy pasta from {program_fn} */") print("SECCOMP_ALLOWED_SYSCALLS :: string.[") for item in syscalls: code = f' "{item.upper()}",' print(code) print("];") exit(0) def run_command(cmd): try: subprocess.run(cmd, text=True, check=True) except subprocess.CalledProcessError as e: print(f"Command failed {e.returncode}: {e.stderr}") exit(1) def open_file_or_exit(fp): try: with open(fp, 'r', encoding="utf8") as f: return f.readlines() except Exception as e: print(e) exit(1) if __name__ == "__main__": args = argv try: main(args) except KeyboardInterrupt: print("Terminated by user") exit(1) # ------------------------------------------------------------------------------ # This software is available under 2 licenses -- choose whichever you prefer. # ------------------------------------------------------------------------------ # ALTERNATIVE A - MIT License # Copyright (c) 2026 Adam Blazeowsky # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies # of the Software, and to permit persons to whom the Software is furnished to do # so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # ------------------------------------------------------------------------------ # ALTERNATIVE B - Public Domain (www.unlicense.org) # This is free and unencumbered software released into the public domain. # Anyone is free to copy, modify, publish, use, compile, sell, or distribute this # software, either in source code form or as a compiled binary, for any purpose, # commercial or non-commercial, and by any means. # In jurisdictions that recognize copyright laws, the author or authors of this # software dedicate any and all copyright interest in the software to the public # domain. We make this dedication for the benefit of the public at large and to # the detriment of our heirs and successors. We intend this dedication to be an # overt act of relinquishment in perpetuity of all present and future rights to # this software under copyright law. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ------------------------------------------------------------------------------