Added some new checks and replaced scanelf by readelf.
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}
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}
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
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}
. $(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
. $(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
. $(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.
[ "${file##*/}" = "libfl_pic.a" ] && continue
[ "${file##*/}" = "libpython2.6.a" ] && continue
- log " Removing: ${file}"
+ log_debug " Removing: ${file}"
rm -f ${file} || exit $?
done
. $(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
# 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
# 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
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
--- /dev/null
+#!/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
. $(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
. $(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
. $(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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
. $(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
+++ /dev/null
-#!/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
. $(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
#!/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
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}
+}
+