You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.8 KiB
190 lines
5.8 KiB
#!/usr/bin/env python3
|
|
#
|
|
# This script generates syscall name to number mapping for supported
|
|
# architectures. To update the output, runs:
|
|
#
|
|
# $ app/gen_blocklist.py --allowed app/assets/syscalls_allowed.json \
|
|
# --blocked app/assets/syscalls_blocked.json
|
|
#
|
|
# Note that these are just syscalls that explicitly allowed and blocked in CTS
|
|
# currently.
|
|
#
|
|
# TODO: Consider generating it in Android.mk/bp.
|
|
|
|
import argparse
|
|
import glob
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
_SUPPORTED_ARCHS = ['arm', 'arm64', 'x86', 'x86_64', 'mips', 'mips64']
|
|
|
|
# Syscalls that are currently explicitly allowed in CTS
|
|
_SYSCALLS_ALLOWED_IN_CTS = {
|
|
'openat': 'all',
|
|
|
|
# b/35034743 - do not remove test without reading bug.
|
|
'syncfs': 'arm64',
|
|
|
|
# b/35906875 - do not remove test without reading bug
|
|
'inotify_init': 'arm',
|
|
}
|
|
|
|
# Syscalls that are currently explicitly blocked in CTS
|
|
_SYSCALLS_BLOCKED_IN_CTS = {
|
|
'acct': 'all',
|
|
'add_key': 'all',
|
|
'adjtimex': 'all',
|
|
'chroot': 'all',
|
|
'clock_adjtime': 'all',
|
|
'clock_settime': 'all',
|
|
'delete_module': 'all',
|
|
'init_module': 'all',
|
|
'keyctl': 'all',
|
|
'mount': 'all',
|
|
'reboot': 'all',
|
|
'setdomainname': 'all',
|
|
'sethostname': 'all',
|
|
'settimeofday': 'all',
|
|
'setfsgid': 'all',
|
|
'setfsuid': 'all',
|
|
'setgid': 'all',
|
|
'setgid32': 'x86,arm',
|
|
'setgroups': 'all',
|
|
'setgroups32': 'x86,arm',
|
|
'setregid': 'all',
|
|
'setregid32': 'x86,arm',
|
|
'setresgid': 'all',
|
|
'setresgid32': 'x86,arm',
|
|
'setreuid': 'all',
|
|
'setreuid32': 'x86,arm',
|
|
'setuid': 'all',
|
|
'setuid32': 'x86,arm',
|
|
'swapoff': 'all',
|
|
'swapoff': 'all',
|
|
'swapon': 'all',
|
|
'swapon': 'all',
|
|
'syslog': 'all',
|
|
'umount2': 'all',
|
|
}
|
|
|
|
def create_syscall_name_to_number_map(arch, names):
|
|
arch_config = {
|
|
'arm': {
|
|
'uapi_class': 'asm-arm',
|
|
'extra_cflags': [],
|
|
},
|
|
'arm64': {
|
|
'uapi_class': 'asm-arm64',
|
|
'extra_cflags': [],
|
|
},
|
|
'x86': {
|
|
'uapi_class': 'asm-x86',
|
|
'extra_cflags': ['-D__i386__'],
|
|
},
|
|
'x86_64': {
|
|
'uapi_class': 'asm-x86',
|
|
'extra_cflags': [],
|
|
},
|
|
'mips': {
|
|
'uapi_class': 'asm-mips',
|
|
'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI32'],
|
|
},
|
|
'mips64': {
|
|
'uapi_class': 'asm-mips',
|
|
'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI64'],
|
|
}
|
|
}
|
|
|
|
# Run preprocessor over the __NR_syscall symbols, including unistd.h,
|
|
# to get the actual numbers
|
|
# TODO: The following code is forked from bionic/libc/tools/genseccomp.py.
|
|
# Figure out if we can de-duplicate them crossing cts project boundary.
|
|
prefix = '__SECCOMP_' # prefix to ensure no name collisions
|
|
kernel_uapi_path = os.path.join(os.getenv('ANDROID_BUILD_TOP'),
|
|
'bionic/libc/kernel/uapi')
|
|
cpp = subprocess.Popen(
|
|
[get_latest_clang_path(),
|
|
'-E', '-nostdinc',
|
|
'-I' + os.path.join(kernel_uapi_path,
|
|
arch_config[arch]['uapi_class']),
|
|
'-I' + os.path.join(kernel_uapi_path)
|
|
]
|
|
+ arch_config[arch]['extra_cflags']
|
|
+ ['-'],
|
|
universal_newlines=True,
|
|
stdin=subprocess.PIPE, stdout=subprocess.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)
|
|
if name in syscalls:
|
|
raise Exception('syscall %s is re-defined' % name)
|
|
syscalls[name] = value
|
|
return syscalls
|
|
|
|
def get_latest_clang_path():
|
|
candidates = sorted(glob.glob(os.path.join(os.getenv('ANDROID_BUILD_TOP'),
|
|
'prebuilts/clang/host/linux-x86/clang-*')), reverse=True)
|
|
for clang_dir in candidates:
|
|
clang_exe = os.path.join(clang_dir, 'bin/clang')
|
|
if os.path.exists(clang_exe):
|
|
return clang_exe
|
|
raise FileNotFoundError('Cannot locate clang executable')
|
|
|
|
def collect_syscall_names_for_arch(syscall_map, arch):
|
|
syscall_names = []
|
|
for syscall in syscall_map.keys():
|
|
if (arch in syscall_map[syscall] or
|
|
'all' == syscall_map[syscall]):
|
|
syscall_names.append(syscall)
|
|
return syscall_names
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser('syscall name to number generator')
|
|
parser.add_argument('--allowed', metavar='path/to/json', type=str)
|
|
parser.add_argument('--blocked', metavar='path/to/json', type=str)
|
|
args = parser.parse_args()
|
|
|
|
allowed = {}
|
|
blocked = {}
|
|
for arch in _SUPPORTED_ARCHS:
|
|
blocked[arch] = create_syscall_name_to_number_map(
|
|
arch,
|
|
collect_syscall_names_for_arch(_SYSCALLS_BLOCKED_IN_CTS, arch))
|
|
allowed[arch] = create_syscall_name_to_number_map(
|
|
arch,
|
|
collect_syscall_names_for_arch(_SYSCALLS_ALLOWED_IN_CTS, arch))
|
|
|
|
msg_do_not_modify = '# DO NOT MODIFY. CHANGE gen_blocklist.py INSTEAD.'
|
|
with open(args.allowed, 'w') as f:
|
|
print(msg_do_not_modify, file=f)
|
|
json.dump(allowed, f, sort_keys=True, indent=2)
|
|
|
|
with open(args.blocked, 'w') as f:
|
|
print(msg_do_not_modify, file=f)
|
|
json.dump(blocked, f, sort_keys=True, indent=2)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|