Created
March 20, 2020 03:46
-
-
Save pcmoore/c33e64237798f05b3ecafca19c5221e5 to your computer and use it in GitHub Desktop.
arch: rework/fix the arch-syscall-validate script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| arch: rework/fix the arch-syscall-validate script | |
| From: Paul Moore <paul@paul-moore.com> | |
| Update the arch-syscall-validate script to be "CSV friendly" in | |
| preparation for follow-up work to move the libseccomp internal | |
| syscall tables into a single CVS file. This is a rather crude | |
| effort, but it works and should serve to get things moving; we can | |
| optimize it later. | |
| In this process of making this change, a few unrelated problems with | |
| the script were identified and fixed. | |
| Signed-off-by: Paul Moore <paul@paul-moore.com> | |
| --- | |
| src/arch-syscall-validate | 222 ++++++++++++++++++++++++++++++--------------- | |
| 1 file changed, 147 insertions(+), 75 deletions(-) | |
| diff --git a/src/arch-syscall-validate b/src/arch-syscall-validate | |
| index a699c6a..1a508bf 100755 | |
| --- a/src/arch-syscall-validate | |
| +++ b/src/arch-syscall-validate | |
| @@ -4,6 +4,8 @@ | |
| # 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> | |
| # | |
| @@ -57,17 +59,34 @@ function verify_deps() { | |
| # | |
| function usage() { | |
| cat << EOF | |
| -usage: arch-syscall-validate [-h] [-a <arch>] <kernel_directory> | |
| +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 system'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 | |
| # | |
| @@ -84,7 +103,9 @@ function dump_lib_arch() { | |
| [[ -z $1 ]] && return | |
| [[ -n $2 ]] && offset_str="-o $2" | |
| - $LIB_SYS_DUMP -a $1 $offset_str | sed -e '/[^\t]\+\t-[0-9]\+/d' | sort | |
| + $LIB_SYS_DUMP -a $1 $offset_str | \ | |
| + sed -e 's/\t/,/' | sed -e '/ -[0-9]\+$/d' | \ | |
| + sort | |
| } | |
| # | |
| @@ -97,11 +118,7 @@ function dump_lib_arch() { | |
| # | |
| function dump_sys_x86() { | |
| cat $1/arch/x86/entry/syscalls/syscall_32.tbl | \ | |
| - grep -v "^#" | awk '{ print $3"\t"$1 }' | sed '/^[ \t]*$/d' | \ | |
| - grep -P -v '^accept4\t|^^bind\t|^connect\t|^getpeername\t|^getsockname\t|^getsockopt\t|^listen\t' | \ | |
| - grep -P -v '^recvfrom\t|^recvmmsg\t|^sendmmsg\t|^sendmsg\t|^sendto\t|^setsockopt\t|^shmat\t|^shmctl\t' | \ | |
| - grep -P -v '^shmdt\t|^shmget\t|^shutdown\t|^socket\t|^socketpair\t' | \ | |
| - grep -P -v '^msgctl\t|^msgget\t|^msgrcv\t|^msgsnd\t|^semctl\t|^semget\t' | \ | |
| + grep -v "^#" | awk '{ print $3","$1 }' | \ | |
| sort | |
| } | |
| @@ -124,8 +141,10 @@ function dump_lib_x86() { | |
| # | |
| function dump_sys_x86_64() { | |
| cat $1/arch/x86/entry/syscalls/syscall_64.tbl | \ | |
| - grep -v "^#" | awk '{ print $2,$3,$1 }' | sed -e '/^x32/d' | \ | |
| - awk '{ print $2"\t"$3 }' | sed '/^[ \t]*$/d' | sort | |
| + grep -v "^#" | sed '/^$/d' | awk '{ print $2,$3,$1 }' | \ | |
| + sed -e '/^x32/d' | \ | |
| + awk '{ print $2","$3 }' | \ | |
| + sort | |
| } | |
| # | |
| @@ -147,8 +166,9 @@ function dump_lib_x86_64() { | |
| # | |
| function dump_sys_x32() { | |
| cat $1/arch/x86/entry/syscalls/syscall_64.tbl | \ | |
| - grep -v "^#" | awk '{ print $2,$3,$1 }' | sed -e '/^64/d' | \ | |
| - awk '{ print $2"\t"$3 }' | sed '/^[ \t]*$/d' | sort | |
| + grep -v "^#" | sed '/^$/d' | awk '{ print $2,$3,$1 }' | \ | |
| + sed -e '/^64/d' | awk '{ print $2","$3 }' | \ | |
| + sort | |
| } | |
| # | |
| @@ -172,11 +192,11 @@ function dump_lib_x32() { | |
| function dump_sys_arm() { | |
| cat $1/arch/arm/tools/syscall.tbl | grep -v "^#" | \ | |
| sed -ne "/[0-9]\+[ \t]\+\(common\|eabi\)/p" | \ | |
| - awk '{ print $3"\t"$1 }' | sort | (cat -; \ | |
| + 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 -e 's/#define __ARM_NR_\([a-z0-9_]*\)[ \t]\+(__ARM_NR_BASE+\(.*\))/\1 983040 + \2/' | \ | |
| - awk '{ print $1"\t"$2+$4 }')) | sort | |
| + awk '{ print $1","$2+$4 }')) | sort | |
| } | |
| # | |
| @@ -186,7 +206,7 @@ function dump_sys_arm() { | |
| # | |
| function dump_lib_arm() { | |
| # NOTE: arm_sync_file_range() and sync_file_range2() share values | |
| - dump_lib_arch arm | sed -e '/sync_file_range2[ \t]\+341/d' | |
| + dump_lib_arch arm | sed -e '/sync_file_range2,\+341/d' | |
| } | |
| # | |
| @@ -205,7 +225,7 @@ function dump_sys_aarch64() { | |
| grep "^#define __NR_" | \ | |
| sed -e '/__NR_syscalls/d' | \ | |
| sed -e '/__NR_arch_specific_syscall/d' | \ | |
| - sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+\(.*\)/\1\t\2/' | \ | |
| + sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+\(.*\)/\1,\2/' | \ | |
| sed -e 's/__NR3264_statfs/43/' | \ | |
| sed -e 's/__NR3264_ftruncate/46/' | \ | |
| sed -e 's/__NR3264_truncate/45/' | \ | |
| @@ -255,7 +275,7 @@ function dump_sys_mips() { | |
| grep -v "^#define __NR_Linux" | \ | |
| grep -v "^#define __NR_unused" | \ | |
| grep -v "^#define __NR_reserved" | \ | |
| - sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+(__NR_Linux[ \t]*+[ \t]*\([0-9]\+\)).*/\1\t\2/' | \ | |
| + sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+(__NR_Linux[ \t]*+[ \t]*\([0-9]\+\)).*/\1,\2/' | \ | |
| sort | |
| } | |
| @@ -292,7 +312,7 @@ function dump_sys_mips64() { | |
| grep -v "^#define __NR_Linux" | \ | |
| grep -v "^#define __NR_unused" | \ | |
| grep -v "^#define __NR_reserved" | \ | |
| - sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+(__NR_Linux[ \t]*+[ \t]*\([0-9]\+\)).*/\1\t\2/' | \ | |
| + sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+(__NR_Linux[ \t]*+[ \t]*\([0-9]\+\)).*/\1,\2/' | \ | |
| sort | |
| } | |
| @@ -329,7 +349,7 @@ function dump_sys_mips64n32() { | |
| grep -v "^#define __NR_Linux" | \ | |
| grep -v "^#define __NR_unused" | \ | |
| grep -v "^#define __NR_reserved" | \ | |
| - sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+(__NR_Linux[ \t]*+[ \t]*\([0-9]\+\)).*/\1\t\2/' | \ | |
| + sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+(__NR_Linux[ \t]*+[ \t]*\([0-9]\+\)).*/\1,\2/' | \ | |
| sort | |
| } | |
| @@ -353,11 +373,11 @@ function dump_lib_mips64n32() { | |
| 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"\t"$1 }' | sort | (cat -; \ | |
| + awk '{ print $3","$1 }' | sort | (cat -; \ | |
| (cat $1/arch/powerpc/include/uapi/asm/unistd.h | \ | |
| grep "^#define __PPC_NR_" | grep -v "^#define __PPC_NR_BASE" | \ | |
| sed -e 's/#define _PPC_NR_\([a-z0-9_]*\)[ \t]\+(__PPC_NR_BASE+\(.*\))/\1 983040 + \2/' | \ | |
| - awk '{ print $1"\t"$2+$4 }')) | sort | |
| + awk '{ print $1","$2+$4 }')) | sort | |
| } | |
| # | |
| @@ -380,11 +400,11 @@ function dump_lib_ppc() { | |
| 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"\t"$1 }' | sort | (cat -; \ | |
| + awk '{ print $3","$1 }' | sort | (cat -; \ | |
| (cat $1/arch/powerpc/include/uapi/asm/unistd.h | \ | |
| grep "^#define __PPC_NR_" | grep -v "^#define __PPC_NR_BASE" | \ | |
| sed -e 's/#define _PPC_NR_\([a-z0-9_]*\)[ \t]\+(__PPC_NR_BASE+\(.*\))/\1 983040 + \2/' | \ | |
| - awk '{ print $1"\t"$2+$4 }')) | sort | |
| + awk '{ print $1","$2+$4 }')) | sort | |
| } | |
| # | |
| @@ -407,11 +427,12 @@ function dump_lib_ppc64() { | |
| function dump_sys_riscv64() { | |
| gcc -E -dM -I$1/include/uapi \ | |
| -D__BITS_PER_LONG=64 -D__ARCH_WANT_NEW_STAT \ | |
| - $1/include/uapi/asm-generic/unistd.h | \ | |
| + $1/arch/riscv/include/uapi/asm/unistd.h | \ | |
| grep "^#define __NR_" | \ | |
| sed -e '/__NR_syscalls/d' | \ | |
| + sed -e 's/(__NR_arch_specific_syscall + 15)/259/' | \ | |
| sed -e '/__NR_arch_specific_syscall/d' | \ | |
| - sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+\(.*\)/\1\t\2/' | \ | |
| + sed -e 's/#define[ \t]\+__NR_\([^ \t]\+\)[ \t]\+\(.*\)/\1,\2/' | \ | |
| sed -e 's/__NR3264_fadvise64/223/' | \ | |
| sed -e 's/__NR3264_fcntl/25/' | \ | |
| sed -e 's/__NR3264_fstatat/79/' | \ | |
| @@ -446,15 +467,8 @@ function dump_lib_riscv64() { | |
| 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"\t"$1 }' | sort | (cat -; \ | |
| - (cat $1/arch/s390/include/uapi/asm/unistd.h | \ | |
| - grep "^#define __PPC_NR_" | grep -v "^#define __PPC_NR_BASE" | \ | |
| - sed -e 's/#define _PPC_NR_\([a-z0-9_]*\)[ \t]\+(__PPC_NR_BASE+\(.*\))/\1 983040 + \2/' | \ | |
| - awk '{ print $1"\t"$2+$4 }')) | \ | |
| - grep -P -v '^accept4\t|^^bind\t|^connect\t|^getpeername\t|^getsockname\t|^getsockopt\t|^listen\t' | \ | |
| - grep -P -v '^recvfrom\t|^recvmmsg\t|^sendmmsg\t|^sendmsg\t|^sendto\t|^setsockopt\t|^shmat\t|^shmctl\t' | \ | |
| - grep -P -v '^shmdt\t|^shmget\t|^shutdown\t|^socket\t|^socketpair\t' | \ | |
| - sort | |
| + awk '{ print $3","$1 }' | \ | |
| + sort | |
| } | |
| # | |
| @@ -477,15 +491,8 @@ function dump_lib_s390() { | |
| 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"\t"$1 }' | sort | (cat -; \ | |
| - (cat $1/arch/s390/include/uapi/asm/unistd.h | \ | |
| - grep "^#define __PPC_NR_" | grep -v "^#define __PPC_NR_BASE" | \ | |
| - sed -e 's/#define _PPC_NR_\([a-z0-9_]*\)[ \t]\+(__PPC_NR_BASE+\(.*\))/\1 983040 + \2/' | \ | |
| - awk '{ print $1"\t"$2+$4 }')) | \ | |
| - grep -P -v '^accept4\t|^^bind\t|^connect\t|^getpeername\t|^getsockname\t|^getsockopt\t|^listen\t' | \ | |
| - grep -P -v '^recvfrom\t|^recvmmsg\t|^sendmmsg\t|^sendmsg\t|^sendto\t|^setsockopt\t|^shmat\t|^shmctl\t' | \ | |
| - grep -P -v '^shmdt\t|^shmget\t|^shutdown\t|^socket\t|^socketpair\t' | \ | |
| - sort | |
| + awk '{ print $3","$1 }' | \ | |
| + sort | |
| } | |
| # | |
| @@ -614,6 +621,60 @@ function dump_lib() { | |
| return 0 | |
| } | |
| +# | |
| +# Generate the syscall csv file | |
| +# | |
| +# Arguments: | |
| +# 1 path to the kernel source | |
| +# | |
| +# Generare a syscall csv file from the given kernel sources. | |
| +# | |
| +function gen_csv() { | |
| + | |
| + # NOTE: we can do soooo much better than this, but this is a quick | |
| + # hack and it seems to work | |
| + | |
| + # abi list | |
| + abi_list="" | |
| + abi_list+=" x86 x86_64 x32" | |
| + abi_list+=" arm aarch64" | |
| + abi_list+=" mips mips64 mips64n32" | |
| + abi_list+=" ppc ppc64" | |
| + abi_list+=" riscv64" | |
| + abi_list+=" s390 s390x" | |
| + | |
| + # get the full syscall list | |
| + sc_list=$((dump_sys_x86 "$1"; dump_sys_x86_64 "$1"; dump_sys_x32 "$1"; \ | |
| + dump_sys_arm "$1"; dump_sys_aarch64 "$1"; \ | |
| + dump_sys_mips "$1"; dump_sys_mips64 "$1"; | |
| + dump_sys_mips64n32 "$1"; \ | |
| + dump_sys_ppc "$1"; dump_sys_ppc64 "$1"; \ | |
| + dump_sys_riscv64 "$1"; \ | |
| + dump_sys_s390 "$1"; dump_sys_s390x "$1") | \ | |
| + awk -F "," '{ print $1 }' | sort -u) | |
| + | |
| + # output a simple header | |
| + printf "# libseccomp syscall table\n" | |
| + printf "#\n" | |
| + printf "# kernel: %s (%s)\n" "$(kernel_version "$1")" "$(TZ=UTC date -R)" | |
| + printf "#\n" | |
| + printf "#syscall" | |
| + 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=$(dump_sys_$abi "$1" | grep "^$sc," | awk -F "," '{ print $2 }' ) | |
| + [[ -z $num ]] && num="PNR" | |
| + printf ",%s" $num | |
| + done | |
| + printf "\n" | |
| + done | |
| +} | |
| + | |
| #### | |
| # main | |
| @@ -628,14 +689,18 @@ if [[ ! -x $LIB_SYS_DUMP ]]; then | |
| fi | |
| opt_arches="" | |
| +opt_csv="" | |
| opt_sys="" | |
| opt_lib="" | |
| -while getopts "a:slh" opt; do | |
| +while getopts "a:cslh" opt; do | |
| case $opt in | |
| a) | |
| opt_arches+="$OPTARG " | |
| ;; | |
| + c) | |
| + opt_csv=1 | |
| + ;; | |
| s) | |
| opt_sys=1 | |
| opt_lib=0 | |
| @@ -664,43 +729,50 @@ 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 | |
| +if [[ $opt_csv -eq 1 || $opt_sys -eq 1 ]]; then | |
| + 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 | |
| fi | |
| # generate some temp files | |
| tmp_lib=$(mktemp -t syscall_validate_XXXXXX) | |
| tmp_sys=$(mktemp -t syscall_validate_XXXXXX) | |
| -# 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 | |
| +if [[ $opt_csv -eq 1 ]]; then | |
| + # generate the syscall csv file | |
| + gen_csv $kernel_dir | |
| +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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment