# Check for major issues with built executables: insecure RPATHs,
# text relocations, executable stacks

elf_check() {
	if ! type -P scanelf >/dev/null || has binchecks ${PORTAGE_RESTRICT}; then
		return
	fi

	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 [[ "${ROOT:-/}" != "/" ]]; then
		forbidden_dirs+=( "${ROOT}" )
	fi
	local dir l rpath_files=$(scanelf -F '%F:%r' -qBR "${ED}")
	f=""
	for dir in "${forbidden_dirs[@]}"; do
		while read l; do
			f+="  ${l/:/\n    RPATH: }\n"
			if ! has stricter ${FEATURES}; then
				__vecho "Auto fixing rpaths for ${l%%:*}"
				TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null
			fi
		done < <(echo "${rpath_files}" | grep -F -e ":${dir}" -e "::" -e ": ")
	done

	# Reject set*id binaries with $ORIGIN in RPATH #260331
	x=$(
		find "${ED}" -type f '(' -perm -u+s -o -perm -g+s ')' \
		  -exec 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 https://bugs.gentoo.org/"
		eqawarn " with the maintainer 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:"
		eqawarn
		eqawarn "   https://wiki.gentoo.org/wiki/Hardened/HOWTO_locate_and_fix_textrels"
		eqawarn
		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
		# https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart#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 " https://bugs.gentoo.org/ to make sure the issue is fixed."
		eqawarn " For more information, see:"
		eqawarn
		eqawarn "   https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart"
		eqawarn
		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@gentoo.org."
		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
}

elf_check
: # guarantee successful exit

# vim:ft=sh
