Merge "riscv64 syscall stub and seccomp filter generation."

This commit is contained in:
Elliott Hughes 2022-10-14 14:36:29 +00:00 committed by Gerrit Code Review
commit 4c2de1fccc
7 changed files with 304 additions and 78 deletions

View file

@ -1304,6 +1304,14 @@ genrule {
cmd: "$(location gensyscalls) arm64 $(in) > $(out)",
}
genrule {
name: "syscalls-riscv64.S",
out: ["syscalls-riscv64.S"],
srcs: ["SYSCALLS.TXT"],
tools: ["gensyscalls"],
cmd: "$(location gensyscalls) riscv64 $(in) > $(out)",
}
genrule {
name: "syscalls-x86.S",
out: ["syscalls-x86.S"],
@ -1330,6 +1338,9 @@ cc_library_static {
arm64: {
srcs: [":syscalls-arm64.S"],
},
riscv64: {
srcs: [":syscalls-riscv64.S"],
},
x86: {
srcs: [":syscalls-x86.S"],
},
@ -2353,6 +2364,15 @@ cc_object {
],
}
cc_object {
name: "libseccomp_gen_syscall_nrs_riscv64",
defaults: ["libseccomp_gen_syscall_nrs_defaults"],
local_include_dirs: [
"kernel/uapi/asm-riscv",
"kernel/uapi",
],
}
cc_object {
name: "libseccomp_gen_syscall_nrs_x86",
defaults: ["libseccomp_gen_syscall_nrs_defaults"],
@ -2390,12 +2410,38 @@ cc_genrule {
srcs: [
"SYSCALLS.TXT",
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
arch: {
arm: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
},
arm64: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
},
riscv64: {
srcs: [":libseccomp_gen_syscall_nrs_riscv64"],
},
x86: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
},
x86_64: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
},
},
out: [
"func_to_syscall_nrs.h",
],
@ -2423,18 +2469,54 @@ cc_genrule {
"SECCOMP_BLOCKLIST_COMMON.TXT",
"SECCOMP_PRIORITY.TXT",
":generate_app_zygote_blocklist",
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"arm64_app_zygote_policy.cpp",
"arm_app_zygote_policy.cpp",
"x86_64_app_zygote_policy.cpp",
"x86_app_zygote_policy.cpp",
],
arch: {
arm: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
out: [
"arm_app_zygote_policy.cpp",
"arm64_app_zygote_policy.cpp",
],
},
arm64: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
out: [
"arm_app_zygote_policy.cpp",
"arm64_app_zygote_policy.cpp",
],
},
riscv64: {
srcs: [":libseccomp_gen_syscall_nrs_riscv64"],
out: ["riscv64_app_zygote_policy.cpp"],
},
x86: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"x86_app_zygote_policy.cpp",
"x86_64_app_zygote_policy.cpp",
],
},
x86_64: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"x86_app_zygote_policy.cpp",
"x86_64_app_zygote_policy.cpp",
],
},
},
}
cc_genrule {
@ -2451,18 +2533,54 @@ cc_genrule {
"SECCOMP_BLOCKLIST_COMMON.TXT",
"SECCOMP_BLOCKLIST_APP.TXT",
"SECCOMP_PRIORITY.TXT",
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"arm64_app_policy.cpp",
"arm_app_policy.cpp",
"x86_64_app_policy.cpp",
"x86_app_policy.cpp",
],
arch: {
arm: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
out: [
"arm_app_policy.cpp",
"arm64_app_policy.cpp",
],
},
arm64: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
out: [
"arm_app_policy.cpp",
"arm64_app_policy.cpp",
],
},
riscv64: {
srcs: [":libseccomp_gen_syscall_nrs_riscv64"],
out: ["riscv64_app_policy.cpp"],
},
x86: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"x86_app_policy.cpp",
"x86_64_app_policy.cpp",
],
},
x86_64: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"x86_app_policy.cpp",
"x86_64_app_policy.cpp",
],
},
},
}
cc_genrule {
@ -2478,18 +2596,54 @@ cc_genrule {
"SECCOMP_ALLOWLIST_SYSTEM.TXT",
"SECCOMP_BLOCKLIST_COMMON.TXT",
"SECCOMP_PRIORITY.TXT",
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"arm64_system_policy.cpp",
"arm_system_policy.cpp",
"x86_64_system_policy.cpp",
"x86_system_policy.cpp",
],
arch: {
arm: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
out: [
"arm_system_policy.cpp",
"arm64_system_policy.cpp",
],
},
arm64: {
srcs: [
":libseccomp_gen_syscall_nrs_arm",
":libseccomp_gen_syscall_nrs_arm64",
],
out: [
"arm_system_policy.cpp",
"arm64_system_policy.cpp",
],
},
riscv64: {
srcs: [":libseccomp_gen_syscall_nrs_riscv64"],
out: ["riscv64_system_policy.cpp"],
},
x86: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"x86_system_policy.cpp",
"x86_64_system_policy.cpp",
],
},
x86_64: {
srcs: [
":libseccomp_gen_syscall_nrs_x86",
":libseccomp_gen_syscall_nrs_x86_64",
],
out: [
"x86_system_policy.cpp",
"x86_64_system_policy.cpp",
],
},
},
}
cc_library {

View file

@ -7,7 +7,7 @@
# where:
# arch_list ::= "all" | arches
# arches ::= arch | arch "," arches
# arch ::= "arm" | "arm64" | "x86" | "x86_64" | "lp32" | "lp64"
# arch ::= "arm" | "arm64" | "riscv64" | "x86" | "x86_64" | "lp32" | "lp64"
#
# Note:
# - syscall_name corresponds to the name of the syscall, which may differ from
@ -352,6 +352,9 @@ int __waitid:waitid(int, pid_t, siginfo_t*, int, void*) all
int __set_tls:__ARM_NR_set_tls(void*) arm
int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm
# riscv64-specific
int _flush_icache:riscv_flush_icache(void*, void*, unsigned long) riscv64
# x86-specific
int __set_thread_area:set_thread_area(void*) x86

View file

@ -33,6 +33,13 @@ extern const size_t arm64_app_zygote_filter_size;
extern const struct sock_filter arm64_system_filter[];
extern const size_t arm64_system_filter_size;
extern const struct sock_filter riscv64_app_filter[];
extern const size_t riscv64_app_filter_size;
extern const struct sock_filter riscv64_app_zygote_filter[];
extern const size_t riscv64_app_zygote_filter_size;
extern const struct sock_filter riscv64_system_filter[];
extern const size_t riscv64_system_filter_size;
extern const struct sock_filter x86_app_filter[];
extern const size_t x86_app_filter_size;
extern const struct sock_filter x86_app_zygote_filter[];

View file

@ -25,13 +25,13 @@
#include <vector>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include "func_to_syscall_nrs.h"
#include "seccomp_bpfs.h"
#if defined __arm__ || defined __aarch64__
#define DUAL_ARCH
#define PRIMARY_ARCH AUDIT_ARCH_AARCH64
static const struct sock_filter* primary_app_filter = arm64_app_filter;
static const size_t primary_app_filter_size = arm64_app_filter_size;
@ -52,9 +52,9 @@ static const size_t secondary_system_filter_size = arm_system_filter_size;
static const long secondary_setresgid = __arm_setresgid;
static const long secondary_setresuid = __arm_setresuid;
#elif defined __i386__ || defined __x86_64__
#define DUAL_ARCH
#define PRIMARY_ARCH AUDIT_ARCH_X86_64
static const struct sock_filter* primary_app_filter = x86_64_app_filter;
static const size_t primary_app_filter_size = x86_64_app_filter_size;
@ -75,6 +75,20 @@ static const size_t secondary_system_filter_size = x86_system_filter_size;
static const long secondary_setresgid = __x86_setresgid;
static const long secondary_setresuid = __x86_setresuid;
#elif defined(__riscv)
#define PRIMARY_ARCH AUDIT_ARCH_RISCV64
static const struct sock_filter* primary_app_filter = riscv64_app_filter;
static const size_t primary_app_filter_size = riscv64_app_filter_size;
static const struct sock_filter* primary_app_zygote_filter = riscv64_app_zygote_filter;
static const size_t primary_app_zygote_filter_size = riscv64_app_zygote_filter_size;
static const struct sock_filter* primary_system_filter = riscv64_system_filter;
static const size_t primary_system_filter_size = riscv64_system_filter_size;
static const long primary_setresgid = __riscv64_setresgid;
static const long primary_setresuid = __riscv64_setresuid;
#else
#error No architecture was defined!
#endif
@ -98,7 +112,7 @@ static void ExamineSyscall(filter& f) {
f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
}
#ifdef DUAL_ARCH
#if defined(SECONDARY_ARCH)
static bool SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
size_t jump_length = f.size() - offset - 1;
auto u8_jump_length = (__u8) jump_length;
@ -149,9 +163,17 @@ static void ValidateSyscallArgInRange(filter& f, __u32 arg_num, __u32 range_min,
// that's the only system call we need to check here. A CTS test ensures the other
// calls will remain blocked.
static void ValidateSetUidGid(filter& f, uint32_t uid_gid_min, uint32_t uid_gid_max, bool primary) {
#if defined(SECONDARY_ARCH)
__u32 setresuid_nr = primary ? primary_setresuid : secondary_setresuid;
__u32 setresgid_nr = primary ? primary_setresgid : secondary_setresgid;
#else
__u32 setresuid_nr = primary_setresuid;
__u32 setresgid_nr = primary_setresgid;
UNUSED(primary);
#endif
// Check setresuid(ruid, euid, sguid) fall within range
ExamineSyscall(f);
__u32 setresuid_nr = primary ? primary_setresuid : secondary_setresuid;
f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, setresuid_nr, 0, 12));
for (int arg = 0; arg < 3; arg++) {
ValidateSyscallArgInRange(f, arg, uid_gid_min, uid_gid_max);
@ -159,7 +181,6 @@ static void ValidateSetUidGid(filter& f, uint32_t uid_gid_min, uint32_t uid_gid_
// Check setresgid(rgid, egid, sgid) fall within range
ExamineSyscall(f);
__u32 setresgid_nr = primary ? primary_setresgid : secondary_setresgid;
f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, setresgid_nr, 0, 12));
for (int arg = 0; arg < 3; arg++) {
ValidateSyscallArgInRange(f, arg, uid_gid_min, uid_gid_max);
@ -184,7 +205,7 @@ static bool install_filter(filter const& f) {
bool _install_setuidgid_filter(uint32_t uid_gid_min, uint32_t uid_gid_max) {
filter f;
#ifdef DUAL_ARCH
#if defined(SECONDARY_ARCH)
// Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
// jump that must be changed to point to the start of the 32-bit policy
// 32 bit syscalls will not hit the policy between here and the call to SetJump
@ -195,7 +216,7 @@ bool _install_setuidgid_filter(uint32_t uid_gid_min, uint32_t uid_gid_max) {
ValidateSetUidGid(f, uid_gid_min, uid_gid_max, true /* primary */);
#ifdef DUAL_ARCH
#if defined(SECONDARY_ARCH)
if (!SetValidateArchitectureJumpTarget(offset_to_secondary_filter, f)) {
return false;
}
@ -213,32 +234,43 @@ enum FilterType {
};
bool _set_seccomp_filter(FilterType type) {
const sock_filter *p, *s;
size_t p_size, s_size;
filter f;
const sock_filter* p;
size_t p_size;
#if defined(SECONDARY_ARCH)
const sock_filter* s;
size_t s_size;
#endif
switch (type) {
case APP:
p = primary_app_filter;
p_size = primary_app_filter_size;
#if defined(SECONDARY_ARCH)
s = secondary_app_filter;
s_size = secondary_app_filter_size;
#endif
break;
case APP_ZYGOTE:
p = primary_app_zygote_filter;
p_size = primary_app_zygote_filter_size;
#if defined(SECONDARY_ARCH)
s = secondary_app_zygote_filter;
s_size = secondary_app_zygote_filter_size;
#endif
break;
case SYSTEM:
p = primary_system_filter;
p_size = primary_system_filter_size;
#if defined(SECONDARY_ARCH)
s = secondary_system_filter;
s_size = secondary_system_filter_size;
#endif
break;
}
#ifdef DUAL_ARCH
#if defined(SECONDARY_ARCH)
// Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
// jump that must be changed to point to the start of the 32-bit policy
// 32 bit syscalls will not hit the policy between here and the call to SetJump
@ -254,7 +286,7 @@ bool _set_seccomp_filter(FilterType type) {
}
Disallow(f);
#ifdef DUAL_ARCH
#if defined(SECONDARY_ARCH)
if (!SetValidateArchitectureJumpTarget(offset_to_secondary_filter, f)) {
return false;
}

View file

@ -21,12 +21,12 @@ def load_syscall_names_from_file(file_path, architecture):
def gen_syscall_nrs(out_file, base_syscall_file, syscall_NRs):
for arch in SupportedArchitectures:
for arch in syscall_NRs.keys():
base_names = load_syscall_names_from_file(base_syscall_file, arch)
for func, syscall in base_names.items():
out_file.write("#define __" + arch + "_" + func + " " +
str(syscall_NRs[arch][syscall]) + ";\n")
str(syscall_NRs[arch][syscall]) + "\n")
def main():

View file

@ -5,9 +5,10 @@ import logging
import operator
import os
import re
import sys
import textwrap
from gensyscalls import SupportedArchitectures, SysCallsTxtParser
from gensyscalls import SysCallsTxtParser
BPF_JGE = "BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, {0}, {1}, {2})"
@ -84,42 +85,46 @@ def parse_syscall_NRs(names_path):
# #define __(ARM_)?NR_${NAME} ${VALUE}
#
# Where ${VALUE} is a preprocessor expression.
#
# Newer architectures have things like this though:
#
# #define __NR3264_fcntl 25
# #define __NR_fcntl __NR3264_fcntl
#
# So we need to keep track of the __NR3264_* constants and substitute them.
constant_re = re.compile(
r'^\s*#define\s+([A-Za-z_][A-Za-z0-9_]+)\s+(.+)\s*$')
line_re = re.compile(r'^# \d+ ".*".*')
undef_re = re.compile(r'^#undef\s.*')
define_re = re.compile(r'^\s*#define\s+([A-Za-z0-9_(,)]+)(?:\s+(.+))?\s*$')
token_re = re.compile(r'\b[A-Za-z_][A-Za-z0-9_]+\b')
constants = {}
nr3264s = {}
with open(names_path) as f:
for line in f:
m = constant_re.match(line)
if m is None:
continue
try:
line = line.strip()
m = define_re.match(line)
if m:
name = m.group(1)
# eval() takes care of any arithmetic that may be done
value = eval(token_re.sub(lambda x: str(constants[x.group(0)]),
m.group(2)))
value = m.group(2)
if name.startswith('__NR3264'):
nr3264s[name] = value
elif name.startswith('__NR_') or name.startswith('__ARM_NR_'):
if value in nr3264s:
value = nr3264s[value]
# eval() takes care of any arithmetic that may be done
value = eval(token_re.sub(lambda x: str(constants[x.group(0)]), value))
constants[name] = value
except: # pylint: disable=bare-except
# TODO: This seems wrong.
# Key error doesn't seem like the error the original author was trying
# to catch. It looks like the intent was to catch IndexError from
# match.group() for non-matching lines, but that's impossible because
# the match object is checked and continued if not matched. What
# actually happens is that KeyError is thrown by constants[x.group(0)]
# on at least the first run because the dict is empty.
#
# It's also matching syntax errors because not all C integer literals
# are valid Python integer literals, e.g. 10L.
logging.debug('Failed to parse %s', line)
constants[name] = value
else:
if not line_re.match(line) and not undef_re.match(line) and line:
print('%s: failed to parse line `%s`' % (names_path, line))
sys.exit(1)
syscalls = {}
for name, value in constants.items():
if not name.startswith("__NR_") and not name.startswith("__ARM_NR"):
continue
# Remove the __NR_ prefix.
# TODO: why not __ARM_NR too?
if name.startswith("__NR_"):
# Remote the __NR_ prefix
name = name[len("__NR_"):]
syscalls[name] = value
@ -237,7 +242,7 @@ def construct_bpf(syscalls, architecture, name_modifier, priorities):
def gen_policy(name_modifier, out_dir, base_syscall_file, syscall_files,
syscall_NRs, priority_file):
for arch in SupportedArchitectures:
for arch in syscall_NRs.keys():
base_names = load_syscall_names_from_file(base_syscall_file, arch)
allowlist_names = set()
blocklist_names = set()
@ -251,11 +256,11 @@ def gen_policy(name_modifier, out_dir, base_syscall_file, syscall_files,
priorities = load_syscall_priorities_from_file(priority_file)
allowed_syscalls = []
for name in merge_names(base_names, allowlist_names, blocklist_names):
for name in sorted(merge_names(base_names, allowlist_names, blocklist_names)):
try:
allowed_syscalls.append((name, syscall_NRs[arch][name]))
except:
logging.exception("Failed to find %s in %s", name, arch)
logging.exception("Failed to find %s in %s (%s)", name, arch, syscall_NRs[arch])
raise
output = construct_bpf(allowed_syscalls, arch, name_modifier, priorities)

View file

@ -15,7 +15,7 @@ import sys
import tempfile
SupportedArchitectures = [ "arm", "arm64", "x86", "x86_64" ]
SupportedArchitectures = [ "arm", "arm64", "riscv64", "x86", "x86_64" ]
syscall_stub_header = \
"""
@ -79,6 +79,24 @@ END(%(func)s)
"""
#
# RISC-V64 assembler templates for each syscall stub
#
riscv64_call = syscall_stub_header + """\
li a7, %(__NR_name)s
ecall
li a7, -MAX_ERRNO
bgtu a0, a7, 1f
ret
1:
neg a0, a0
j __set_errno_internal
END(%(func)s)
"""
#
# x86 assembler templates for each syscall stub
#
@ -228,6 +246,10 @@ def arm64_genstub(syscall):
return arm64_call % syscall
def riscv64_genstub(syscall):
return riscv64_call % syscall
def x86_genstub(syscall):
result = syscall_stub_header % syscall
@ -440,6 +462,9 @@ def main(arch, syscall_file):
if "arm64" in syscall:
syscall["asm-arm64"] = add_footer(64, arm64_genstub(syscall), syscall)
if "riscv64" in syscall:
syscall["asm-riscv64"] = add_footer(64, riscv64_genstub(syscall), syscall)
if "x86" in syscall:
if syscall["socketcall_id"] >= 0:
syscall["asm-x86"] = add_footer(32, x86_genstub_socketcall(syscall), syscall)