1#!/usr/bin/env python3 2# 3# This script generates syscall name to number mapping for supported 4# architectures. To update the output, runs: 5# 6# $ app/gen_blocklist.py --allowed app/assets/syscalls_allowed.json \ 7# --blocked app/assets/syscalls_blocked.json 8# 9# Note that these are just syscalls that explicitly allowed and blocked in CTS 10# currently. 11# 12# TODO: Consider generating it in Android.mk/bp. 13 14import argparse 15import glob 16import json 17import os 18import subprocess 19 20_SUPPORTED_ARCHS = ['arm', 'arm64', 'x86', 'x86_64', 'mips', 'mips64'] 21 22# Syscalls that are currently explicitly allowed in CTS 23_SYSCALLS_ALLOWED_IN_CTS = { 24 'openat': 'all', 25 26 # b/35034743 - do not remove test without reading bug. 27 'syncfs': 'arm64', 28 29 # b/35906875 - do not remove test without reading bug 30 'inotify_init': 'arm', 31} 32 33# Syscalls that are currently explicitly blocked in CTS 34_SYSCALLS_BLOCKED_IN_CTS = { 35 'acct': 'all', 36 'add_key': 'all', 37 'adjtimex': 'all', 38 'chroot': 'all', 39 'clock_adjtime': 'all', 40 'clock_settime': 'all', 41 'delete_module': 'all', 42 'init_module': 'all', 43 'keyctl': 'all', 44 'mount': 'all', 45 'reboot': 'all', 46 'setdomainname': 'all', 47 'sethostname': 'all', 48 'settimeofday': 'all', 49 'setfsgid': 'all', 50 'setfsuid': 'all', 51 'setgid': 'all', 52 'setgid32': 'x86,arm', 53 'setgroups': 'all', 54 'setgroups32': 'x86,arm', 55 'setregid': 'all', 56 'setregid32': 'x86,arm', 57 'setresgid': 'all', 58 'setresgid32': 'x86,arm', 59 'setreuid': 'all', 60 'setreuid32': 'x86,arm', 61 'setuid': 'all', 62 'setuid32': 'x86,arm', 63 'swapoff': 'all', 64 'swapoff': 'all', 65 'swapon': 'all', 66 'swapon': 'all', 67 'syslog': 'all', 68 'umount2': 'all', 69} 70 71def create_syscall_name_to_number_map(arch, names): 72 arch_config = { 73 'arm': { 74 'uapi_class': 'asm-arm', 75 'extra_cflags': [], 76 }, 77 'arm64': { 78 'uapi_class': 'asm-arm64', 79 'extra_cflags': [], 80 }, 81 'x86': { 82 'uapi_class': 'asm-x86', 83 'extra_cflags': ['-D__i386__'], 84 }, 85 'x86_64': { 86 'uapi_class': 'asm-x86', 87 'extra_cflags': [], 88 }, 89 'mips': { 90 'uapi_class': 'asm-mips', 91 'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI32'], 92 }, 93 'mips64': { 94 'uapi_class': 'asm-mips', 95 'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI64'], 96 } 97 } 98 99 # Run preprocessor over the __NR_syscall symbols, including unistd.h, 100 # to get the actual numbers 101 # TODO: The following code is forked from bionic/libc/tools/genseccomp.py. 102 # Figure out if we can de-duplicate them crossing cts project boundary. 103 prefix = '__SECCOMP_' # prefix to ensure no name collisions 104 kernel_uapi_path = os.path.join(os.getenv('ANDROID_BUILD_TOP'), 105 'bionic/libc/kernel/uapi') 106 cpp = subprocess.Popen( 107 [get_latest_clang_path(), 108 '-E', '-nostdinc', 109 '-I' + os.path.join(kernel_uapi_path, 110 arch_config[arch]['uapi_class']), 111 '-I' + os.path.join(kernel_uapi_path) 112 ] 113 + arch_config[arch]['extra_cflags'] 114 + ['-'], 115 universal_newlines=True, 116 stdin=subprocess.PIPE, stdout=subprocess.PIPE) 117 cpp.stdin.write('#include <asm/unistd.h>\n') 118 for name in names: 119 # In SYSCALLS.TXT, there are two arm-specific syscalls whose names start 120 # with __ARM__NR_. These we must simply write out as is. 121 if not name.startswith('__ARM_NR_'): 122 cpp.stdin.write(prefix + name + ', __NR_' + name + '\n') 123 else: 124 cpp.stdin.write(prefix + name + ', ' + name + '\n') 125 content = cpp.communicate()[0].split('\n') 126 127 # The input is now the preprocessed source file. This will contain a lot 128 # of junk from the preprocessor, but our lines will be in the format: 129 # 130 # __SECCOMP_${NAME}, (0 + value) 131 syscalls = {} 132 for line in content: 133 if not line.startswith(prefix): 134 continue 135 # We might pick up extra whitespace during preprocessing, so best to strip. 136 name, value = [w.strip() for w in line.split(',')] 137 name = name[len(prefix):] 138 # Note that some of the numbers were expressed as base + offset, so we 139 # need to eval, not just int 140 value = eval(value) 141 if name in syscalls: 142 raise Exception('syscall %s is re-defined' % name) 143 syscalls[name] = value 144 return syscalls 145 146def get_latest_clang_path(): 147 candidates = sorted(glob.glob(os.path.join(os.getenv('ANDROID_BUILD_TOP'), 148 'prebuilts/clang/host/linux-x86/clang-*')), reverse=True) 149 for clang_dir in candidates: 150 clang_exe = os.path.join(clang_dir, 'bin/clang') 151 if os.path.exists(clang_exe): 152 return clang_exe 153 raise FileNotFoundError('Cannot locate clang executable') 154 155def collect_syscall_names_for_arch(syscall_map, arch): 156 syscall_names = [] 157 for syscall in syscall_map.keys(): 158 if (arch in syscall_map[syscall] or 159 'all' == syscall_map[syscall]): 160 syscall_names.append(syscall) 161 return syscall_names 162 163def main(): 164 parser = argparse.ArgumentParser('syscall name to number generator') 165 parser.add_argument('--allowed', metavar='path/to/json', type=str) 166 parser.add_argument('--blocked', metavar='path/to/json', type=str) 167 args = parser.parse_args() 168 169 allowed = {} 170 blocked = {} 171 for arch in _SUPPORTED_ARCHS: 172 blocked[arch] = create_syscall_name_to_number_map( 173 arch, 174 collect_syscall_names_for_arch(_SYSCALLS_BLOCKED_IN_CTS, arch)) 175 allowed[arch] = create_syscall_name_to_number_map( 176 arch, 177 collect_syscall_names_for_arch(_SYSCALLS_ALLOWED_IN_CTS, arch)) 178 179 msg_do_not_modify = '# DO NOT MODIFY. CHANGE gen_blocklist.py INSTEAD.' 180 with open(args.allowed, 'w') as f: 181 print(msg_do_not_modify, file=f) 182 json.dump(allowed, f, sort_keys=True, indent=2) 183 184 with open(args.blocked, 'w') as f: 185 print(msg_do_not_modify, file=f) 186 json.dump(blocked, f, sort_keys=True, indent=2) 187 188if __name__ == '__main__': 189 main() 190