diff options
author | Fabian Groffen <grobian@gentoo.org> | 2014-09-28 19:52:16 +0200 |
---|---|---|
committer | Fabian Groffen <grobian@gentoo.org> | 2014-09-28 19:52:16 +0200 |
commit | 990c5f4896b309fdcaf1dbbb5779177ecfcf6e74 (patch) | |
tree | f54ebb8d5bcbfea1986b9c73eee0ec3c5b390577 /bin/install-qa-check.d | |
parent | install_qa_check_macho: introduce QA_IGNORE_INSTALL_NAME_FILES (diff) | |
parent | Use a single grep call for gcc warning checks (diff) | |
download | portage-990c5f4896b309fdcaf1dbbb5779177ecfcf6e74.tar.gz portage-990c5f4896b309fdcaf1dbbb5779177ecfcf6e74.tar.bz2 portage-990c5f4896b309fdcaf1dbbb5779177ecfcf6e74.zip |
Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix
Conflicts:
bin/ebuild-helpers/emake
bin/misc-functions.sh
bin/portageq
doc/Makefile
pym/_emerge/EbuildBuild.py
pym/portage/const.py
pym/portage/dbapi/vartree.py
pym/portage/package/ebuild/doebuild.py
Diffstat (limited to 'bin/install-qa-check.d')
-rw-r--r-- | bin/install-qa-check.d/05double-D | 17 | ||||
-rw-r--r-- | bin/install-qa-check.d/05prefix | 118 | ||||
-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 | 167 | ||||
-rw-r--r-- | bin/install-qa-check.d/80multilib-strict | 50 | ||||
-rw-r--r-- | bin/install-qa-check.d/90gcc-warnings | 168 | ||||
-rw-r--r-- | bin/install-qa-check.d/90world-writable | 27 |
16 files changed, 1097 insertions, 0 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..32561e263 --- /dev/null +++ b/bin/install-qa-check.d/05prefix @@ -0,0 +1,118 @@ +# 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 or an init + # script? + if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${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..c83f27800 --- /dev/null +++ b/bin/install-qa-check.d/80libraries @@ -0,0 +1,167 @@ +# 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 + # PREFIX LOCAL: support MachO objects + [[ ${CHOST} == *-darwin* ]] \ + && s=${a%.a}.dylib \ + || s=${a%.a}.so + # END PREFIX LOCAL + 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 + # PREFIX LOCAL: on AIX, "dynamic libs" have extension .a, so don't + # get false positives + [[ ${CHOST} == *-aix* ]] \ + && f=$(ls "${ED}"lib*/*.la 2>/dev/null || true) \ + || f=$(ls "${ED}"lib*/*.{a,la} 2>/dev/null) + # END PREFIX LOCAL + 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..436932e80 --- /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 ${EPREFIX}/usr/bin/file && -x ${EPREFIX}/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..9703c39de --- /dev/null +++ b/bin/install-qa-check.d/90gcc-warnings @@ -0,0 +1,168 @@ +# 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=( + # only will and does, no might :) + 'warning: .*will.*\[-Wstrict-aliasing\]' + 'warning: .*does.*\[-Wstrict-aliasing\]' + # implicit declaration of function ‘...’ + 'warning: .*\[-Wimplicit-function-declaration\]' + # with -Wall, goes in pair with -Wimplicit-function-declaration + # but without -Wall, we need to assert for it alone + 'warning: .*incompatible implicit declaration of built-in function' + # 'is used uninitialized in this function' and some more + 'warning: .*\[-Wuninitialized\]' + # comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning + 'warning: .*mathematical meaning*\[-Wparentheses\]' + # null argument where non-null required + 'warning: .*\[-Wnonnull\]' + # array subscript is above/below/outside array bounds + 'warning: .*\[-Warray-bounds\]' + # attempt to free a non-heap object + 'warning: .*\[-Wfree-nonheap-object\]' + # those three do not have matching -W flags, it seems + 'warning: .*will always overflow destination buffer' + 'warning: .*assuming pointer wraparound does not occur' + 'warning: .*escape sequence out of range' + # left/right-hand operand of comma expression has no effect + 'warning: .*comma.*\[-Wunused-value\]' + # converting to non-pointer type ... from NULL and likes + 'warning: .*\[-Wconversion-null\]' + # NULL used in arithmetic + 'warning: .*NULL.*\[-Wpointer-arith\]' + # pointer to a function used in arithmetic and likes + 'warning: .*function.*\[-Wpointer-arith\]' + # the address of ... will never be NULL and likes + # (uses of function refs & string constants in conditionals) + 'warning: .*\[-Waddress\]' + # outdated? + 'warning: .*too few arguments for format' + # format ... expects a matching ... argument + # (iow, too few arguments for format in new wording :)) + 'warning: .*matching.*\[-Wformat=\]' + # function returns address of local variable + 'warning: .*\[-Wreturn-local-addr\]' + # argument to sizeof ... is the same expression as the source + 'warning: .*\[-Wsizeof-pointer-memaccess\]' + # iteration invokes undefined behavior + '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' + ) + + # join all messages into one grep-expression + local joined_msgs + printf -v joined_msgs '%s|' "${msgs[@]}" + joined_msgs=${joined_msgs%|} + + local abort="no" + local grep_cmd=grep + [[ $PORTAGE_LOG_FILE = *.gz ]] && grep_cmd=zgrep + + # force C locale to work around slow unicode locales #160234 + f=$(LC_CTYPE=C LC_COLLATE=C "${grep_cmd}" -E "${joined_msgs}" "${PORTAGE_LOG_FILE}") + if [[ -n ${f} ]] ; then + abort="yes" + # for now, don't make this fatal (see bug #337031) + #if [[ ${f} == *'will always overflow destination buffer'* ]]; then + # always_overflow=yes + #fi + 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 + + 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..635612dc8 --- /dev/null +++ b/bin/install-qa-check.d/90world-writable @@ -0,0 +1,27 @@ +# Check for world-writable files + +world_writable_check() { + # Now we look for all world writable files. + # PREFIX LOCAL: keep offset prefix in the reported files + local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${D}:- :") + # END PREFIX LOCAL + 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:^${D}:/:") + 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 |