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 <arch>:<name> 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 <sbrivio@redhat.com>
This commit is contained in:
parent
1eb14d7305
commit
daf8d057ce
1 changed files with 48 additions and 9 deletions
57
seccomp.sh
57
seccomp.sh
|
@ -63,6 +63,7 @@ sub() {
|
||||||
|
|
||||||
sed -i "${__line_no}s#.*#${__template}#" "${TMP}"
|
sed -i "${__line_no}s#.*#${__template}#" "${TMP}"
|
||||||
|
|
||||||
|
IFS=' '
|
||||||
for __def in ${@}; do
|
for __def in ${@}; do
|
||||||
__key="@${__def%%:*}@"
|
__key="@${__def%%:*}@"
|
||||||
__value="${__def#*:}"
|
__value="${__def#*:}"
|
||||||
|
@ -79,6 +80,7 @@ finish() {
|
||||||
__out="$(eval printf '%s' "\${${1}}")"
|
__out="$(eval printf '%s' "\${${1}}")"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
|
IFS=' '
|
||||||
for __def in ${@}; do
|
for __def in ${@}; do
|
||||||
__key="@${__def%%:*}@"
|
__key="@${__def%%:*}@"
|
||||||
__value="${__def#*:}"
|
__value="${__def#*:}"
|
||||||
|
@ -101,15 +103,54 @@ log2() {
|
||||||
echo ${__x}
|
echo ${__x}
|
||||||
}
|
}
|
||||||
|
|
||||||
# cc_syscall_nr - Try to get syscall number from compiler
|
# syscall_nr - Get syscall number from compiler
|
||||||
# $1: Name of syscall
|
# $1: Name of syscall
|
||||||
cc_syscall_nr() {
|
syscall_nr() {
|
||||||
__in="$(printf "#include <sys/syscall.h>\n__NR_%s" ${1})"
|
__in="$(printf "#include <asm-generic/unistd.h>\n#include <sys/syscall.h>\n__NR_%s" ${1})"
|
||||||
__out="$(echo "${__in}" | cc -E -xc - -o - | tail -1)"
|
__out="$(echo "${__in}" | cc -E -xc - -o - | tail -1)"
|
||||||
[ "${__out}" = "__NR_$1" ] && return 1
|
[ "${__out}" = "__NR_$1" ] && return 1
|
||||||
echo "${__out}"
|
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
|
# gen_profile() - Build struct sock_filter for a single profile
|
||||||
# $1: Profile name
|
# $1: Profile name
|
||||||
# $@: Names of allowed system calls, amount padded to next power of two
|
# $@: Names of allowed system calls, amount padded to next power of two
|
||||||
|
@ -127,9 +168,7 @@ gen_profile() {
|
||||||
done
|
done
|
||||||
for __i in $(seq 1 ${__statements_calls} ); do
|
for __i in $(seq 1 ${__statements_calls} ); do
|
||||||
__syscall_name="$(eval echo \${${__i}})"
|
__syscall_name="$(eval echo \${${__i}})"
|
||||||
if { ! command -V ausyscall >/dev/null 2>&1 || \
|
if ! syscall_nr ${__syscall_name} >> "${TMP}"; then
|
||||||
! ausyscall "${__syscall_name}" --exact >> "${TMP}"; } && \
|
|
||||||
! cc_syscall_nr "${__syscall_name}" >> "${TMP}"; then
|
|
||||||
echo "Cannot get syscall number for ${__syscall_name}"
|
echo "Cannot get syscall number for ${__syscall_name}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -191,8 +230,8 @@ gen_profile() {
|
||||||
printf '%s\n' "${HEADER}" > "${OUT}"
|
printf '%s\n' "${HEADER}" > "${OUT}"
|
||||||
__profiles="$(sed -n 's/[\t ]*\*[\t ]*#syscalls:\([^ ]*\).*/\1/p' *.[ch] | sort -u)"
|
__profiles="$(sed -n 's/[\t ]*\*[\t ]*#syscalls:\([^ ]*\).*/\1/p' *.[ch] | sort -u)"
|
||||||
for __p in ${__profiles}; do
|
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
|
echo "seccomp profile ${__p} allows: ${__calls}" | tr '\n' ' ' | fmt -t
|
||||||
|
|
||||||
# Pad here to keep gen_profile() "simple"
|
# 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
|
for __c in ${__calls}; do __count=$(( __count + 1 )); done
|
||||||
__padded=$(( 1 << (( $(log2 ${__count}) + 1 )) ))
|
__padded=$(( 1 << (( $(log2 ${__count}) + 1 )) ))
|
||||||
for __i in $( seq ${__count} $(( __padded - 1 )) ); do
|
for __i in $( seq ${__count} $(( __padded - 1 )) ); do
|
||||||
__calls="${__calls} tuxcall"
|
__calls="${__calls} read"
|
||||||
done
|
done
|
||||||
|
|
||||||
gen_profile "${__p}" ${__calls}
|
gen_profile "${__p}" ${__calls}
|
||||||
|
|
Loading…
Reference in a new issue