From daf8d057cebf4b304c11b10cd6e6c98e19710630 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Tue, 25 Jan 2022 19:21:31 +0100 Subject: [PATCH] seccomp: Introduce mechanism to allow per-arch syscalls Some C library functions are commonly implemented by different syscalls on different architectures. Add a mechanism to allow selected syscalls for a single architecture, syntax in #syscalls comment is: #syscalls : e.g. s390x:socketcall, given that socketcall() is commonly used there instead of socket(). This is now implemented by a compiler probe for syscall numbers, auditd tools (ausyscall) are not required anymore as a result. Signed-off-by: Stefano Brivio --- seccomp.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/seccomp.sh b/seccomp.sh index c710ce4..f5ee98e 100755 --- a/seccomp.sh +++ b/seccomp.sh @@ -63,6 +63,7 @@ sub() { sed -i "${__line_no}s#.*#${__template}#" "${TMP}" + IFS=' ' for __def in ${@}; do __key="@${__def%%:*}@" __value="${__def#*:}" @@ -79,6 +80,7 @@ finish() { __out="$(eval printf '%s' "\${${1}}")" shift + IFS=' ' for __def in ${@}; do __key="@${__def%%:*}@" __value="${__def#*:}" @@ -101,15 +103,54 @@ log2() { echo ${__x} } -# cc_syscall_nr - Try to get syscall number from compiler +# syscall_nr - Get syscall number from compiler # $1: Name of syscall -cc_syscall_nr() { - __in="$(printf "#include \n__NR_%s" ${1})" +syscall_nr() { + __in="$(printf "#include \n#include \n__NR_%s" ${1})" __out="$(echo "${__in}" | cc -E -xc - -o - | tail -1)" [ "${__out}" = "__NR_$1" ] && return 1 echo "${__out}" } +filter() { + __filtered= + for __c in ${@}; do + __arch_match=0 + case ${__c} in + *:*) + case ${__c} in + $(uname -m):*) + __arch_match=1 + __c=${__c##*:} + ;; + esac + ;; + *) + __arch_match=1 + ;; + esac + [ ${__arch_match} -eq 0 ] && continue + + IFS='| ' + __found=0 + for __name in ${__c}; do + syscall_nr "${__name}" >/dev/null && __found=1 && break + done + unset IFS + + if [ ${__found} -eq 0 ]; then + echo + echo "Warning: no syscall number for ${__c}" >&2 + echo " none of these syscalls will be allowed" >&2 + continue + fi + + __filtered="${__filtered} ${__name}" + done + + echo "${__filtered}" | tr ' ' '\n' | sort -u +} + # gen_profile() - Build struct sock_filter for a single profile # $1: Profile name # $@: Names of allowed system calls, amount padded to next power of two @@ -127,9 +168,7 @@ gen_profile() { done for __i in $(seq 1 ${__statements_calls} ); do __syscall_name="$(eval echo \${${__i}})" - if { ! command -V ausyscall >/dev/null 2>&1 || \ - ! ausyscall "${__syscall_name}" --exact >> "${TMP}"; } && \ - ! cc_syscall_nr "${__syscall_name}" >> "${TMP}"; then + if ! syscall_nr ${__syscall_name} >> "${TMP}"; then echo "Cannot get syscall number for ${__syscall_name}" exit 1 fi @@ -191,8 +230,8 @@ gen_profile() { printf '%s\n' "${HEADER}" > "${OUT}" __profiles="$(sed -n 's/[\t ]*\*[\t ]*#syscalls:\([^ ]*\).*/\1/p' *.[ch] | sort -u)" for __p in ${__profiles}; do - __calls="$(sed -n 's/[\t ]*\*[\t ]*#syscalls\(:'"${__p}"'\|\)[\t ]\{1,\}\(.*\)/\2/p' *.[ch] | tr ' ' '\n' | sort -u)" - + __calls="$(sed -n 's/[\t ]*\*[\t ]*#syscalls\(:'"${__p}"'\|\)[\t ]\{1,\}\(.*\)/\2/p' *.[ch])" + __calls="$(filter ${__calls})" echo "seccomp profile ${__p} allows: ${__calls}" | tr '\n' ' ' | fmt -t # Pad here to keep gen_profile() "simple" @@ -200,7 +239,7 @@ for __p in ${__profiles}; do for __c in ${__calls}; do __count=$(( __count + 1 )); done __padded=$(( 1 << (( $(log2 ${__count}) + 1 )) )) for __i in $( seq ${__count} $(( __padded - 1 )) ); do - __calls="${__calls} tuxcall" + __calls="${__calls} read" done gen_profile "${__p}" ${__calls}