From: Michael Tremer Date: Mon, 5 Apr 2010 13:10:13 +0000 (+0200) Subject: QA: Update quality-agent. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=91c73b6e13e9501f2a13aeb037dd54df962605a7;p=ipfire-3.x.git QA: Update quality-agent. Added some new checks and replaced scanelf by readelf. --- diff --git a/tools/common-functions b/tools/common-functions index d887a5c08..e3c8928d0 100644 --- a/tools/common-functions +++ b/tools/common-functions @@ -4,6 +4,53 @@ LIBARY_PATHS="${BUILDROOT}/lib ${BUILDROOT}/usr/lib" BINARY_PATHS="${LIBARY_PATHS} ${BUILDROOT}/bin ${BUILDROOT}/sbin" BINARY_PATHS="${BINARY_PATHS} ${BUILDROOT}/usr/bin ${BUILDROOT}/usr/sbin" +has_canary() { + local file=${1} + + readelf -s ${file} | grep -q "__stack_chk_fail" +} + +has_execstack() { + local file=${1} + + readelf -h ${file} | grep -qE "Type:[[:space:]]*EXEC" +} + +has_interpreter() { + local file=${1} + + [ -n "$(get_interpreter ${file})" ] +} + +has_nx() { + local file=${1} + + readelf -l ${file} | grep "GNU_STACK" | grep -q "RWE" + [ $? != 0 ] +} + +is_relro_partly() { + local file=${1} + + readelf -l ${file} | grep -q "GNU_RELRO" +} + +is_relro_full() { + local file=${1} + + if is_relro_partly ${file}; then + readelf -d ${file} | grep -q "BIND_NOW" + return $? + fi + return 1 +} + +is_shared_object() { + local file=${1} + + file ${file} | grep -q "shared object" +} + get_interpreter() { local file=${1} @@ -18,6 +65,13 @@ get_needed() { tr -d "[]" | awk '{ print $NF }' } +get_rpath() { + local file=${1} + + readelf -d ${file} | grep RPATH | \ + tr -d "[]" | awk '{ print $NF }' +} + get_soname() { local file=${1} @@ -58,7 +112,7 @@ find_elf_files() { for dir in ${dirs}; do for file in $(find ${dir} -maxdepth 1 -type f 2>/dev/null); do - if file ${file} | grep -q ELF; then + if file ${file} | grep -q "ELF"; then files="${files} ${file}" fi done diff --git a/tools/quality-agent b/tools/quality-agent index 45e256049..57d06680f 100755 --- a/tools/quality-agent +++ b/tools/quality-agent @@ -2,10 +2,11 @@ DIR_QA=${0}.d +failed=0 for file in ${DIR_QA}/*; do [ -x "${file}" ] || continue - ${file} || exit $? + ${file} || failed=1 done -exit 0 +exit ${failed} diff --git a/tools/quality-agent.d/001-include-files b/tools/quality-agent.d/001-include-files index abf683cec..34257e690 100755 --- a/tools/quality-agent.d/001-include-files +++ b/tools/quality-agent.d/001-include-files @@ -2,11 +2,15 @@ . $(dirname ${0})/qa-include -# Fix include files -log "Fix include files" +DESC="Include files have to belong to the root user. \ + This script will fix this automatically." -if [ ! -d "${BUILDROOT}/usr/include" ]; then - exit 0 -fi +check() { + if [ ! -d "${BUILDROOT}/usr/include" ]; then + return 0 + fi + + chown -R root:root ${BUILDROOT}/usr/include +} -chown -R root:root ${BUILDROOT}/usr/include +run diff --git a/tools/quality-agent.d/001-remove-info-files b/tools/quality-agent.d/001-remove-info-files index 9b8db23d6..6e2ff0f29 100755 --- a/tools/quality-agent.d/001-remove-info-files +++ b/tools/quality-agent.d/001-remove-info-files @@ -3,10 +3,10 @@ . $(dirname ${0})/qa-include # Remove documentation files -log "Removing documentation files..." +log_debug "Removing documentation files..." for dir in ${BUILDROOT}/usr/{,share}/{doc,info}; do if [ -d "${dir}" ]; then - log " Removing: ${dir}" + log_debug " Removing: ${dir}" rm -rf ${dir} || exit $? fi done diff --git a/tools/quality-agent.d/001-remove-static-libs b/tools/quality-agent.d/001-remove-static-libs index 331a0f271..cbeabf21e 100755 --- a/tools/quality-agent.d/001-remove-static-libs +++ b/tools/quality-agent.d/001-remove-static-libs @@ -3,7 +3,7 @@ . $(dirname ${0})/qa-include # Remove unwanted files -log "Removing unwanted files: *.a *.la" +log_debug "Removing unwanted files: *.a *.la" for file in $(find ${BUILDROOT} -name "*.a" -or -name "*.la"); do # Don't remove libc_nonshared.a. It is used by gcc/ld. @@ -14,7 +14,7 @@ for file in $(find ${BUILDROOT} -name "*.a" -or -name "*.la"); do [ "${file##*/}" = "libfl_pic.a" ] && continue [ "${file##*/}" = "libpython2.6.a" ] && continue - log " Removing: ${file}" + log_debug " Removing: ${file}" rm -f ${file} || exit $? done diff --git a/tools/quality-agent.d/001-unsafe-files b/tools/quality-agent.d/001-unsafe-files index 34e948324..547a1b1ce 100755 --- a/tools/quality-agent.d/001-unsafe-files +++ b/tools/quality-agent.d/001-unsafe-files @@ -2,24 +2,24 @@ . $(dirname ${0})/qa-include -log "Searching for world-writeable files..." +log_debug "Searching for world-writeable files..." files=$(find ${BUILDROOT} -type f -perm -2 2>/dev/null) if [ -n "${files}" ]; then - log " QA Security Notice:" - log " - The folloing files will be world writable." - log " - This may or may not be a security problem, most of the time it is one." - log " - Please double check that these files really need a world writeable bit and file bugs accordingly." - log - log "${files}" + log_error " QA Security Notice:" + log_error " - The folloing files will be world writable." + log_error " - This may or may not be a security problem, most of the time it is one." + log_error " - Please double check that these files really need a world writeable bit and file bugs accordingly." + log_error + log_error "${files}" exit 1 fi files=$(find ${BUILDROOT} -type f '(' -perm -2002 -o -perm -4002 ')') if [ -n "${files}" ]; then - log " QA Notice: Unsafe files detected (set*id and world writable)" - log - log "${files}" + log_error " QA Notice: Unsafe files detected (set*id and world writable)" + log_error + log_error "${files}" exit 1 fi diff --git a/tools/quality-agent.d/002-bad-symlinks b/tools/quality-agent.d/002-bad-symlinks index f3217fd7b..e05fc8239 100755 --- a/tools/quality-agent.d/002-bad-symlinks +++ b/tools/quality-agent.d/002-bad-symlinks @@ -5,17 +5,17 @@ # Check for absolute symlinks. # We do not allow them because they may point to any bad location. -log "Search for absolute symlinks" +log_debug "Search for absolute symlinks" failed=0 for link in $(find ${BUILDROOT} -type l); do destination=$(readlink ${link}) if [ "${destination:0:1}" = "/" ]; then - log " absolute symlink: ${link}" + log_error " absolute symlink: ${link}" failed=1 fi if [ ! -e "${link%/*}/${destination}" ]; then - log " not existant destination: ${link} -> ${destination}" + log_error " not existant destination: ${link} -> ${destination}" failed=1 fi done diff --git a/tools/quality-agent.d/003-libs-location b/tools/quality-agent.d/003-libs-location index 09a4280b1..3d29bea7a 100755 --- a/tools/quality-agent.d/003-libs-location +++ b/tools/quality-agent.d/003-libs-location @@ -4,7 +4,7 @@ # Check for libs that are missing in /usr/lib. -log "Checking correct installation of libraries" +log_debug "Checking correct installation of libraries" failed=0 for lib in $(find ${BUILDROOT}/lib -type f -name "lib*.so.*" 2>/dev/null); do @@ -13,7 +13,7 @@ for lib in $(find ${BUILDROOT}/lib -type f -name "lib*.so.*" 2>/dev/null); do if [ ! -e "${BUILDROOT}/usr/lib/${lib}.so" ]; then failed=1 - log " /usr/lib/${lib}.so is missing" + log_error " /usr/lib/${lib}.so is missing" fi done diff --git a/tools/quality-agent.d/050-canary b/tools/quality-agent.d/050-canary new file mode 100755 index 000000000..9841d5a8d --- /dev/null +++ b/tools/quality-agent.d/050-canary @@ -0,0 +1,21 @@ +#!/bin/bash + +. $(dirname ${0})/qa-include + +DESC="Every binary file has to provide a canary." + +function check() { + local failed=0 + + local file + for file in $(find_elf_files ${BINARY_PATHS}); do + if ! has_canary ${file}; then + log_error " Has no canary: ${file}" + failed=1 + fi + done + + return ${failed} +} + +run diff --git a/tools/quality-agent.d/050-execstacks b/tools/quality-agent.d/050-execstacks index ce384f1b9..d3aace659 100755 --- a/tools/quality-agent.d/050-execstacks +++ b/tools/quality-agent.d/050-execstacks @@ -2,32 +2,21 @@ . $(dirname ${0})/qa-include -# Also, executable stacks only matter on linux... -log "Searching for executeable stacks" +DESC="Files with executable stacks will not work properly (or at all!) \ + on some architectures/operating systems." -command="scanelf -qyRF '%e %p' ${BUILDROOT} 2>/dev/null" +check() { + local failed=0 -for i in $QUALITY_AGENT_WHITELIST_EXECSTACK; do - if [ -n "$FILTER" ]; then - FILTER="$FILTER|$i" - else - FILTER="$i" - fi -done + local file + for file in $(find_elf_files ${BINARY_PATHS}); do + if has_execstack ${file}; then + log_error " File has execstack: ${file}" + failed=1 + fi + done -if [ -n "$FILTER" ]; then - log " Filter: $FILTER" - command="$command | grep -vE \"$FILTER\"" -fi + return ${failed} +} -files=$(${command}) -if [ -n "${files}" ]; then - log " QA Notice: The following files contain executable stacks" - log " Files with executable stacks will not work properly (or at all!)" - log " on some architectures/operating systems." - log "${files}" - - exit 1 -fi - -exit 0 +run diff --git a/tools/quality-agent.d/050-libs-needed b/tools/quality-agent.d/050-libs-needed index 3fefe61e5..dbc6196d4 100755 --- a/tools/quality-agent.d/050-libs-needed +++ b/tools/quality-agent.d/050-libs-needed @@ -2,17 +2,30 @@ . $(dirname ${0})/qa-include -check_files=$(find ${BUILDROOT} -name lib*.so) +DESC="Every shared object has to provide the NEEDED entry." -log "Searching bad libs that lack the NEEDED attribute" +check() { + local failed=0 -if [ -n "$check_files" ]; then - f=$(scanelf -ByF '%n %p' $check_files | awk '$2 == "" { print }') - if [ -n "$f" ]; then - log " QA Notice: The following shared libraries lack NEEDED entries" - log "${f}" - exit 1 - fi -fi + local file + local needed + for file in $(find_elf_files ${LIBARY_PATHS}); do + if ! is_shared_object ${file}; then + continue + fi -exit 0 + if ! has_interpreter ${file}; then + continue + fi + + needed=$(get_needed ${file}) + if [ -z "${needed}" ]; then + log_error " File lacks needed attribute: ${file}" + failed=1 + fi + done + + return ${failed} +} + +run diff --git a/tools/quality-agent.d/050-libs-soname b/tools/quality-agent.d/050-libs-soname old mode 100644 new mode 100755 index 8430e46bd..e4f514c87 --- a/tools/quality-agent.d/050-libs-soname +++ b/tools/quality-agent.d/050-libs-soname @@ -2,30 +2,30 @@ . $(dirname ${0})/qa-include -log "Searching bad libs that lack a SONAME" +DESC="Every shared object has to provide the SONAME entry." -check_files=$(find ${BUILDROOT} -name lib*.so) +check() { + local failed=0 -command="scanelf -ByF '%S %p' $check_files | awk '$2 == "" { print }'" + local file + local soname + for file in $(find_elf_files ${LIBARY_PATHS}); do + if ! is_shared_object ${file}; then + continue + fi -for i in $QUALITY_AGENT_WHITELIST_SONAME; do - if [ -n "$FILTER" ]; then - FILTER="$FILTER|$i" - else - FILTER="$i" - fi -done + if ! has_interpreter ${file}; then + continue + fi -if [ -n "$FILTER" ]; then - command="$command | grep -vE \"$FILTER\"" -fi + soname=$(get_soname ${file}) + if [ -z "${soname}" ]; then + log_error " File lacks soname attribute: ${file}" + failed=1 + fi + done -files=$(${command}) -if [ -n "${files}" ]; then - log " QA Notice: The following shared libraries lack a SONAME" - log "${files}" + return ${failed} +} - exit 1 -fi - -exit 0 +run diff --git a/tools/quality-agent.d/050-nx b/tools/quality-agent.d/050-nx new file mode 100755 index 000000000..7a78a7240 --- /dev/null +++ b/tools/quality-agent.d/050-nx @@ -0,0 +1,19 @@ +#!/bin/bash + +. $(dirname ${0})/qa-include + +function check() { + local failed=0 + + local file + for file in $(find_elf_files ${BINARY_PATHS}); do + if ! has_nx ${file}; then + log_error " No NX: ${file}" + failed=1 + fi + done + + return ${failed} +} + +run diff --git a/tools/quality-agent.d/050-relro b/tools/quality-agent.d/050-relro new file mode 100755 index 000000000..f11c07ec8 --- /dev/null +++ b/tools/quality-agent.d/050-relro @@ -0,0 +1,24 @@ +#!/bin/bash + +. $(dirname ${0})/qa-include + +DESC="Text relocations force the dynamic linker to perform extra \ + work at startup, waste system resources, and may pose a security \ + risk. On some architectures, the code may not even function \ + properly, if at all." + +function check() { + local failed=0 + + local file + for file in $(find_elf_files ${BINARY_PATHS}); do + if ! is_relro_full ${file}; then + log_error " Is not full relro: ${file}" + failed=1 + fi + done + + return ${failed} +} + +run diff --git a/tools/quality-agent.d/050-rpaths b/tools/quality-agent.d/050-rpaths index f14607d49..a5da54085 100755 --- a/tools/quality-agent.d/050-rpaths +++ b/tools/quality-agent.d/050-rpaths @@ -2,33 +2,41 @@ . $(dirname ${0})/qa-include -# Make sure we disallow insecure RUNPATH/RPATH's -# Don't want paths that point to the tree where the package was built -# (older, broken libtools would do this). Also check for null paths -# because the loader will search $PWD when it finds null paths. -log "Searching for bad RPATH attributes" - -command="scanelf -qyRF '%r %p' ${BUILDROOT} 2>/dev/null" - -for i in $QUALITY_AGENT_WHITELIST_RPATH; do +DESC="Searching for RPATHs. We don't want paths that point to the tree where \ + the package was built (older, broken libtools would do this). \ + Also check for null paths because the loader will search \$PWD when it \ + finds null paths." + +check() { + for i in $QUALITY_AGENT_WHITELIST_RPATH; do + if [ -n "$FILTER" ]; then + FILTER="$FILTER|$i" + else + FILTER="$i" + fi + done + if [ -n "$FILTER" ]; then - FILTER="$FILTER|$i" - else - FILTER="$i" + log_debug " Filter: $FILTER" fi -done -if [ -n "$FILTER" ]; then - log " Filter: $FILTER" - command="$command | grep -vE \"$FILTER\"" -fi + local failed=0 + + local file + local rpath + for file in $(find_elf_files ${BINARY_PATHS}); do + if filtered ${file}; then + continue + fi -files=$(${command}) -if [ -n "${files}" ]; then - log " QA Notice: The following files contain insecure RUNPATH's" - log "${files}" + rpath=$(get_rpath ${file}) + if [ -n "${rpath}" ]; then + log_error " File has rpath: ${file} - ${rpath}" + failed=1 + fi + done - exit 1 -fi + return ${failed} +} -exit 0 +run diff --git a/tools/quality-agent.d/050-textrels b/tools/quality-agent.d/050-textrels deleted file mode 100755 index a3c2f2e70..000000000 --- a/tools/quality-agent.d/050-textrels +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -. $(dirname ${0})/qa-include - -# TEXTREL's are baaaaaaaad -log "Searching for bad TEXTRELs" - -files=$(scanelf -qyRF '%t %p' ${BUILDROOT} 2>/dev/null | awk '{ print $NF }') -if [ -n "${files}" ]; then - log " QA Notice: The following files contain runtime text relocations" - log " Text relocations force the dynamic linker to perform extra" - log " work at startup, waste system resources, and may pose a security" - log " risk. On some architectures, the code may not even function" - log " properly, if at all." - log "${files}" - - exit 1 -fi - -exit 0 diff --git a/tools/quality-agent.d/095-directory-layout b/tools/quality-agent.d/095-directory-layout index cf1f0bd4a..c18fd4443 100755 --- a/tools/quality-agent.d/095-directory-layout +++ b/tools/quality-agent.d/095-directory-layout @@ -2,26 +2,22 @@ . $(dirname ${0})/qa-include -function check() { - local dir=${1} +DESC="The filelayout should comply to the FHS." - log " ...${dir}" +DIRS="/etc/init.d /etc/rc.d /lib/pkgconfig /usr/etc /usr/local /usr/man /usr/var" - if [ -d "${BUILDROOT}/${dir}" ]; then - log "ERROR: This directory should not be there: ${dir}" - exit 1 - fi -} +function check() { + local failed=0 -log "Check directory layout" + local dir + for dir in ${DIRS}; do + if [ -d "${dir}" ]; then + log_error "Bad directory: ${dir}" + failed=1 + fi + done -log " Checking for directories that should not be there" -check /etc/init.d -check /etc/rc.d -check /lib/pkgconfig -check /usr/etc -check /usr/local -check /usr/man -check /usr/var + return ${failed} +} -exit 0 +run diff --git a/tools/quality-agent.d/qa-include b/tools/quality-agent.d/qa-include index c7197268f..1644a9145 100644 --- a/tools/quality-agent.d/qa-include +++ b/tools/quality-agent.d/qa-include @@ -1,7 +1,29 @@ #!/bin/bash +# Include additional functions +. $(dirname ${0})/qa-functions + +function debug() { + [ "${NAOKI_DEBUG}" = "1" ] +} + function log() { - printf "%-22s: %s\n" "${0##*/}" "$@" + local facility=${1} + shift + + printf " %-7s %s\n" "${facility}" "$@" +} + +function log_debug() { + debug && log DEBUG "$@" +} + +function log_error() { + log "ERROR" "$@" +} + +function log_info() { + log "INFO" "$@" } if [ -z "${BUILDROOT}" ]; then @@ -9,5 +31,55 @@ if [ -z "${BUILDROOT}" ]; then exit 1 fi -# Include additional functions -. $(dirname ${0})/qa-functions +function filtered() { + [ -z "${FILTER}" ] && return 1 + grep -qE ${FILTER} <<<$@ +} + +function print_description() { + # Remove all whitespaces + local desc=$(echo ${DESC}) + + log_info "Check: $(basename ${0})" + IFS=' +' + for line in $(fold -s -w 60 <<<${desc}); do + log_info " ${line}" + done + log_info # Empty line + + unset IFS +} + +function qa_find() { + local filetype=${1} + local command=${2} + + log_debug "Running qa_find with command ${command} in ${filetype}" + + local file + for file in $(find_elf_files ${!filetype}); do + ${command} ${file} + done +} + +function check() { + log_error "REPLACE THIS FUNCTION BY A CUSTOM CHECK" + return 1 +} + +function run() { + local error_message + local ret + + error_message=$(check) + ret=$? + + [ "${ret}" = "0" ] && return 0 + + print_description + + echo "${error_message}" + return ${ret} +} +