diff options
Diffstat (limited to 'src/arch-syscall-validate')
-rwxr-xr-x | src/arch-syscall-validate | 867 |
1 files changed, 867 insertions, 0 deletions
diff --git a/src/arch-syscall-validate b/src/arch-syscall-validate new file mode 100755 index 0000000..3b69e9b --- /dev/null +++ b/src/arch-syscall-validate @@ -0,0 +1,867 @@ +#!/bin/bash + +# +# libseccomp syscall validation script +# +# Copyright (c) 2014 Red Hat <pmoore@redhat.com> +# Copyright (c) 2020 Cisco Systems, Inc. <pmoore2@cisco.com> +# +# Author: Paul Moore <paul@paul-moore.com> +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see <http://www.gnu.org/licenses>. +# + +LIB_SYS_DUMP="./arch-syscall-dump" + +#### +# functions + +# +# Dependency check +# +# Arguments: +# 1 Dependency to check for +# +function check_deps() { + [[ -z "$1" ]] && return + which "$1" >& /dev/null + return $? +} + +# +# Dependency verification +# +# Arguments: +# 1 Dependency to check for +# +function verify_deps() { + [[ -z "$1" ]] && return + if ! check_deps "$1"; then + echo "error: install \"$1\" and include it in your \$PATH" + exit 1 + fi +} + +# +# Print out script usage details +# +function usage() { +cat << EOF +usage: arch-syscall-validate [-h] [-c] [-a <arch>] <kernel_directory> + +libseccomp syscall validation script +optional arguments: + -h show this help message and exit + -a architecture + -l output the library's syscall definitions + -s output the kernel's syscall definitions + -c generate a CSV of the kernel's syscall definitions +EOF +} + +# +# Dump the kernel version +# +# Arguments: +# 1 path to the kernel source +# +# Dump the kernel's version information to stdout. +# +function kernel_version() { + local maj=$(cat $1/Makefile | \ + grep "^VERSION =" | awk -F "= " '{ print $2 }') + local min=$(cat $1/Makefile | \ + grep "^PATCHLEVEL =" | awk -F "= " '{ print $2 }') + local sub=$(cat $1/Makefile | \ + grep "^SUBLEVEL =" | awk -F "= " '{ print $2 }') + local xtr=$(cat $1/Makefile | \ + grep "^EXTRAVERSION =" | awk -F "= " '{ print $2 }') + echo "${maj}.${min}.${sub}${xtr}" +} + +# +# Dump the library syscall table for a given architecture +# +# Arguments: +# 1 architecture +# 2 offset (optional) +# +# +# Dump the library's syscall table to stdout. +# +function dump_lib_arch() { + local offset_str="" + + [[ -z $1 ]] && return + + [[ -n $2 ]] && offset_str="-o $2" + $LIB_SYS_DUMP -a $1 $offset_str | sed 's/\t/,/' | sort +} + +# +# Mangle the library pseudo syscall values +# +# Arguments: +# 1 architecture +# +# Mangle the supplied pseudo syscall to match the system values +# +function mangle_lib_syscall() { + local sed_filter="" + + sed_filter+='s/accept4,-118/accept4,364/;' + sed_filter+='s/bind,-102/bind,361/;' + sed_filter+='s/connect,-103/connect,362/;' + sed_filter+='s/getpeername,-107/getpeername,368/;' + sed_filter+='s/getsockname,-106/getsockname,367/;' + sed_filter+='s/getsockopt,-115/getsockopt,365/;' + sed_filter+='s/listen,-104/listen,363/;' + sed_filter+='s/msgctl,-214/msgctl,402/;' + sed_filter+='s/msgget,-213/msgget,399/;' + sed_filter+='s/msgrcv,-212/msgrcv,401/;' + sed_filter+='s/msgsnd,-211/msgsnd,400/;' + sed_filter+='s/recvfrom,-112/recvfrom,371/;' + sed_filter+='s/recvmsg,-117/recvmsg,372/;' + sed_filter+='s/semctl,-203/semctl,394/;' + sed_filter+='s/semget,-202/semget,393/;' + sed_filter+='s/sendmsg,-116/sendmsg,370/;' + sed_filter+='s/sendto,-111/sendto,369/;' + sed_filter+='s/setsockopt,-114/setsockopt,366/;' + sed_filter+='s/shmat,-221/shmat,397/;' + sed_filter+='s/shmctl,-224/shmctl,396/;' + sed_filter+='s/shmdt,-222/shmdt,398/;' + sed_filter+='s/shmget,-223/shmget,395/;' + sed_filter+='s/shutdown,-113/shutdown,373/;' + sed_filter+='s/socket,-101/socket,359/;' + sed_filter+='s/socketpair,-108/socketpair,360/;' + + case $1 in + s390|s390x) + sed_filter+='s/recvmmsg,-119/recvmmsg,357/;' + sed_filter+='s/sendmmsg,-120/sendmmsg,358/;' + ;; + *) + sed_filter+='s/recvmmsg,-119/recvmmsg,337/;' + sed_filter+='s/sendmmsg,-120/sendmmsg,345/;' + ;; + esac + + sed $sed_filter | sed '/,-[0-9]\+$/d' +} + +# +# Dump the x86 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_x86() { + cat $1/arch/x86/entry/syscalls/syscall_32.tbl | \ + grep -v "^#" | awk '{ print $3","$1 }' | \ + sort +} + +# +# Dump the x86 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_x86() { + dump_lib_arch x86 | mangle_lib_syscall x86 +} + +# +# Dump the x86_64 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_x86_64() { + cat $1/arch/x86/entry/syscalls/syscall_64.tbl | \ + grep -v "^#" | sed '/^$/d' | awk '{ print $2,$3,$1 }' | \ + sed '/^x32/d' | awk '{ print $2","$3 }' | sort +} + +# +# Dump the x86_64 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_x86_64() { + dump_lib_arch x86_64 | mangle_lib_syscall x86_64 +} + +# +# Dump the x32 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_x32() { + cat $1/arch/x86/entry/syscalls/syscall_64.tbl | \ + grep -v "^#" | sed '/^$/d' | awk '{ print $2,$3,$1 }' | \ + sed '/^64/d' | awk '{ print $2","$3 }' | sort +} + +# +# Dump the x32 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_x32() { + dump_lib_arch x32 | mangle_lib_syscall x32 +} + +# +# Dump the arm system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_arm() { + cat $1/arch/arm/tools/syscall.tbl | grep -v "^#" | \ + sed -n "/[0-9]\+[ \t]\+\(common\|eabi\)/p" | \ + awk '{ print $3","$1 }' | sort | (cat -; \ + (cat $1/arch/arm/include/uapi/asm/unistd.h | \ + grep "^#define __ARM_NR_" | \ + grep -v "^#define __ARM_NR_BASE" | \ + sed 's/#define __ARM_NR_\([a-z0-9_]*\)[ \t]\+(__ARM_NR_BASE+\(.*\))/\1 983040 + \2/' | \ + awk '{ print $1","$2+$4 }')) | sort +} + +# +# Dump the arm library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_arm() { + # NOTE: arm_sync_file_range() and sync_file_range2() share values + dump_lib_arch arm | sed '/sync_file_range2,\+341/d' | \ + mangle_lib_syscall arm +} + +# +# Dump the aarch64 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_aarch64() { + local sed_filter="" + + sed_filter+='s/__NR3264_statfs/43/;' + sed_filter+='s/__NR3264_ftruncate/46/;' + sed_filter+='s/__NR3264_truncate/45/;' + sed_filter+='s/__NR3264_lseek/62/;' + sed_filter+='s/__NR3264_sendfile/71/;' + sed_filter+='s/__NR3264_fstatat/79/;' + sed_filter+='s/__NR3264_fstatfs/44/;' + sed_filter+='s/__NR3264_fcntl/25/;' + sed_filter+='s/__NR3264_fadvise64/223/;' + sed_filter+='s/__NR3264_mmap/222/;' + sed_filter+='s/__NR3264_fstat/80/;' + sed_filter+='s/__NR3264_lstat/1039/;' + sed_filter+='s/__NR3264_stat/1038/;' + + gcc -E -dM -I$1/include/uapi \ + -D__BITS_PER_LONG=64 -D__ARCH_WANT_RENAMEAT \ + -D__ARCH_WANT_NEW_STAT \ + $1/arch/arm64/include/uapi/asm/unistd.h | \ + grep "^#define __NR_" | \ + sed '/__NR_syscalls/d' | \ + sed '/__NR_arch_specific_syscall/d' | \ + sed 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+\(.*\)/\1,\2/' | \ + sed $sed_filter | sort +} + +# +# Dump the aarch64 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_aarch64() { + dump_lib_arch aarch64 | mangle_lib_syscall aarch64 +} + +# +# Dump the mips system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_mips() { + cat $1/arch/mips/kernel/syscalls/syscall_o32.tbl | \ + grep -v "^#" | \ + sed -e '/[ \t]\+reserved[0-9]\+[ \t]\+/d;' | \ + sed -e '/[ \t]\+unused[0-9]\+[ \t]\+/d;' | \ + awk '{ print $3","$1 }' | sort +} + +# +# Dump the mips library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_mips() { + dump_lib_arch mips | mangle_lib_syscall mips +} + +# +# Dump the mips64 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_mips64() { + cat $1/arch/mips/kernel/syscalls/syscall_n64.tbl | \ + grep -v "^#" | \ + sed -e '/[ \t]\+reserved[0-9]\+[ \t]\+/d;' | \ + sed -e '/[ \t]\+unused[0-9]\+[ \t]\+/d;' | \ + awk '{ print $3","$1 }' | sort +} + +# +# Dump the mips64 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_mips64() { + dump_lib_arch mips64 | mangle_lib_syscall mips64 +} + +# +# Dump the mips64n32 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_mips64n32() { + cat $1/arch/mips/kernel/syscalls/syscall_n32.tbl | \ + grep -v "^#" | \ + sed -e '/[ \t]\+reserved[0-9]\+[ \t]\+/d;' | \ + sed -e '/[ \t]\+unused[0-9]\+[ \t]\+/d;' | \ + awk '{ print $3","$1 }' | sort +} + +# +# Dump the mips64n32 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_mips64n32() { + dump_lib_arch mips64n32 | mangle_lib_syscall mips64n32 +} + +# +# Dump the parisc system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_parisc() { + cat $1/arch/parisc/kernel/syscalls/syscall.tbl | \ + grep -v "^#" | \ + sed -n "/[0-9]\+[ \t]\+\(common\|32\)/p" | \ + awk '{ print $3","$1 }' | \ + sort +} + +# +# Dump the parisc library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_parisc() { + dump_lib_arch parisc | mangle_lib_syscall parisc +} + +# +# Dump the parisc64 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_parisc64() { + cat $1/arch/parisc/kernel/syscalls/syscall.tbl | \ + grep -v "^#" | \ + sed -n "/[0-9]\+[ \t]\+\(common\|64\)/p" | \ + awk '{ print $3","$1 }' | \ + sort +} + +# +# Dump the parisc64 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_parisc64() { + dump_lib_arch parisc64 | mangle_lib_syscall parisc64 +} + +# +# Dump the ppc system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_ppc() { + cat $1/arch/powerpc/kernel/syscalls/syscall.tbl | grep -v "^#" | \ + sed -ne "/[0-9]\+[ \t]\+\(common\|nospu\|32\)/p" | \ + awk '{ print $3","$1 }' | sort +} + +# +# Dump the ppc library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_ppc() { + dump_lib_arch ppc | mangle_lib_syscall ppc +} + +# +# Dump the ppc64 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_ppc64() { + cat $1/arch/powerpc/kernel/syscalls/syscall.tbl | grep -v "^#" | \ + sed -ne "/[0-9]\+[ \t]\+\(common\|nospu\|64\)/p" | \ + awk '{ print $3","$1 }' | sort +} + +# +# Dump the ppc64 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_ppc64() { + dump_lib_arch ppc64 | mangle_lib_syscall ppc64 +} + +# +# Dump the riscv64 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_riscv64() { + local sed_filter="" + + sed_filter+='s/__NR3264_fadvise64/223/;' + sed_filter+='s/__NR3264_fcntl/25/;' + sed_filter+='s/__NR3264_fstatat/79/;' + sed_filter+='s/__NR3264_fstatfs/44/;' + sed_filter+='s/__NR3264_ftruncate/46/;' + sed_filter+='s/__NR3264_lseek/62/;' + sed_filter+='s/__NR3264_mmap/222/;' + sed_filter+='s/__NR3264_sendfile/71/;' + sed_filter+='s/__NR3264_statfs/43/;' + sed_filter+='s/__NR3264_truncate/45/;' + sed_filter+='s/__NR3264_fstat/80/;' + + gcc -E -dM -I$1/include/uapi \ + -D__BITS_PER_LONG=64 -D__ARCH_WANT_NEW_STAT \ + $1/arch/riscv/include/uapi/asm/unistd.h | \ + grep "^#define __NR_" | \ + sed '/__NR_syscalls/d' | \ + sed 's/(__NR_arch_specific_syscall + 15)/259/' | \ + sed '/__NR_arch_specific_syscall/d' | \ + sed 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+\(.*\)/\1,\2/' | \ + sed $sed_filter | sort +} + +# +# Dump the riscv64 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_riscv64() { + dump_lib_arch riscv64 | mangle_lib_syscall riscv64 +} + +# +# Dump the s390 system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_s390() { + cat $1/arch/s390/kernel/syscalls/syscall.tbl | grep -v "^#" | \ + sed -ne "/[0-9]\+[ \t]\+\(common\|32\)/p" | \ + awk '{ print $3","$1 }' | \ + sort +} + +# +# Dump the s390 library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_s390() { + dump_lib_arch s390 | mangle_lib_syscall s390 +} + +# +# Dump the s390x system syscall table +# +# Arguments: +# 1 path to the kernel source +# +# Dump the architecture's syscall table to stdout. +# +function dump_sys_s390x() { + cat $1/arch/s390/kernel/syscalls/syscall.tbl | grep -v "^#" | \ + sed -ne "/[0-9]\+[ \t]\+\(common\|64\)/p" | \ + awk '{ print $3","$1 }' | \ + sort +} + +# +# Dump the s390x library syscall table +# +# Dump the library's syscall table to stdout. +# +function dump_lib_s390x() { + dump_lib_arch s390x | mangle_lib_syscall s390x +} + +# +# Dump the system syscall table +# +# Arguments: +# 1 architecture +# 2 path to the kernel source +# +# Dump the system's syscall table to stdout using the given architecture. +# +function dump_sys() { + case $1 in + x86) + dump_sys_x86 "$2" + ;; + x86_64) + dump_sys_x86_64 "$2" + ;; + x32) + dump_sys_x32 "$2" + ;; + arm) + dump_sys_arm "$2" + ;; + aarch64) + dump_sys_aarch64 "$2" + ;; + mips) + dump_sys_mips "$2" + ;; + mips64) + dump_sys_mips64 "$2" + ;; + mips64n32) + dump_sys_mips64n32 "$2" + ;; + parisc) + dump_sys_parisc "$2" + ;; + parisc64) + dump_sys_parisc64 "$2" + ;; + ppc) + dump_sys_ppc "$2" + ;; + ppc64) + dump_sys_ppc64 "$2" + ;; + riscv64) + dump_sys_riscv64 "$2" + ;; + s390) + dump_sys_s390 "$2" + ;; + s390x) + dump_sys_s390x "$2" + ;; + *) + echo "" + return 1 + ;; + esac + + return 0 +} + +# +# Dump the library syscall table +# +# Arguments: +# 1 architecture +# +# Dump the library's syscall table to stdout using the given architecture. +# +function dump_lib() { + case $1 in + x86) + dump_lib_x86 + ;; + x86_64) + dump_lib_x86_64 + ;; + x32) + dump_lib_x32 + ;; + arm) + dump_lib_arm + ;; + aarch64) + dump_lib_aarch64 + ;; + mips) + dump_lib_mips + ;; + mips64) + dump_lib_mips64 + ;; + mips64n32) + dump_lib_mips64n32 + ;; + parisc) + dump_lib_parisc + ;; + parisc64) + dump_lib_parisc64 + ;; + ppc) + dump_lib_ppc + ;; + ppc64) + dump_lib_ppc64 + ;; + riscv64) + dump_lib_riscv64 + ;; + s390) + dump_lib_s390 + ;; + s390x) + dump_lib_s390x + ;; + *) + echo "" + return 1 + ;; + esac + + return 0 +} + +# +# Generate the syscall csv file +# +# Arguments: +# 1 path to the kernel source +# 2 "sys" or "lib" depending on the syscall list to use +# +# Generare a syscall csv file from the given kernel sources. +# +function gen_csv() { + + # sanity checks + [[ -z $1 ]] && return + [[ $2 != "sys" && $2 != "lib" ]] && return + + # abi list + # NOTE: the ordering here is dependent on the layout of the + # arch_syscall_table struct in syscalls.h - BEWARE! + abi_list="" + abi_list+=" x86 x86_64 x32" + abi_list+=" arm aarch64" + abi_list+=" mips mips64 mips64n32" + abi_list+=" parisc parisc64" + abi_list+=" ppc ppc64" + abi_list+=" riscv64" + abi_list+=" s390 s390x" + + # get the full syscall list + for abi in $abi_list; do + eval output_$abi=$(mktemp -t syscall_validate_XXXXXX) + dump_$2_$abi "$1" > $(eval echo $`eval echo output_$abi`) + done + sc_list=$((for abi in $abi_list; do + cat $(eval echo $`eval echo output_$abi`); + done) | awk -F "," '{ print $1 }' | sort -u) + + # output a simple header + printf "#syscall (v%s %s)" \ + "$(kernel_version "$1")" "$(TZ=UTC date "+%Y-%m-%d")" + for abi in $abi_list; do + printf ",%s" $abi + done + printf "\n" + + # output the syscall csv details + for sc in $sc_list; do + printf "%s" $sc + for abi in $abi_list; do + num=$(grep "^$sc," \ + $(eval echo $`eval echo output_$abi`) | \ + awk -F "," '{ print $2 }' ) + [[ -z $num ]] && num="PNR" + printf ",%s" $num + done + printf "\n" + done + + # cleanup + for abi in $abi_list; do + rm -f $(eval echo $`eval echo output_$abi`) + done +} + +#### +# main + +verify_deps diff +verify_deps gcc +verify_deps grep +verify_deps mktemp +verify_deps sed +if [[ ! -x $LIB_SYS_DUMP ]]; then + echo "error: \"$LIB_SYS_DUMP\" is not in the current working directory" + exit 1 +fi + +opt_arches="" +opt_csv=0 +opt_sys=0 +opt_lib=0 + +while getopts "a:cslh" opt; do + case $opt in + a) + opt_arches+="$OPTARG " + ;; + c) + opt_csv=1 + ;; + s) + opt_sys=1 + opt_lib=0 + ;; + l) + opt_sys=0 + opt_lib=1 + ;; + h|*) + usage + exit 1 + ;; + esac +done +shift $(($OPTIND - 1)) + +# defaults +if [[ $opt_arches == "" ]]; then + opt_arches=" \ + x86 x86_64 x32 \ + arm aarch64 \ + mips mips64 mips64n32 \ + parisc parisc64 \ + ppc ppc64 \ + s390 s390x" +fi + +# sanity checks +kernel_dir="$1" +if [[ -z $kernel_dir ]]; then + usage + exit 1 +fi +if [[ ! -d $kernel_dir ]]; then + echo "error: \"$1\" is not a valid directory" + exit 1 +fi + +# generate some temp files +tmp_lib=$(mktemp -t syscall_validate_XXXXXX) +tmp_sys=$(mktemp -t syscall_validate_XXXXXX) + +if [[ $opt_csv -eq 1 ]]; then + # generate the syscall csv file + if [[ $opt_lib -eq 1 ]]; then + gen_csv $kernel_dir "lib" + else + gen_csv $kernel_dir "sys" + fi +else + # loop through the architectures and compare + for i in $opt_arches; do + # dump the syscall tables + dump_lib $i > $tmp_lib + if [[ $? -ne 0 ]]; then + echo "error: unknown arch $i" + exit 1 + fi + dump_sys $i "$kernel_dir" > $tmp_sys + if [[ $? -ne 0 ]]; then + echo "error: unknown arch $i" + exit 1 + fi + + if [[ $opt_lib -eq 1 ]]; then + cat $tmp_lib + elif [[ $opt_sys -eq 1 ]]; then + cat $tmp_sys + else + # compare the lib and sys output + diff -u --label="$i [library]" $tmp_lib \ + --label "$i [system]" $tmp_sys + fi + done +fi + +# cleanup and exit +rm -f $tmp_lib $tmp_sys + +exit 0 |