diff options
-rw-r--r-- | bin/install-qa-check.d/05double-D | 17 | ||||
-rw-r--r-- | bin/install-qa-check.d/05prefix | 117 | ||||
-rw-r--r-- | bin/install-qa-check.d/10executable-issues | 140 | ||||
-rw-r--r-- | bin/install-qa-check.d/10ignored-flags | 99 | ||||
-rw-r--r-- | bin/install-qa-check.d/20deprecated-directories | 18 | ||||
-rw-r--r-- | bin/install-qa-check.d/20runtime-directories | 26 | ||||
-rw-r--r-- | bin/install-qa-check.d/60bash-completion | 130 | ||||
-rw-r--r-- | bin/install-qa-check.d/60openrc | 41 | ||||
-rw-r--r-- | bin/install-qa-check.d/60pkgconfig | 15 | ||||
-rw-r--r-- | bin/install-qa-check.d/60pngfix | 35 | ||||
-rw-r--r-- | bin/install-qa-check.d/60systemd | 25 | ||||
-rw-r--r-- | bin/install-qa-check.d/60udev | 21 | ||||
-rw-r--r-- | bin/install-qa-check.d/80libraries | 158 | ||||
-rw-r--r-- | bin/install-qa-check.d/80multilib-strict | 50 | ||||
-rw-r--r-- | bin/install-qa-check.d/90gcc-warnings | 145 | ||||
-rw-r--r-- | bin/install-qa-check.d/90world-writable | 25 | ||||
-rwxr-xr-x | bin/misc-functions.sh | 939 |
17 files changed, 1073 insertions, 928 deletions
diff --git a/bin/install-qa-check.d/05double-D b/bin/install-qa-check.d/05double-D new file mode 100644 index 000000000..1634afd78 --- /dev/null +++ b/bin/install-qa-check.d/05double-D @@ -0,0 +1,17 @@ +# Check for accidential install into ${D}/${D} + +DD_check() { + if [[ -d ${D%/}${D} ]] ; then + local -i INSTALLTOD=0 + while read -r -d $'\0' i ; do + eqawarn "QA Notice: /${i##${D%/}${D}} installed in \${D}/\${D}" + ((INSTALLTOD++)) + done < <(find "${D%/}${D}" -print0) + die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D%/}${D}" + fi +} + +DD_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/05prefix b/bin/install-qa-check.d/05prefix new file mode 100644 index 000000000..e1fc2bd99 --- /dev/null +++ b/bin/install-qa-check.d/05prefix @@ -0,0 +1,117 @@ +# Prefix specific QA checks + +install_qa_check_prefix() { + [[ ${ED} == ${D} ]] && return + + if [[ -d ${ED}/${D} ]] ; then + find "${ED}/${D}" | \ + while read i ; do + eqawarn "QA Notice: /${i##${ED}/${D}} installed in \${ED}/\${D}" + done + die "Aborting due to QA concerns: files installed in ${ED}/${D}" + fi + + if [[ -d ${ED}/${EPREFIX} ]] ; then + find "${ED}/${EPREFIX}/" | \ + while read i ; do + eqawarn "QA Notice: ${i#${D}} double prefix" + done + die "Aborting due to QA concerns: double prefix files installed" + fi + + if [[ -d ${D} ]] ; then + INSTALLTOD=$(find ${D%/} | egrep -v "^${ED}" | sed -e "s|^${D%/}||" | awk '{if (length($0) <= length("'"${EPREFIX}"'")) { if (substr("'"${EPREFIX}"'", 1, length($0)) != $0) {print $0;} } else if (substr($0, 1, length("'"${EPREFIX}"'")) != "'"${EPREFIX}"'") {print $0;} }') + if [[ -n ${INSTALLTOD} ]] ; then + eqawarn "QA Notice: the following files are outside of the prefix:" + eqawarn "${INSTALLTOD}" + die "Aborting due to QA concerns: there are files installed outside the prefix" + fi + fi + + # all further checks rely on ${ED} existing + [[ -d ${ED} ]] || return + + # check shebangs, bug #282539 + rm -f "${T}"/non-prefix-shebangs-errs + local WHITELIST=" /usr/bin/env " + # this is hell expensive, but how else? + find "${ED}" -executable \! -type d -print0 \ + | xargs -0 grep -H -n -m1 "^#!" \ + | while read f ; + do + local fn=${f%%:*} + local pos=${f#*:} ; pos=${pos%:*} + local line=${f##*:} + # shebang always appears on the first line ;) + [[ ${pos} != 1 ]] && continue + local oldIFS=${IFS} + IFS=$'\r'$'\n'$'\t'" " + line=( ${line#"#!"} ) + IFS=${oldIFS} + [[ ${WHITELIST} == *" ${line[0]} "* ]] && continue + local fp=${fn#${D}} ; fp=/${fp%/*} + # line[0] can be an absolutised path, bug #342929 + local eprefix=$(canonicalize ${EPREFIX}) + local rf=${fn} + # in case we deal with a symlink, make sure we don't replace it + # with a real file (sed -i does that) + if [[ -L ${fn} ]] ; then + rf=$(readlink ${fn}) + [[ ${rf} != /* ]] && rf=${fn%/*}/${rf} + # ignore symlinks pointing to outside prefix + # as seen in sys-devel/native-cctools + [[ $(canonicalize "/${rf#${D}}") != ${eprefix}/* ]] && continue + fi + # does the shebang start with ${EPREFIX}, and does it exist? + if [[ ${line[0]} == ${EPREFIX}/* || ${line[0]} == ${eprefix}/* ]] ; then + if [[ ! -e ${ROOT%/}${line[0]} && ! -e ${D%/}${line[0]} ]] ; then + # hmm, refers explicitly to $EPREFIX, but doesn't exist, + # if it's in PATH that's wrong in any case + if [[ ":${PATH}:" == *":${fp}:"* ]] ; then + echo "${fn#${D}}:${line[0]} (explicit EPREFIX but target not found)" \ + >> "${T}"/non-prefix-shebangs-errs + else + eqawarn "${fn#${D}} has explicit EPREFIX in shebang but target not found (${line[0]})" + fi + fi + continue + fi + # unprefixed shebang, is the script directly in $PATH? + if [[ ":${PATH}:" == *":${fp}:"* ]] ; then + if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then + # is it unprefixed, but we can just fix it because a + # prefixed variant exists + eqawarn "prefixing shebang of ${fn#${D}}" + # statement is made idempotent on purpose, because + # symlinks may point to the same target, and hence the + # same real file may be sedded multiple times since we + # read the shebangs in one go upfront for performance + # reasons + sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${EPREFIX}"${line[0]}':' "${rf}" + continue + else + # this is definitely wrong: script in $PATH and invalid shebang + echo "${fn#${D}}:${line[0]} (script ${fn##*/} installed in PATH but interpreter ${line[0]} not found)" \ + >> "${T}"/non-prefix-shebangs-errs + fi + else + # unprefixed/invalid shebang, but outside $PATH, this may be + # intended (e.g. config.guess) so remain silent by default + has stricter ${FEATURES} && \ + eqawarn "invalid shebang in ${fn#${D}}: ${line[0]}" + fi + done + if [[ -e "${T}"/non-prefix-shebangs-errs ]] ; then + eqawarn "QA Notice: the following files use invalid (possible non-prefixed) shebangs:" + while read line ; do + eqawarn " ${line}" + done < "${T}"/non-prefix-shebangs-errs + rm -f "${T}"/non-prefix-shebangs-errs + die "Aborting due to QA concerns: invalid shebangs found" + fi +} + +install_qa_check_prefix +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/10executable-issues b/bin/install-qa-check.d/10executable-issues new file mode 100644 index 000000000..f765749b6 --- /dev/null +++ b/bin/install-qa-check.d/10executable-issues @@ -0,0 +1,140 @@ +# Check for major issues with built executables: insecure RPATHs, +# text relocations, executable stacks + +elf_check() { + if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT}; then + local insecure_rpath=0 tmp_quiet=${PORTAGE_QUIET} + local f x + + # display warnings when using stricter because we die afterwards + if has stricter ${FEATURES} ; then + local PORTAGE_QUIET + fi + + # Make sure we disallow insecure RUNPATH/RPATHs. + # 1) References to PORTAGE_BUILDDIR are banned because it's a + # security risk. We don't want to load files from a + # temporary directory. + # 2) If ROOT != "/", references to ROOT are banned because + # that directory won't exist on the target system. + # 3) Null paths are banned because the loader will search $PWD when + # it finds null paths. + local forbidden_dirs="${PORTAGE_BUILDDIR}" + if [[ -n "${ROOT}" && "${ROOT}" != "/" ]]; then + forbidden_dirs+=" ${ROOT}" + fi + local dir l rpath_files=$(scanelf -F '%F:%r' -qBR "${ED}") + f="" + for dir in ${forbidden_dirs}; do + for l in $(echo "${rpath_files}" | grep -E ":${dir}|::|: "); do + f+=" ${l%%:*}\n" + if ! has stricter ${FEATURES}; then + __vecho "Auto fixing rpaths for ${l%%:*}" + TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null + fi + done + done + + # Reject set*id binaries with $ORIGIN in RPATH #260331 + x=$( + find "${ED}" -type f \( -perm -u+s -o -perm -g+s \) -print0 | \ + xargs -0 scanelf -qyRF '%r %p' | grep '$ORIGIN' + ) + + # Print QA notice. + if [[ -n ${f}${x} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: The following files contain insecure RUNPATHs" + eqawarn " Please file a bug about this at http://bugs.gentoo.org/" + eqawarn " with the maintaining herd of the package." + eqawarn "${f}${f:+${x:+\n}}${x}" + __vecho -ne '\n' + if [[ -n ${x} ]] || has stricter ${FEATURES} ; then + insecure_rpath=1 + fi + fi + + # TEXTRELs are baaaaaaaad + # Allow devs to mark things as ignorable ... e.g. things that are + # binary-only and upstream isn't cooperating (nvidia-glx) ... we + # allow ebuild authors to set QA_TEXTRELS_arch and QA_TEXTRELS ... + # the former overrides the latter ... regexes allowed ! :) + local qa_var="QA_TEXTRELS_${ARCH/-/_}" + [[ -n ${!qa_var} ]] && QA_TEXTRELS=${!qa_var} + [[ -n ${QA_STRICT_TEXTRELS} ]] && QA_TEXTRELS="" + export QA_TEXTRELS="${QA_TEXTRELS} lib*/modules/*.ko" + f=$(scanelf -qyRF '%t %p' "${ED}" | grep -v 'usr/lib/debug/') + if [[ -n ${f} ]] ; then + scanelf -qyRAF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log + __vecho -ne '\n' + eqawarn "QA Notice: The following files contain runtime text relocations" + eqawarn " Text relocations force the dynamic linker to perform extra" + eqawarn " work at startup, waste system resources, and may pose a security" + eqawarn " risk. On some architectures, the code may not even function" + eqawarn " properly, if at all." + eqawarn " For more information, see http://hardened.gentoo.org/pic-fix-guide.xml" + eqawarn " Please include the following list of files in your report:" + eqawarn "${f}" + __vecho -ne '\n' + die_msg="${die_msg} textrels," + sleep 1 + fi + + # Also, executable stacks only matter on linux (and just glibc atm ...) + f="" + case ${CTARGET:-${CHOST}} in + *-linux-gnu*) + # Check for files with executable stacks, but only on arches which + # are supported at the moment. Keep this list in sync with + # http://www.gentoo.org/proj/en/hardened/gnu-stack.xml (Arch Status) + case ${CTARGET:-${CHOST}} in + arm*|i?86*|ia64*|m68k*|s390*|sh*|x86_64*) + # Allow devs to mark things as ignorable ... e.g. things + # that are binary-only and upstream isn't cooperating ... + # we allow ebuild authors to set QA_EXECSTACK_arch and + # QA_EXECSTACK ... the former overrides the latter ... + # regexes allowed ! :) + + qa_var="QA_EXECSTACK_${ARCH/-/_}" + [[ -n ${!qa_var} ]] && QA_EXECSTACK=${!qa_var} + [[ -n ${QA_STRICT_EXECSTACK} ]] && QA_EXECSTACK="" + qa_var="QA_WX_LOAD_${ARCH/-/_}" + [[ -n ${!qa_var} ]] && QA_WX_LOAD=${!qa_var} + [[ -n ${QA_STRICT_WX_LOAD} ]] && QA_WX_LOAD="" + export QA_EXECSTACK="${QA_EXECSTACK} lib*/modules/*.ko" + export QA_WX_LOAD="${QA_WX_LOAD} lib*/modules/*.ko" + f=$(scanelf -qyRAF '%e %p' "${ED}" | grep -v 'usr/lib/debug/') + ;; + esac + ;; + esac + if [[ -n ${f} ]] ; then + # One more pass to help devs track down the source + scanelf -qyRAF '%e %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-execstack.log + __vecho -ne '\n' + eqawarn "QA Notice: The following files contain writable and executable sections" + eqawarn " Files with such sections will not work properly (or at all!) on some" + eqawarn " architectures/operating systems. A bug should be filed at" + eqawarn " http://bugs.gentoo.org/ to make sure the issue is fixed." + eqawarn " For more information, see http://hardened.gentoo.org/gnu-stack.xml" + eqawarn " Please include the following list of files in your report:" + eqawarn " Note: Bugs should be filed for the respective maintainers" + eqawarn " of the package in question and not hardened@g.o." + eqawarn "${f}" + __vecho -ne '\n' + die_msg="${die_msg} execstacks" + sleep 1 + fi + + if [[ ${insecure_rpath} -eq 1 ]] ; then + die "Aborting due to serious QA concerns with RUNPATH/RPATH" + elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then + die "Aborting due to QA concerns: ${die_msg}" + fi + fi +} + +elf_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/10ignored-flags b/bin/install-qa-check.d/10ignored-flags new file mode 100644 index 000000000..7aa9eb695 --- /dev/null +++ b/bin/install-qa-check.d/10ignored-flags @@ -0,0 +1,99 @@ +# QA checks for ignored *FLAGS. + +ignored_flag_check() { + type -P scanelf > /dev/null || return + has binchecks ${RESTRICT} && return + + local qa_var="QA_FLAGS_IGNORED_${ARCH/-/_}" + eval "[[ -n \${!qa_var} ]] && QA_FLAGS_IGNORED=(\"\${${qa_var}[@]}\")" + if [[ ${#QA_FLAGS_IGNORED[@]} -eq 1 ]] ; then + local shopts=$- + set -o noglob + QA_FLAGS_IGNORED=(${QA_FLAGS_IGNORED}) + set +o noglob + set -${shopts} + fi + + local f x + + # Check for files built without respecting *FLAGS. Note that + # -frecord-gcc-switches must be in all *FLAGS variables, in + # order to avoid false positive results here. + # NOTE: This check must execute before prepall/prepstrip, since + # prepstrip strips the .GCC.command.line sections. + if [[ "${CFLAGS}" == *-frecord-gcc-switches* ]] && \ + [[ "${CXXFLAGS}" == *-frecord-gcc-switches* ]] && \ + [[ "${FFLAGS}" == *-frecord-gcc-switches* ]] && \ + [[ "${FCFLAGS}" == *-frecord-gcc-switches* ]] ; then + rm -f "${T}"/scanelf-ignored-CFLAGS.log + for x in $(scanelf -qyRF '#k%p' -k '!.GCC.command.line' "${ED}") ; do + # Separate out file types that are known to support + # .GCC.command.line sections, using the `file` command + # similar to how prepstrip uses it. + f=$(file "${x}") || continue + [[ -z ${f} ]] && continue + if [[ ${f} == *"SB executable"* || + ${f} == *"SB shared object"* ]] ; then + echo "${x}" >> "${T}"/scanelf-ignored-CFLAGS.log + fi + done + + if [[ -f "${T}"/scanelf-ignored-CFLAGS.log ]] ; then + + if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then + for x in "${QA_FLAGS_IGNORED[@]}" ; do + sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-CFLAGS.log + done + fi + # Filter anything under /usr/lib/debug/ in order to avoid + # duplicate warnings for splitdebug files. + sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \ + -i "${T}"/scanelf-ignored-CFLAGS.log + f=$(<"${T}"/scanelf-ignored-CFLAGS.log) + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "${BAD}QA Notice: Files built without respecting CFLAGS have been detected${NORMAL}" + eqawarn " Please include the following list of files in your report:" + eqawarn "${f}" + __vecho -ne '\n' + sleep 1 + else + rm -f "${T}"/scanelf-ignored-CFLAGS.log + fi + fi + fi + + # Check for files built without respecting LDFLAGS + if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && \ + ! has binchecks ${RESTRICT} ; then + f=$(scanelf -qyRF '#k%p' -k .hash "${ED}") + if [[ -n ${f} ]] ; then + echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log + if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then + for x in "${QA_FLAGS_IGNORED[@]}" ; do + sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-LDFLAGS.log + done + fi + # Filter anything under /usr/lib/debug/ in order to avoid + # duplicate warnings for splitdebug files. + sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \ + -i "${T}"/scanelf-ignored-LDFLAGS.log + f=$(<"${T}"/scanelf-ignored-LDFLAGS.log) + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "${BAD}QA Notice: Files built without respecting LDFLAGS have been detected${NORMAL}" + eqawarn " Please include the following list of files in your report:" + eqawarn "${f}" + __vecho -ne '\n' + sleep 1 + else + rm -f "${T}"/scanelf-ignored-LDFLAGS.log + fi + fi + fi +} + +ignored_flag_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/20deprecated-directories b/bin/install-qa-check.d/20deprecated-directories new file mode 100644 index 000000000..fb82bfe7a --- /dev/null +++ b/bin/install-qa-check.d/20deprecated-directories @@ -0,0 +1,18 @@ +# Check for deprecated directories + +deprecated_dir_check() { + local x f= + for x in etc/app-defaults usr/man usr/info usr/X11R6 usr/doc usr/locale ; do + [[ -d ${ED}/$x ]] && f+=" $x\n" + done + if [[ -n $f ]] ; then + eqawarn "QA Notice: This ebuild installs into the following deprecated directories:" + eqawarn + eqawarn "$f" + fi +} + +deprecated_dir_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/20runtime-directories b/bin/install-qa-check.d/20runtime-directories new file mode 100644 index 000000000..2e21d6d04 --- /dev/null +++ b/bin/install-qa-check.d/20runtime-directories @@ -0,0 +1,26 @@ +# Check for directories that need to be created at runtime + +runtime_dir_check() { + # It's ok create these directories, but not to install into them. #493154 + # TODO: We should add var/lib to this list. + local x f= + for x in var/cache var/lock var/run run ; do + if [[ ! -L ${ED}/${x} && -d ${ED}/${x} ]] ; then + if [[ -z $(find "${ED}/${x}" -prune -empty) ]] ; then + f+=$(cd "${ED}"; find "${x}" -printf ' %p\n') + fi + fi + done + if [[ -n ${f} ]] ; then + eqawarn "QA Notice: This ebuild installs into paths that should be created at runtime." + eqawarn " To fix, simply do not install into these directories. Instead, your package" + eqawarn " should create dirs on the fly at runtime as needed via init scripts/etc..." + eqawarn + eqawarn "${f}" + fi +} + +runtime_dir_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60bash-completion b/bin/install-qa-check.d/60bash-completion new file mode 100644 index 000000000..c1547619a --- /dev/null +++ b/bin/install-qa-check.d/60bash-completion @@ -0,0 +1,130 @@ +# QA checks for bash-completion files + +bashcomp_check() { + # Check for correct bash-completion install path. + local syscompdir=$(pkg-config --variable=completionsdir bash-completion 2>/dev/null) + : ${syscompdir:=${EPREFIX}/usr/share/bash-completion/completions} + + local instcompdir + if [[ -d ${ED}/usr/share/bash-completion/completions ]]; then + instcompdir=${ED}/usr/share/bash-completion/completions + elif [[ -d ${ED}/usr/share/bash-completion ]]; then + if [[ ${syscompdir} != ${EPREFIX}/usr/share/bash-completion ]]; then + eqawarn "Bash completions were installed in legacy location. Please update" + eqawarn "the ebuild to get the install paths using bash-completion-r1.eclass." + eqawarn + fi + + instcompdir=${ED}/usr/share/bash-completion + fi + + # Do a few QA tests on bash completions. + if [[ -n ${instcompdir} && -f ${EROOT}/usr/share/bash-completion/bash_completion ]]; then + _get_completions() { + # source the file + source "${1}" &>/dev/null + + [[ ${USED_HAVE} == yes ]] && echo '__HAVE_USED__' + + # print the completed commands + while read -a args; do + [[ ${args[0]} == complete ]] || continue + # command always comes last, one per line + echo "${args[$(( ${#args[@]} - 1))]}" + done < <(complete -p) + } + + # load the global helpers + source "${EROOT}"/usr/share/bash-completion/bash_completion + + # clean up predefined completions + complete -r + + # force all completions on + _have() { + return 0 + } + + local USED_HAVE=no + # add a replacement for have() + have() { + USED_HAVE=yes + + unset -v have + _have ${1} && have=yes + } + + local f c completions + local all_compls=() + local all_files=() + local qa_warnings=() + + for f in "${instcompdir}"/*; do + # ignore directories and other non-files + [[ ! -f ${f} ]] && continue + + # skip the common code file + # (in case we're run in /usr/share/bash-completion) + [[ ${f##*/} == bash_completion ]] && continue + + completions=( $(_get_completions "${f}") ) + + if [[ ${completions[0]} == __HAVE_USED__ ]]; then + qa_warnings+=( + "${f##*/}: 'have' command is deprecated and must not be used." + ) + unset 'completions[0]' + fi + + if [[ -z ${completions[@]} ]]; then + qa_warnings+=( + "${f##*/}: does not define any completions (failed to source?)." + ) + continue + fi + + for c in "${completions[@]}"; do + if [[ ${c} == /* ]]; then + qa_warnings+=( + "${f##*/}: absolute paths can not be used for completions (on '${c}')." + ) + else + all_compls+=( "${c}" ) + fi + done + + if ! has "${f##*/}" "${all_compls[@]}"; then + qa_warnings+=( + "${f##*/}: incorrect name, no completions for '${f##*/}' command defined." + ) + fi + + all_files+=( "${f##*/}" ) + done + + for c in "${all_compls[@]}"; do + if ! has "${c}" "${all_files[@]}"; then + qa_warnings+=( + "${c}: missing alias (symlink) for completed command." + ) + fi + done + + if [[ -n ${qa_warnings[@]} ]]; then + eqawarn "Problems with installed bash completions were found:" + eqawarn + for c in "${qa_warnings[@]}"; do + eqawarn " ${c}" + done + eqawarn + eqawarn "For more details on installing bash-completions, please see:" + eqawarn "https://wiki.gentoo.org/wiki/Bash/Installing_completion_files" + eqawarn + fi + fi +} + +bashcomp_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60openrc b/bin/install-qa-check.d/60openrc new file mode 100644 index 000000000..9b7fc6d99 --- /dev/null +++ b/bin/install-qa-check.d/60openrc @@ -0,0 +1,41 @@ +# QA checks for OpenRC init.d files. + +openrc_check() { + # Sanity check syntax errors in init.d scripts + local d i + for d in /etc/conf.d /etc/init.d ; do + [[ -d ${ED}/${d} ]] || continue + for i in "${ED}"/${d}/* ; do + [[ -L ${i} ]] && continue + # if empty conf.d/init.d dir exists (baselayout), then i will be "/etc/conf.d/*" and not exist + [[ ! -e ${i} ]] && continue + if [[ ${d} == /etc/init.d && ${i} != *.sh ]] ; then + # skip non-shell-script for bug #451386 + [[ $(head -n1 "${i}") =~ ^#!.*[[:space:]/](runscript|sh)$ ]] || continue + fi + bash -n "${i}" || die "The init.d file has syntax errors: ${i}" + done + done + + local checkbashisms=$(type -P checkbashisms) + if [[ -n ${checkbashisms} ]] ; then + for d in /etc/init.d ; do + [[ -d ${ED}${d} ]] || continue + for i in "${ED}${d}"/* ; do + [[ -e ${i} ]] || continue + [[ -L ${i} ]] && continue + f=$("${checkbashisms}" -f "${i}" 2>&1) + [[ $? != 0 && -n ${f} ]] || continue + eqawarn "QA Notice: shell script appears to use non-POSIX feature(s):" + while read -r ; + do eqawarn " ${REPLY}" + done <<< "${f//${ED}}" + done + done + fi +} + +openrc_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60pkgconfig b/bin/install-qa-check.d/60pkgconfig new file mode 100644 index 000000000..1b34c04db --- /dev/null +++ b/bin/install-qa-check.d/60pkgconfig @@ -0,0 +1,15 @@ +# Check for pkg-config file issues + +pkgconfig_check() { + # Look for leaking LDFLAGS into pkg-config files + local f=$(egrep -sH '^Libs.*-Wl,(-O[012]|--hash-style)' "${ED}"/usr/*/pkgconfig/*.pc) + if [[ -n ${f} ]] ; then + eqawarn "QA Notice: pkg-config files with wrong LDFLAGS detected:" + eqawarn "${f//${D}}" + fi +} + +pkgconfig_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60pngfix b/bin/install-qa-check.d/60pngfix new file mode 100644 index 000000000..8d53040b6 --- /dev/null +++ b/bin/install-qa-check.d/60pngfix @@ -0,0 +1,35 @@ +# Check for issues with PNG files + +pngfix_check() { + local pngfix=$(type -P pngfix) + if [[ -n ${pngfix} ]] ; then + local pngout=() + local next + + while read -r -a pngout ; do + local error="" + + case "${pngout[1]}" in + CHK) + error='invalid checksum' + ;; + TFB) + error='broken IDAT window length' + ;; + esac + + if [[ -n ${error} ]] ; then + if [[ -z ${next} ]] ; then + eqawarn "QA Notice: broken .png files found:" + next=1 + fi + eqawarn " ${pngout[@]:7}: ${error}" + fi + done < <(find "${ED}" -type f -name '*.png' -exec "${pngfix}" {} +) + fi +} + +pngfix_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60systemd b/bin/install-qa-check.d/60systemd new file mode 100644 index 000000000..f134a3068 --- /dev/null +++ b/bin/install-qa-check.d/60systemd @@ -0,0 +1,25 @@ +# QA checks for systemd units. + +systemd_check() { + local systemddir f + + # Common mistakes in systemd service files. + if type -P pkg-config >/dev/null && pkg-config --exists systemd; then + systemddir=$(pkg-config --variable=systemdsystemunitdir systemd) + else + systemddir=/usr/lib/systemd/system + fi + if [[ -d ${ED%/}${systemddir} ]]; then + f=$(grep -sH '^EnvironmentFile.*=.*/etc/conf\.d' "${ED%/}${systemddir}"/*.service) + if [[ -n ${f} ]] ; then + eqawarn "QA Notice: systemd units using /etc/conf.d detected:" + eqawarn "${f//${D}}" + eqawarn "See: https://wiki.gentoo.org/wiki/Project:Systemd/conf.d_files" + fi + fi +} + +systemd_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60udev b/bin/install-qa-check.d/60udev new file mode 100644 index 000000000..4327d069d --- /dev/null +++ b/bin/install-qa-check.d/60udev @@ -0,0 +1,21 @@ +# Check udev rule installs + +udev_check() { + set +f + local x f= + for x in "${ED}etc/udev/rules.d/"* "${ED}lib"*"/udev/rules.d/"* ; do + [[ -e ${x} ]] || continue + [[ ${x} == ${ED}lib/udev/rules.d/* ]] && continue + f+=" ${x#${ED}}\n" + done + if [[ -n $f ]] ; then + eqawarn "QA Notice: udev rules should be installed in /lib/udev/rules.d:" + eqawarn + eqawarn "$f" + fi +} + +udev_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/80libraries b/bin/install-qa-check.d/80libraries new file mode 100644 index 000000000..3977baea6 --- /dev/null +++ b/bin/install-qa-check.d/80libraries @@ -0,0 +1,158 @@ +# Check for issues with installed libraries + +lib_check() { + local f x i j + + if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT}; then + # Check for shared libraries lacking SONAMEs + local qa_var="QA_SONAME_${ARCH/-/_}" + eval "[[ -n \${!qa_var} ]] && QA_SONAME=(\"\${${qa_var}[@]}\")" + f=$(scanelf -ByF '%S %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") + if [[ -n ${f} ]] ; then + echo "${f}" > "${T}"/scanelf-missing-SONAME.log + if [[ "${QA_STRICT_SONAME-unset}" == unset ]] ; then + if [[ ${#QA_SONAME[@]} -gt 1 ]] ; then + for x in "${QA_SONAME[@]}" ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log + done + else + local shopts=$- + set -o noglob + for x in ${QA_SONAME} ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log + done + set +o noglob + set -${shopts} + fi + fi + sed -e "/^\$/d" -i "${T}"/scanelf-missing-SONAME.log + f=$(<"${T}"/scanelf-missing-SONAME.log) + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: The following shared libraries lack a SONAME" + eqawarn "${f}" + __vecho -ne '\n' + sleep 1 + else + rm -f "${T}"/scanelf-missing-SONAME.log + fi + fi + + # Check for shared libraries lacking NEEDED entries + qa_var="QA_DT_NEEDED_${ARCH/-/_}" + eval "[[ -n \${!qa_var} ]] && QA_DT_NEEDED=(\"\${${qa_var}[@]}\")" + f=$(scanelf -ByF '%n %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") + if [[ -n ${f} ]] ; then + echo "${f}" > "${T}"/scanelf-missing-NEEDED.log + if [[ "${QA_STRICT_DT_NEEDED-unset}" == unset ]] ; then + if [[ ${#QA_DT_NEEDED[@]} -gt 1 ]] ; then + for x in "${QA_DT_NEEDED[@]}" ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log + done + else + local shopts=$- + set -o noglob + for x in ${QA_DT_NEEDED} ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log + done + set +o noglob + set -${shopts} + fi + fi + sed -e "/^\$/d" -i "${T}"/scanelf-missing-NEEDED.log + f=$(<"${T}"/scanelf-missing-NEEDED.log) + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: The following shared libraries lack NEEDED entries" + eqawarn "${f}" + __vecho -ne '\n' + sleep 1 + else + rm -f "${T}"/scanelf-missing-NEEDED.log + fi + fi + fi + + # this should help to ensure that all (most?) shared libraries are executable + # and that all libtool scripts / static libraries are not executable + for i in "${ED}"opt/*/lib* \ + "${ED}"lib* \ + "${ED}"usr/lib* ; do + [[ ! -d ${i} ]] && continue + + for j in "${i}"/*.so.* "${i}"/*.so ; do + [[ ! -e ${j} ]] && continue + [[ -L ${j} ]] && continue + [[ -x ${j} ]] && continue + __vecho "making executable: ${j#${ED}}" + chmod +x "${j}" + done + + for j in "${i}"/*.a "${i}"/*.la ; do + [[ ! -e ${j} ]] && continue + [[ -L ${j} ]] && continue + [[ ! -x ${j} ]] && continue + __vecho "removing executable bit: ${j#${ED}}" + chmod -x "${j}" + done + + for j in "${i}"/*.{a,dll,dylib,sl,so}.* "${i}"/*.{a,dll,dylib,sl,so} ; do + [[ ! -e ${j} ]] && continue + [[ ! -L ${j} ]] && continue + linkdest=$(readlink "${j}") + if [[ ${linkdest} == /* ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: Found an absolute symlink in a library directory:" + eqawarn " ${j#${D}} -> ${linkdest}" + eqawarn " It should be a relative symlink if in the same directory" + eqawarn " or a linker script if it crosses the /usr boundary." + fi + done + done + + # When installing static libraries into /usr/lib and shared libraries into + # /lib, we have to make sure we have a linker script in /usr/lib along side + # the static library, or gcc will utilize the static lib when linking :(. + # http://bugs.gentoo.org/4411 + local abort="no" + local a s + for a in "${ED}"usr/lib*/*.a ; do + s=${a%.a}.so + if [[ ! -e ${s} ]] ; then + s=${s%usr/*}${s##*/usr/} + if [[ -e ${s} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: Missing gen_usr_ldscript for ${s##*/}" + abort="yes" + fi + fi + done + [[ ${abort} == "yes" ]] && die "add those ldscripts" + + # Make sure people don't store libtool files or static libs in /lib + f=$(ls "${ED}"lib*/*.{a,la} 2>/dev/null) + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: Excessive files found in the / partition" + eqawarn "${f}" + __vecho -ne '\n' + die "static archives (*.a) and libtool library files (*.la) belong in /usr/lib*, not /lib*" + fi + + # Verify that the libtool files don't contain bogus $D entries. + local abort=no gentoo_bug=no always_overflow=no + for a in "${ED}"usr/lib*/*.la ; do + s=${a##*/} + if grep -qs "${ED}" "${a}" ; then + __vecho -ne '\n' + eqawarn "QA Notice: ${s} appears to contain PORTAGE_TMPDIR paths" + abort="yes" + fi + done + [[ ${abort} == "yes" ]] && die "soiled libtool library files found" +} + +lib_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/80multilib-strict b/bin/install-qa-check.d/80multilib-strict new file mode 100644 index 000000000..f944be9e6 --- /dev/null +++ b/bin/install-qa-check.d/80multilib-strict @@ -0,0 +1,50 @@ +# Strict multilib directory checks +multilib_strict_check() { + if has multilib-strict ${FEATURES} && \ + [[ -x /usr/bin/file && -x /usr/bin/find ]] && \ + [[ -n ${MULTILIB_STRICT_DIRS} && -n ${MULTILIB_STRICT_DENY} ]] + then + rm -f "${T}/multilib-strict.log" + local abort=no dir file + MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g') + for dir in ${MULTILIB_STRICT_DIRS} ; do + [[ -d ${ED}/${dir} ]] || continue + for file in $(find ${ED}/${dir} -type f | grep -v "^${ED}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do + if file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" ; then + echo "${file#${ED}//}" >> "${T}/multilib-strict.log" + fi + done + done + + if [[ -s ${T}/multilib-strict.log ]] ; then + if [[ ${#QA_MULTILIB_PATHS[@]} -eq 1 ]] ; then + local shopts=$- + set -o noglob + QA_MULTILIB_PATHS=(${QA_MULTILIB_PATHS}) + set +o noglob + set -${shopts} + fi + if [ "${QA_STRICT_MULTILIB_PATHS-unset}" = unset ] ; then + local x + for x in "${QA_MULTILIB_PATHS[@]}" ; do + sed -e "s#^${x#/}\$##" -i "${T}/multilib-strict.log" + done + sed -e "/^\$/d" -i "${T}/multilib-strict.log" + fi + if [[ -s ${T}/multilib-strict.log ]] ; then + abort=yes + echo "Files matching a file type that is not allowed:" + while read -r ; do + echo " ${REPLY}" + done < "${T}/multilib-strict.log" + fi + fi + + [[ ${abort} == yes ]] && die "multilib-strict check failed!" + fi +} + +multilib_strict_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/90gcc-warnings b/bin/install-qa-check.d/90gcc-warnings new file mode 100644 index 000000000..ae3948542 --- /dev/null +++ b/bin/install-qa-check.d/90gcc-warnings @@ -0,0 +1,145 @@ +# Check for important gcc warning + +gcc_warn_check() { + local f + + # Evaluate misc gcc warnings + if [[ -n ${PORTAGE_LOG_FILE} && -r ${PORTAGE_LOG_FILE} ]] ; then + # In debug mode, this variable definition and corresponding grep calls + # will produce false positives if they're shown in the trace. + local reset_debug=0 + if [[ ${-/x/} != $- ]] ; then + set +x + reset_debug=1 + fi + local m msgs=( + ": warning: dereferencing type-punned pointer will break strict-aliasing rules" + ": warning: dereferencing pointer .* does break strict-aliasing rules" + ": warning: implicit declaration of function" + ": warning: incompatible implicit declaration of built-in function" + ": warning: is used uninitialized in this function" # we'll ignore "may" and "might" + ": warning: comparisons like X<=Y<=Z do not have their mathematical meaning" + ": warning: null argument where non-null required" + ": warning: array subscript is below array bounds" + ": warning: array subscript is above array bounds" + ": warning: attempt to free a non-heap object" + ": warning: .* called with .*bigger.* than .* destination buffer" + ": warning: call to .* will always overflow destination buffer" + ": warning: assuming pointer wraparound does not occur when comparing" + ": warning: hex escape sequence out of range" + ": warning: [^ ]*-hand operand of comma .*has no effect" + ": warning: converting to non-pointer type .* from NULL" + ": warning: NULL used in arithmetic" + ": warning: passing NULL to non-pointer argument" + ": warning: the address of [^ ]* will always evaluate as" + ": warning: the address of [^ ]* will never be NULL" + ": warning: too few arguments for format" + ": warning: reference to local variable .* returned" + ": warning: returning reference to temporary" + ": warning: function returns address of local variable" + ": warning: .*\\[-Wsizeof-pointer-memaccess\\]" + ": warning: .*\\[-Waggressive-loop-optimizations\\]" + # this may be valid code :/ + #": warning: multi-character character constant" + # need to check these two ... + #": warning: assuming signed overflow does not occur when" + #": warning: comparison with string literal results in unspecified behav" + # yacc/lex likes to trigger this one + #": warning: extra tokens at end of .* directive" + # only gcc itself triggers this ? + #": warning: .*noreturn.* function does return" + # these throw false positives when 0 is used instead of NULL + #": warning: missing sentinel in function call" + #": warning: not enough variable arguments to fit a sentinel" + ) + local abort="no" + local i=0 + local grep_cmd=grep + [[ $PORTAGE_LOG_FILE = *.gz ]] && grep_cmd=zgrep + while [[ -n ${msgs[${i}]} ]] ; do + m=${msgs[$((i++))]} + # force C locale to work around slow unicode locales #160234 + f=$(LC_ALL=C $grep_cmd "${m}" "${PORTAGE_LOG_FILE}") + if [[ -n ${f} ]] ; then + abort="yes" + # for now, don't make this fatal (see bug #337031) + #case "$m" in + # ": warning: call to .* will always overflow destination buffer") always_overflow=yes ;; + #esac + if [[ $always_overflow = yes ]] ; then + eerror + eerror "QA Notice: Package triggers severe warnings which indicate that it" + eerror " may exhibit random runtime failures." + eerror + eerror "${f}" + eerror + eerror " Please file a bug about this at http://bugs.gentoo.org/" + eerror " with the maintaining herd of the package." + eerror + else + __vecho -ne '\n' + eqawarn "QA Notice: Package triggers severe warnings which indicate that it" + eqawarn " may exhibit random runtime failures." + eqawarn "${f}" + __vecho -ne '\n' + fi + fi + done + local cat_cmd=cat + [[ $PORTAGE_LOG_FILE = *.gz ]] && cat_cmd=zcat + [[ $reset_debug = 1 ]] && set -x + # Use safe cwd, avoiding unsafe import for bug #469338. + f=$(cd "${PORTAGE_PYM_PATH}" ; $cat_cmd "${PORTAGE_LOG_FILE}" | \ + "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/check-implicit-pointer-usage.py || die "check-implicit-pointer-usage.py failed") + if [[ -n ${f} ]] ; then + + # In the future this will be a forced "die". In preparation, + # increase the log level from "qa" to "eerror" so that people + # are aware this is a problem that must be fixed asap. + + # just warn on 32bit hosts but bail on 64bit hosts + case ${CHOST} in + alpha*|hppa64*|ia64*|powerpc64*|mips64*|sparc64*|sparcv9*|x86_64*) gentoo_bug=yes ;; + esac + + abort=yes + + if [[ $gentoo_bug = yes ]] ; then + eerror + eerror "QA Notice: Package triggers severe warnings which indicate that it" + eerror " will almost certainly crash on 64bit architectures." + eerror + eerror "${f}" + eerror + eerror " Please file a bug about this at http://bugs.gentoo.org/" + eerror " with the maintaining herd of the package." + eerror + else + __vecho -ne '\n' + eqawarn "QA Notice: Package triggers severe warnings which indicate that it" + eqawarn " will almost certainly crash on 64bit architectures." + eqawarn "${f}" + __vecho -ne '\n' + fi + + fi + if [[ ${abort} == "yes" ]] ; then + if [[ $gentoo_bug = yes || $always_overflow = yes ]] ; then + die "install aborted due to severe warnings shown above" + else + echo "Please do not file a Gentoo bug and instead" \ + "report the above QA issues directly to the upstream" \ + "developers of this software." | fmt -w 70 | \ + while read -r line ; do eqawarn "${line}" ; done + eqawarn "Homepage: ${HOMEPAGE}" + has stricter ${FEATURES} && \ + die "install aborted due to severe warnings shown above" + fi + fi + fi +} + +gcc_warn_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/90world-writable b/bin/install-qa-check.d/90world-writable new file mode 100644 index 000000000..771027e3f --- /dev/null +++ b/bin/install-qa-check.d/90world-writable @@ -0,0 +1,25 @@ +# Check for world-writable files + +world_writable_check() { + # Now we look for all world writable files. + local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${ED}:- :") + if [[ -n ${unsafe_files} ]] ; then + __vecho "QA Security Notice: world writable file(s):" + __vecho "${unsafe_files}" + __vecho "- This may or may not be a security problem, most of the time it is one." + __vecho "- Please double check that $PF really needs a world writeable bit and file bugs accordingly." + sleep 1 + fi + + local unsafe_files=$(find "${ED}" -type f '(' -perm -2002 -o -perm -4002 ')' | sed -e "s:^${ED}:/:") + if [[ -n ${unsafe_files} ]] ; then + eqawarn "QA Notice: Unsafe files detected (set*id and world writable)" + eqawarn "${unsafe_files}" + die "Unsafe files found in \${D}. Portage will not install them." + fi +} + +world_writable_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index f6c3c1cfe..d701ba6d1 100755 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -170,63 +170,17 @@ install_qa_check() { cd "${ED}" || die "cd failed" - qa_var="QA_FLAGS_IGNORED_${ARCH/-/_}" - eval "[[ -n \${!qa_var} ]] && QA_FLAGS_IGNORED=(\"\${${qa_var}[@]}\")" - if [[ ${#QA_FLAGS_IGNORED[@]} -eq 1 ]] ; then - local shopts=$- - set -o noglob - QA_FLAGS_IGNORED=(${QA_FLAGS_IGNORED}) - set +o noglob - set -${shopts} - fi - - # Check for files built without respecting *FLAGS. Note that - # -frecord-gcc-switches must be in all *FLAGS variables, in - # order to avoid false positive results here. - # NOTE: This check must execute before prepall/prepstrip, since - # prepstrip strips the .GCC.command.line sections. - if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT} && \ - [[ "${CFLAGS}" == *-frecord-gcc-switches* ]] && \ - [[ "${CXXFLAGS}" == *-frecord-gcc-switches* ]] && \ - [[ "${FFLAGS}" == *-frecord-gcc-switches* ]] && \ - [[ "${FCFLAGS}" == *-frecord-gcc-switches* ]] ; then - rm -f "${T}"/scanelf-ignored-CFLAGS.log - for x in $(scanelf -qyRF '#k%p' -k '!.GCC.command.line' "${ED}") ; do - # Separate out file types that are known to support - # .GCC.command.line sections, using the `file` command - # similar to how prepstrip uses it. - f=$(file "${x}") || continue - [[ -z ${f} ]] && continue - if [[ ${f} == *"SB executable"* || - ${f} == *"SB shared object"* ]] ; then - echo "${x}" >> "${T}"/scanelf-ignored-CFLAGS.log - fi - done - - if [[ -f "${T}"/scanelf-ignored-CFLAGS.log ]] ; then - - if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then - for x in "${QA_FLAGS_IGNORED[@]}" ; do - sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-CFLAGS.log - done - fi - # Filter anything under /usr/lib/debug/ in order to avoid - # duplicate warnings for splitdebug files. - sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \ - -i "${T}"/scanelf-ignored-CFLAGS.log - f=$(<"${T}"/scanelf-ignored-CFLAGS.log) - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "${BAD}QA Notice: Files built without respecting CFLAGS have been detected${NORMAL}" - eqawarn " Please include the following list of files in your report:" - eqawarn "${f}" - __vecho -ne '\n' - sleep 1 - else - rm -f "${T}"/scanelf-ignored-CFLAGS.log - fi - fi - fi + # Run QA checks from install-qa-check.d. + # Note: checks need to be run *before* stripping. + local f + # TODO: handle nullglob-like + for f in "${PORTAGE_BIN_PATH}"/install-qa-check.d/*; do + # Run in a subshell to treat it like external script, + # but use 'source' to pass all variables through. + ( + source "${f}" || eerror "Post-install QA check ${f##*/} failed to run" + ) + done export STRIP_MASK prepall @@ -234,290 +188,6 @@ install_qa_check() { ecompressdir --dequeue ecompress --dequeue - # Prefix specific checks - [[ ${ED} != ${D} ]] && install_qa_check_prefix - - f= - for x in etc/app-defaults usr/man usr/info usr/X11R6 usr/doc usr/locale ; do - [[ -d ${ED}/$x ]] && f+=" $x\n" - done - if [[ -n $f ]] ; then - eqawarn "QA Notice: This ebuild installs into the following deprecated directories:" - eqawarn - eqawarn "$f" - fi - - # It's ok create these directories, but not to install into them. #493154 - # TODO: We should add var/lib to this list. - f= - for x in var/cache var/lock var/run run ; do - if [[ ! -L ${ED}/${x} && -d ${ED}/${x} ]] ; then - if [[ -z $(find "${ED}/${x}" -prune -empty) ]] ; then - f+=$(cd "${ED}"; find "${x}" -printf ' %p\n') - fi - fi - done - if [[ -n ${f} ]] ; then - eqawarn "QA Notice: This ebuild installs into paths that should be created at runtime." - eqawarn " To fix, simply do not install into these directories. Instead, your package" - eqawarn " should create dirs on the fly at runtime as needed via init scripts/etc..." - eqawarn - eqawarn "${f}" - fi - - set +f - f= - for x in "${ED}etc/udev/rules.d/"* "${ED}lib"*"/udev/rules.d/"* ; do - [[ -e ${x} ]] || continue - [[ ${x} == ${ED}lib/udev/rules.d/* ]] && continue - f+=" ${x#${ED}}\n" - done - if [[ -n $f ]] ; then - eqawarn "QA Notice: udev rules should be installed in /lib/udev/rules.d:" - eqawarn - eqawarn "$f" - fi - - # Now we look for all world writable files. - local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${ED}:- :") - if [[ -n ${unsafe_files} ]] ; then - __vecho "QA Security Notice: world writable file(s):" - __vecho "${unsafe_files}" - __vecho "- This may or may not be a security problem, most of the time it is one." - __vecho "- Please double check that $PF really needs a world writeable bit and file bugs accordingly." - sleep 1 - fi - - if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT}; then - local insecure_rpath=0 tmp_quiet=${PORTAGE_QUIET} - local x - - # display warnings when using stricter because we die afterwards - if has stricter ${FEATURES} ; then - unset PORTAGE_QUIET - fi - - # Make sure we disallow insecure RUNPATH/RPATHs. - # 1) References to PORTAGE_BUILDDIR are banned because it's a - # security risk. We don't want to load files from a - # temporary directory. - # 2) If ROOT != "/", references to ROOT are banned because - # that directory won't exist on the target system. - # 3) Null paths are banned because the loader will search $PWD when - # it finds null paths. - local forbidden_dirs="${PORTAGE_BUILDDIR}" - if [[ -n "${ROOT}" && "${ROOT}" != "/" ]]; then - forbidden_dirs+=" ${ROOT}" - fi - local dir l rpath_files=$(scanelf -F '%F:%r' -qBR "${ED}") - f="" - for dir in ${forbidden_dirs}; do - for l in $(echo "${rpath_files}" | grep -E ":${dir}|::|: "); do - f+=" ${l%%:*}\n" - if ! has stricter ${FEATURES}; then - __vecho "Auto fixing rpaths for ${l%%:*}" - TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null - fi - done - done - - # Reject set*id binaries with $ORIGIN in RPATH #260331 - x=$( - find "${ED}" -type f \( -perm -u+s -o -perm -g+s \) -print0 | \ - xargs -0 scanelf -qyRF '%r %p' | grep '$ORIGIN' - ) - - # Print QA notice. - if [[ -n ${f}${x} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: The following files contain insecure RUNPATHs" - eqawarn " Please file a bug about this at http://bugs.gentoo.org/" - eqawarn " with the maintaining herd of the package." - eqawarn "${f}${f:+${x:+\n}}${x}" - __vecho -ne '\n' - if [[ -n ${x} ]] || has stricter ${FEATURES} ; then - insecure_rpath=1 - fi - fi - - # TEXTRELs are baaaaaaaad - # Allow devs to mark things as ignorable ... e.g. things that are - # binary-only and upstream isn't cooperating (nvidia-glx) ... we - # allow ebuild authors to set QA_TEXTRELS_arch and QA_TEXTRELS ... - # the former overrides the latter ... regexes allowed ! :) - qa_var="QA_TEXTRELS_${ARCH/-/_}" - [[ -n ${!qa_var} ]] && QA_TEXTRELS=${!qa_var} - [[ -n ${QA_STRICT_TEXTRELS} ]] && QA_TEXTRELS="" - export QA_TEXTRELS="${QA_TEXTRELS} lib*/modules/*.ko" - f=$(scanelf -qyRF '%t %p' "${ED}" | grep -v 'usr/lib/debug/') - if [[ -n ${f} ]] ; then - scanelf -qyRAF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log - __vecho -ne '\n' - eqawarn "QA Notice: The following files contain runtime text relocations" - eqawarn " Text relocations force the dynamic linker to perform extra" - eqawarn " work at startup, waste system resources, and may pose a security" - eqawarn " risk. On some architectures, the code may not even function" - eqawarn " properly, if at all." - eqawarn " For more information, see http://hardened.gentoo.org/pic-fix-guide.xml" - eqawarn " Please include the following list of files in your report:" - eqawarn "${f}" - __vecho -ne '\n' - die_msg="${die_msg} textrels," - sleep 1 - fi - - # Also, executable stacks only matter on linux (and just glibc atm ...) - f="" - case ${CTARGET:-${CHOST}} in - *-linux-gnu*) - # Check for files with executable stacks, but only on arches which - # are supported at the moment. Keep this list in sync with - # http://www.gentoo.org/proj/en/hardened/gnu-stack.xml (Arch Status) - case ${CTARGET:-${CHOST}} in - arm*|i?86*|ia64*|m68k*|s390*|sh*|x86_64*) - # Allow devs to mark things as ignorable ... e.g. things - # that are binary-only and upstream isn't cooperating ... - # we allow ebuild authors to set QA_EXECSTACK_arch and - # QA_EXECSTACK ... the former overrides the latter ... - # regexes allowed ! :) - - qa_var="QA_EXECSTACK_${ARCH/-/_}" - [[ -n ${!qa_var} ]] && QA_EXECSTACK=${!qa_var} - [[ -n ${QA_STRICT_EXECSTACK} ]] && QA_EXECSTACK="" - qa_var="QA_WX_LOAD_${ARCH/-/_}" - [[ -n ${!qa_var} ]] && QA_WX_LOAD=${!qa_var} - [[ -n ${QA_STRICT_WX_LOAD} ]] && QA_WX_LOAD="" - export QA_EXECSTACK="${QA_EXECSTACK} lib*/modules/*.ko" - export QA_WX_LOAD="${QA_WX_LOAD} lib*/modules/*.ko" - f=$(scanelf -qyRAF '%e %p' "${ED}" | grep -v 'usr/lib/debug/') - ;; - esac - ;; - esac - if [[ -n ${f} ]] ; then - # One more pass to help devs track down the source - scanelf -qyRAF '%e %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-execstack.log - __vecho -ne '\n' - eqawarn "QA Notice: The following files contain writable and executable sections" - eqawarn " Files with such sections will not work properly (or at all!) on some" - eqawarn " architectures/operating systems. A bug should be filed at" - eqawarn " http://bugs.gentoo.org/ to make sure the issue is fixed." - eqawarn " For more information, see http://hardened.gentoo.org/gnu-stack.xml" - eqawarn " Please include the following list of files in your report:" - eqawarn " Note: Bugs should be filed for the respective maintainers" - eqawarn " of the package in question and not hardened@g.o." - eqawarn "${f}" - __vecho -ne '\n' - die_msg="${die_msg} execstacks" - sleep 1 - fi - - # Check for files built without respecting LDFLAGS - if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && \ - ! has binchecks ${RESTRICT} ; then - f=$(scanelf -qyRF '#k%p' -k .hash "${ED}") - if [[ -n ${f} ]] ; then - echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log - if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then - for x in "${QA_FLAGS_IGNORED[@]}" ; do - sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-LDFLAGS.log - done - fi - # Filter anything under /usr/lib/debug/ in order to avoid - # duplicate warnings for splitdebug files. - sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \ - -i "${T}"/scanelf-ignored-LDFLAGS.log - f=$(<"${T}"/scanelf-ignored-LDFLAGS.log) - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "${BAD}QA Notice: Files built without respecting LDFLAGS have been detected${NORMAL}" - eqawarn " Please include the following list of files in your report:" - eqawarn "${f}" - __vecho -ne '\n' - sleep 1 - else - rm -f "${T}"/scanelf-ignored-LDFLAGS.log - fi - fi - fi - - if [[ ${insecure_rpath} -eq 1 ]] ; then - die "Aborting due to serious QA concerns with RUNPATH/RPATH" - elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then - die "Aborting due to QA concerns: ${die_msg}" - fi - - # Check for shared libraries lacking SONAMEs - qa_var="QA_SONAME_${ARCH/-/_}" - eval "[[ -n \${!qa_var} ]] && QA_SONAME=(\"\${${qa_var}[@]}\")" - f=$(scanelf -ByF '%S %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") - if [[ -n ${f} ]] ; then - echo "${f}" > "${T}"/scanelf-missing-SONAME.log - if [[ "${QA_STRICT_SONAME-unset}" == unset ]] ; then - if [[ ${#QA_SONAME[@]} -gt 1 ]] ; then - for x in "${QA_SONAME[@]}" ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log - done - else - local shopts=$- - set -o noglob - for x in ${QA_SONAME} ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log - done - set +o noglob - set -${shopts} - fi - fi - sed -e "/^\$/d" -i "${T}"/scanelf-missing-SONAME.log - f=$(<"${T}"/scanelf-missing-SONAME.log) - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: The following shared libraries lack a SONAME" - eqawarn "${f}" - __vecho -ne '\n' - sleep 1 - else - rm -f "${T}"/scanelf-missing-SONAME.log - fi - fi - - # Check for shared libraries lacking NEEDED entries - qa_var="QA_DT_NEEDED_${ARCH/-/_}" - eval "[[ -n \${!qa_var} ]] && QA_DT_NEEDED=(\"\${${qa_var}[@]}\")" - f=$(scanelf -ByF '%n %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") - if [[ -n ${f} ]] ; then - echo "${f}" > "${T}"/scanelf-missing-NEEDED.log - if [[ "${QA_STRICT_DT_NEEDED-unset}" == unset ]] ; then - if [[ ${#QA_DT_NEEDED[@]} -gt 1 ]] ; then - for x in "${QA_DT_NEEDED[@]}" ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log - done - else - local shopts=$- - set -o noglob - for x in ${QA_DT_NEEDED} ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log - done - set +o noglob - set -${shopts} - fi - fi - sed -e "/^\$/d" -i "${T}"/scanelf-missing-NEEDED.log - f=$(<"${T}"/scanelf-missing-NEEDED.log) - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: The following shared libraries lack NEEDED entries" - eqawarn "${f}" - __vecho -ne '\n' - sleep 1 - else - rm -f "${T}"/scanelf-missing-NEEDED.log - fi - fi - - PORTAGE_QUIET=${tmp_quiet} - fi - # Create NEEDED.ELF.2 regardless of RESTRICT=binchecks, since this info is # too useful not to have (it's required for things like preserve-libs), and # it's tempting for ebuild authors to set RESTRICT=binchecks for packages @@ -546,595 +216,8 @@ install_qa_check() { fi fi - local unsafe_files=$(find "${ED}" -type f '(' -perm -2002 -o -perm -4002 ')' | sed -e "s:^${ED}:/:") - if [[ -n ${unsafe_files} ]] ; then - eqawarn "QA Notice: Unsafe files detected (set*id and world writable)" - eqawarn "${unsafe_files}" - die "Unsafe files found in \${D}. Portage will not install them." - fi - - if [[ -d ${D%/}${D} ]] ; then - local -i INSTALLTOD=0 - while read -r -d $'\0' i ; do - eqawarn "QA Notice: /${i##${D%/}${D}} installed in \${D}/\${D}" - ((INSTALLTOD++)) - done < <(find "${D%/}${D}" -print0) - die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D%/}${D}" - fi - - # Sanity check syntax errors in init.d scripts - local d - for d in /etc/conf.d /etc/init.d ; do - [[ -d ${ED}/${d} ]] || continue - for i in "${ED}"/${d}/* ; do - [[ -L ${i} ]] && continue - # if empty conf.d/init.d dir exists (baselayout), then i will be "/etc/conf.d/*" and not exist - [[ ! -e ${i} ]] && continue - if [[ ${d} == /etc/init.d && ${i} != *.sh ]] ; then - # skip non-shell-script for bug #451386 - [[ $(head -n1 "${i}") =~ ^#!.*[[:space:]/](runscript|sh)$ ]] || continue - fi - bash -n "${i}" || die "The init.d file has syntax errors: ${i}" - done - done - - local checkbashisms=$(type -P checkbashisms) - if [[ -n ${checkbashisms} ]] ; then - for d in /etc/init.d ; do - [[ -d ${ED}${d} ]] || continue - for i in "${ED}${d}"/* ; do - [[ -e ${i} ]] || continue - [[ -L ${i} ]] && continue - f=$("${checkbashisms}" -f "${i}" 2>&1) - [[ $? != 0 && -n ${f} ]] || continue - eqawarn "QA Notice: shell script appears to use non-POSIX feature(s):" - while read -r ; - do eqawarn " ${REPLY}" - done <<< "${f//${ED}}" - done - done - fi - - # Common mistakes in systemd service files. - if type -P pkg-config >/dev/null && pkg-config --exists systemd; then - systemddir=$(pkg-config --variable=systemdsystemunitdir systemd) - else - systemddir=/usr/lib/systemd/system - fi - if [[ -d ${ED%/}${systemddir} ]]; then - f=$(grep -sH '^EnvironmentFile.*=.*/etc/conf\.d' "${ED%/}${systemddir}"/*.service) - if [[ -n ${f} ]] ; then - eqawarn "QA Notice: systemd units using /etc/conf.d detected:" - eqawarn "${f//${D}}" - eqawarn "See: https://wiki.gentoo.org/wiki/Project:Systemd/conf.d_files" - fi - fi - - # Check for correct bash-completion install path. - local syscompdir=$(pkg-config --variable=completionsdir bash-completion 2>/dev/null) - : ${syscompdir:=${EPREFIX}/usr/share/bash-completion/completions} - - local instcompdir - if [[ -d ${ED}/usr/share/bash-completion/completions ]]; then - instcompdir=${ED}/usr/share/bash-completion/completions - elif [[ -d ${ED}/usr/share/bash-completion ]]; then - if [[ ${syscompdir} != ${EPREFIX}/usr/share/bash-completion ]]; then - eqawarn "Bash completions were installed in legacy location. Please update" - eqawarn "the ebuild to get the install paths using bash-completion-r1.eclass." - eqawarn - fi - - instcompdir=${ED}/usr/share/bash-completion - fi - - # Do a few QA tests on bash completions. - if [[ -n ${instcompdir} && -f ${EROOT}/usr/share/bash-completion/bash_completion ]]; then - ( - _get_completions() { - # source the file - source "${1}" &>/dev/null - - [[ ${USED_HAVE} == yes ]] && echo '__HAVE_USED__' - - # print the completed commands - while read -a args; do - [[ ${args[0]} == complete ]] || continue - # command always comes last, one per line - echo "${args[$(( ${#args[@]} - 1))]}" - done < <(complete -p) - } - - # load the global helpers - source "${EROOT}"/usr/share/bash-completion/bash_completion - - # clean up predefined completions - complete -r - - # force all completions on - _have() { - return 0 - } - - local USED_HAVE=no - # add a replacement for have() - have() { - USED_HAVE=yes - - unset -v have - _have ${1} && have=yes - } - - local f c completions - local all_compls=() - local all_files=() - local qa_warnings=() - - for f in "${instcompdir}"/*; do - # ignore directories and other non-files - [[ ! -f ${f} ]] && continue - - # skip the common code file - # (in case we're run in /usr/share/bash-completion) - [[ ${f##*/} == bash_completion ]] && continue - - completions=( $(_get_completions "${f}") ) - - if [[ ${completions[0]} == __HAVE_USED__ ]]; then - qa_warnings+=( - "${f##*/}: 'have' command is deprecated and must not be used." - ) - unset 'completions[0]' - fi - - if [[ -z ${completions[@]} ]]; then - qa_warnings+=( - "${f##*/}: does not define any completions (failed to source?)." - ) - continue - fi - - for c in "${completions[@]}"; do - if [[ ${c} == /* ]]; then - qa_warnings+=( - "${f##*/}: absolute paths can not be used for completions (on '${c}')." - ) - else - all_compls+=( "${c}" ) - fi - done - - if ! has "${f##*/}" "${all_compls[@]}"; then - qa_warnings+=( - "${f##*/}: incorrect name, no completions for '${f##*/}' command defined." - ) - fi - - all_files+=( "${f##*/}" ) - done - - for c in "${all_compls[@]}"; do - if ! has "${c}" "${all_files[@]}"; then - qa_warnings+=( - "${c}: missing alias (symlink) for completed command." - ) - fi - done - - if [[ -n ${qa_warnings[@]} ]]; then - eqawarn "Problems with installed bash completions were found:" - eqawarn - for c in "${qa_warnings[@]}"; do - eqawarn " ${c}" - done - eqawarn - eqawarn "For more details on installing bash-completions, please see:" - eqawarn "https://wiki.gentoo.org/wiki/Bash/Installing_completion_files" - eqawarn - fi - ) - fi - - # Look for leaking LDFLAGS into pkg-config files - f=$(egrep -sH '^Libs.*-Wl,(-O[012]|--hash-style)' "${ED}"/usr/*/pkgconfig/*.pc) - if [[ -n ${f} ]] ; then - eqawarn "QA Notice: pkg-config files with wrong LDFLAGS detected:" - eqawarn "${f//${D}}" - fi - - # this should help to ensure that all (most?) shared libraries are executable - # and that all libtool scripts / static libraries are not executable - local j - for i in "${ED}"opt/*/lib* \ - "${ED}"lib* \ - "${ED}"usr/lib* ; do - [[ ! -d ${i} ]] && continue - - for j in "${i}"/*.so.* "${i}"/*.so ; do - [[ ! -e ${j} ]] && continue - [[ -L ${j} ]] && continue - [[ -x ${j} ]] && continue - __vecho "making executable: ${j#${ED}}" - chmod +x "${j}" - done - - for j in "${i}"/*.a "${i}"/*.la ; do - [[ ! -e ${j} ]] && continue - [[ -L ${j} ]] && continue - [[ ! -x ${j} ]] && continue - __vecho "removing executable bit: ${j#${ED}}" - chmod -x "${j}" - done - - for j in "${i}"/*.{a,dll,dylib,sl,so}.* "${i}"/*.{a,dll,dylib,sl,so} ; do - [[ ! -e ${j} ]] && continue - [[ ! -L ${j} ]] && continue - linkdest=$(readlink "${j}") - if [[ ${linkdest} == /* ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: Found an absolute symlink in a library directory:" - eqawarn " ${j#${D}} -> ${linkdest}" - eqawarn " It should be a relative symlink if in the same directory" - eqawarn " or a linker script if it crosses the /usr boundary." - fi - done - done - - # When installing static libraries into /usr/lib and shared libraries into - # /lib, we have to make sure we have a linker script in /usr/lib along side - # the static library, or gcc will utilize the static lib when linking :(. - # http://bugs.gentoo.org/4411 - abort="no" - local a s - for a in "${ED}"usr/lib*/*.a ; do - s=${a%.a}.so - if [[ ! -e ${s} ]] ; then - s=${s%usr/*}${s##*/usr/} - if [[ -e ${s} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: Missing gen_usr_ldscript for ${s##*/}" - abort="yes" - fi - fi - done - [[ ${abort} == "yes" ]] && die "add those ldscripts" - - # Make sure people don't store libtool files or static libs in /lib - f=$(ls "${ED}"lib*/*.{a,la} 2>/dev/null) - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: Excessive files found in the / partition" - eqawarn "${f}" - __vecho -ne '\n' - die "static archives (*.a) and libtool library files (*.la) belong in /usr/lib*, not /lib*" - fi - - # Verify that the libtool files don't contain bogus $D entries. - local abort=no gentoo_bug=no always_overflow=no - for a in "${ED}"usr/lib*/*.la ; do - s=${a##*/} - if grep -qs "${ED}" "${a}" ; then - __vecho -ne '\n' - eqawarn "QA Notice: ${s} appears to contain PORTAGE_TMPDIR paths" - abort="yes" - fi - done - [[ ${abort} == "yes" ]] && die "soiled libtool library files found" - - # Evaluate misc gcc warnings - if [[ -n ${PORTAGE_LOG_FILE} && -r ${PORTAGE_LOG_FILE} ]] ; then - # In debug mode, this variable definition and corresponding grep calls - # will produce false positives if they're shown in the trace. - local reset_debug=0 - if [[ ${-/x/} != $- ]] ; then - set +x - reset_debug=1 - fi - local m msgs=( - ": warning: dereferencing type-punned pointer will break strict-aliasing rules" - ": warning: dereferencing pointer .* does break strict-aliasing rules" - ": warning: implicit declaration of function" - ": warning: incompatible implicit declaration of built-in function" - ": warning: is used uninitialized in this function" # we'll ignore "may" and "might" - ": warning: comparisons like X<=Y<=Z do not have their mathematical meaning" - ": warning: null argument where non-null required" - ": warning: array subscript is below array bounds" - ": warning: array subscript is above array bounds" - ": warning: attempt to free a non-heap object" - ": warning: .* called with .*bigger.* than .* destination buffer" - ": warning: call to .* will always overflow destination buffer" - ": warning: assuming pointer wraparound does not occur when comparing" - ": warning: hex escape sequence out of range" - ": warning: [^ ]*-hand operand of comma .*has no effect" - ": warning: converting to non-pointer type .* from NULL" - ": warning: NULL used in arithmetic" - ": warning: passing NULL to non-pointer argument" - ": warning: the address of [^ ]* will always evaluate as" - ": warning: the address of [^ ]* will never be NULL" - ": warning: too few arguments for format" - ": warning: reference to local variable .* returned" - ": warning: returning reference to temporary" - ": warning: function returns address of local variable" - ": warning: .*\\[-Wsizeof-pointer-memaccess\\]" - ": warning: .*\\[-Waggressive-loop-optimizations\\]" - # this may be valid code :/ - #": warning: multi-character character constant" - # need to check these two ... - #": warning: assuming signed overflow does not occur when" - #": warning: comparison with string literal results in unspecified behav" - # yacc/lex likes to trigger this one - #": warning: extra tokens at end of .* directive" - # only gcc itself triggers this ? - #": warning: .*noreturn.* function does return" - # these throw false positives when 0 is used instead of NULL - #": warning: missing sentinel in function call" - #": warning: not enough variable arguments to fit a sentinel" - ) - abort="no" - i=0 - local grep_cmd=grep - [[ $PORTAGE_LOG_FILE = *.gz ]] && grep_cmd=zgrep - while [[ -n ${msgs[${i}]} ]] ; do - m=${msgs[$((i++))]} - # force C locale to work around slow unicode locales #160234 - f=$(LC_ALL=C $grep_cmd "${m}" "${PORTAGE_LOG_FILE}") - if [[ -n ${f} ]] ; then - abort="yes" - # for now, don't make this fatal (see bug #337031) - #case "$m" in - # ": warning: call to .* will always overflow destination buffer") always_overflow=yes ;; - #esac - if [[ $always_overflow = yes ]] ; then - eerror - eerror "QA Notice: Package triggers severe warnings which indicate that it" - eerror " may exhibit random runtime failures." - eerror - eerror "${f}" - eerror - eerror " Please file a bug about this at http://bugs.gentoo.org/" - eerror " with the maintaining herd of the package." - eerror - else - __vecho -ne '\n' - eqawarn "QA Notice: Package triggers severe warnings which indicate that it" - eqawarn " may exhibit random runtime failures." - eqawarn "${f}" - __vecho -ne '\n' - fi - fi - done - local cat_cmd=cat - [[ $PORTAGE_LOG_FILE = *.gz ]] && cat_cmd=zcat - [[ $reset_debug = 1 ]] && set -x - # Use safe cwd, avoiding unsafe import for bug #469338. - f=$(cd "${PORTAGE_PYM_PATH}" ; $cat_cmd "${PORTAGE_LOG_FILE}" | \ - "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/check-implicit-pointer-usage.py || die "check-implicit-pointer-usage.py failed") - if [[ -n ${f} ]] ; then - - # In the future this will be a forced "die". In preparation, - # increase the log level from "qa" to "eerror" so that people - # are aware this is a problem that must be fixed asap. - - # just warn on 32bit hosts but bail on 64bit hosts - case ${CHOST} in - alpha*|hppa64*|ia64*|powerpc64*|mips64*|sparc64*|sparcv9*|x86_64*) gentoo_bug=yes ;; - esac - - abort=yes - - if [[ $gentoo_bug = yes ]] ; then - eerror - eerror "QA Notice: Package triggers severe warnings which indicate that it" - eerror " will almost certainly crash on 64bit architectures." - eerror - eerror "${f}" - eerror - eerror " Please file a bug about this at http://bugs.gentoo.org/" - eerror " with the maintaining herd of the package." - eerror - else - __vecho -ne '\n' - eqawarn "QA Notice: Package triggers severe warnings which indicate that it" - eqawarn " will almost certainly crash on 64bit architectures." - eqawarn "${f}" - __vecho -ne '\n' - fi - - fi - if [[ ${abort} == "yes" ]] ; then - if [[ $gentoo_bug = yes || $always_overflow = yes ]] ; then - die "install aborted due to severe warnings shown above" - else - echo "Please do not file a Gentoo bug and instead" \ - "report the above QA issues directly to the upstream" \ - "developers of this software." | fmt -w 70 | \ - while read -r line ; do eqawarn "${line}" ; done - eqawarn "Homepage: ${HOMEPAGE}" - has stricter ${FEATURES} && \ - die "install aborted due to severe warnings shown above" - fi - fi - fi - # Portage regenerates this on the installed system. rm -f "${ED}"/usr/share/info/dir{,.gz,.bz2} || die "rm failed!" - - if has multilib-strict ${FEATURES} && \ - [[ -x /usr/bin/file && -x /usr/bin/find ]] && \ - [[ -n ${MULTILIB_STRICT_DIRS} && -n ${MULTILIB_STRICT_DENY} ]] - then - rm -f "${T}/multilib-strict.log" - local abort=no dir file - MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g') - for dir in ${MULTILIB_STRICT_DIRS} ; do - [[ -d ${ED}/${dir} ]] || continue - for file in $(find ${ED}/${dir} -type f | grep -v "^${ED}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do - if file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" ; then - echo "${file#${ED}//}" >> "${T}/multilib-strict.log" - fi - done - done - - if [[ -s ${T}/multilib-strict.log ]] ; then - if [[ ${#QA_MULTILIB_PATHS[@]} -eq 1 ]] ; then - local shopts=$- - set -o noglob - QA_MULTILIB_PATHS=(${QA_MULTILIB_PATHS}) - set +o noglob - set -${shopts} - fi - if [ "${QA_STRICT_MULTILIB_PATHS-unset}" = unset ] ; then - for x in "${QA_MULTILIB_PATHS[@]}" ; do - sed -e "s#^${x#/}\$##" -i "${T}/multilib-strict.log" - done - sed -e "/^\$/d" -i "${T}/multilib-strict.log" - fi - if [[ -s ${T}/multilib-strict.log ]] ; then - abort=yes - echo "Files matching a file type that is not allowed:" - while read -r ; do - echo " ${REPLY}" - done < "${T}/multilib-strict.log" - fi - fi - - [[ ${abort} == yes ]] && die "multilib-strict check failed!" - fi - - local pngfix=$(type -P pngfix) - if [[ -n ${pngfix} ]] ; then - local pngout=() - local next - - while read -r -a pngout ; do - local error="" - - case "${pngout[1]}" in - CHK) - error='invalid checksum' - ;; - TFB) - error='broken IDAT window length' - ;; - esac - - if [[ -n ${error} ]] ; then - if [[ -z ${next} ]] ; then - eqawarn "QA Notice: broken .png files found:" - next=1 - fi - eqawarn " ${pngout[@]:7}: ${error}" - fi - done < <(find "${ED}" -type f -name '*.png' -exec "${pngfix}" {} +) - fi -} - -install_qa_check_prefix() { - if [[ -d ${ED}/${D} ]] ; then - find "${ED}/${D}" | \ - while read i ; do - eqawarn "QA Notice: /${i##${ED}/${D}} installed in \${ED}/\${D}" - done - die "Aborting due to QA concerns: files installed in ${ED}/${D}" - fi - - if [[ -d ${ED}/${EPREFIX} ]] ; then - find "${ED}/${EPREFIX}/" | \ - while read i ; do - eqawarn "QA Notice: ${i#${D}} double prefix" - done - die "Aborting due to QA concerns: double prefix files installed" - fi - - if [[ -d ${D} ]] ; then - INSTALLTOD=$(find ${D%/} | egrep -v "^${ED}" | sed -e "s|^${D%/}||" | awk '{if (length($0) <= length("'"${EPREFIX}"'")) { if (substr("'"${EPREFIX}"'", 1, length($0)) != $0) {print $0;} } else if (substr($0, 1, length("'"${EPREFIX}"'")) != "'"${EPREFIX}"'") {print $0;} }') - if [[ -n ${INSTALLTOD} ]] ; then - eqawarn "QA Notice: the following files are outside of the prefix:" - eqawarn "${INSTALLTOD}" - die "Aborting due to QA concerns: there are files installed outside the prefix" - fi - fi - - # all further checks rely on ${ED} existing - [[ -d ${ED} ]] || return - - # check shebangs, bug #282539 - rm -f "${T}"/non-prefix-shebangs-errs - local WHITELIST=" /usr/bin/env " - # this is hell expensive, but how else? - find "${ED}" -executable \! -type d -print0 \ - | xargs -0 grep -H -n -m1 "^#!" \ - | while read f ; - do - local fn=${f%%:*} - local pos=${f#*:} ; pos=${pos%:*} - local line=${f##*:} - # shebang always appears on the first line ;) - [[ ${pos} != 1 ]] && continue - local oldIFS=${IFS} - IFS=$'\r'$'\n'$'\t'" " - line=( ${line#"#!"} ) - IFS=${oldIFS} - [[ ${WHITELIST} == *" ${line[0]} "* ]] && continue - local fp=${fn#${D}} ; fp=/${fp%/*} - # line[0] can be an absolutised path, bug #342929 - local eprefix=$(canonicalize ${EPREFIX}) - local rf=${fn} - # in case we deal with a symlink, make sure we don't replace it - # with a real file (sed -i does that) - if [[ -L ${fn} ]] ; then - rf=$(readlink ${fn}) - [[ ${rf} != /* ]] && rf=${fn%/*}/${rf} - # ignore symlinks pointing to outside prefix - # as seen in sys-devel/native-cctools - [[ $(canonicalize "/${rf#${D}}") != ${eprefix}/* ]] && continue - fi - # does the shebang start with ${EPREFIX}, and does it exist? - if [[ ${line[0]} == ${EPREFIX}/* || ${line[0]} == ${eprefix}/* ]] ; then - if [[ ! -e ${ROOT%/}${line[0]} && ! -e ${D%/}${line[0]} ]] ; then - # hmm, refers explicitly to $EPREFIX, but doesn't exist, - # if it's in PATH that's wrong in any case - if [[ ":${PATH}:" == *":${fp}:"* ]] ; then - echo "${fn#${D}}:${line[0]} (explicit EPREFIX but target not found)" \ - >> "${T}"/non-prefix-shebangs-errs - else - eqawarn "${fn#${D}} has explicit EPREFIX in shebang but target not found (${line[0]})" - fi - fi - continue - fi - # unprefixed shebang, is the script directly in $PATH? - if [[ ":${PATH}:" == *":${fp}:"* ]] ; then - if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then - # is it unprefixed, but we can just fix it because a - # prefixed variant exists - eqawarn "prefixing shebang of ${fn#${D}}" - # statement is made idempotent on purpose, because - # symlinks may point to the same target, and hence the - # same real file may be sedded multiple times since we - # read the shebangs in one go upfront for performance - # reasons - sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${EPREFIX}"${line[0]}':' "${rf}" - continue - else - # this is definitely wrong: script in $PATH and invalid shebang - echo "${fn#${D}}:${line[0]} (script ${fn##*/} installed in PATH but interpreter ${line[0]} not found)" \ - >> "${T}"/non-prefix-shebangs-errs - fi - else - # unprefixed/invalid shebang, but outside $PATH, this may be - # intended (e.g. config.guess) so remain silent by default - has stricter ${FEATURES} && \ - eqawarn "invalid shebang in ${fn#${D}}: ${line[0]}" - fi - done - if [[ -e "${T}"/non-prefix-shebangs-errs ]] ; then - eqawarn "QA Notice: the following files use invalid (possible non-prefixed) shebangs:" - while read line ; do - eqawarn " ${line}" - done < "${T}"/non-prefix-shebangs-errs - rm -f "${T}"/non-prefix-shebangs-errs - die "Aborting due to QA concerns: invalid shebangs found" - fi } install_mask() { |