aboutsummaryrefslogtreecommitdiff
blob: 0cef800a6e2b1672a8fcdf072505520c2431c6ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#!/usr/bin/env bash
# ebuild-default-functions.sh; default functions for ebuild env that aren't saved- specific to the portage instance.
# Copyright 2005-2012 Brian Harring <ferringb@gmail.com>: BSD/GPL2
# Copyright 2004-2006 Gentoo Foundation: GPL2

# sandbox support functions
addread() {
	export SANDBOX_READ=${SANDBOX_READ}:$1
}

addwrite() {
	export SANDBOX_WRITE=${SANDBOX_WRITE}:$1
}

adddeny() {
	export SANDBOX_DENY=${SANDBOX_DENY}:$1
}

addpredict() {
	export SANDBOX_PREDICT=${SANDBOX_PREDICT}:$1
}

__dyn_src_install() {
	local f
	echo
	if ${PKGCORE_PREFIX_SUPPORT}; then
		echo ">>> Install ${PF} into ${ED} category ${CATEGORY}"
	else
		echo ">>> Install ${PF} into ${D} category ${CATEGORY}"
	fi
	if __is_function src_install; then
		__qa_invoke src_install
	else
		__qa_run_function_if_exists __phase_src_install
	fi

	"${PKGCORE_BIN_PATH}"/helpers/internals/prepall
	${PKGCORE_PREFIX_SUPPORT} || local ED=${D}
	cd "${ED}"

	if type -p scanelf > /dev/null; then
		# Make sure we disallow insecure RUNPATH/RPATH's
		# Don't want paths that point to the tree where the package was built
		# (older, broken libtools would do this).  Also check for null paths
		# because the loader will search $PWD when it finds null paths.
		f=$(scanelf -qyRF '%r %p' "${ED}" | grep -E "(${WORKDIR}|${ED}|: |::|^ )")
		if [[ -n ${f} ]]; then
			echo -ne '\a\n'
			echo "QA Notice: the following files contain insecure RUNPATH's"
			echo " Please file a bug about this at http://bugs.gentoo.org/"
			echo " For more information on this issue, kindly review:"
			echo " http://bugs.gentoo.org/81745"
			echo "${f}"
			echo -ne '\a\n'
			__feature_is_enabled stricter && die "Insecure binaries detected"
			echo "autofixing rpath..."
			TMPDIR=${WORKDIR} scanelf -BXr ${f} -o /dev/null
		fi

		# Check for setid binaries but are not built with BIND_NOW
		f=$(scanelf -qyRF '%b %p' "${ED}")
		if [[ -n ${f} ]]; then
			echo -ne '\a\n'
			echo "QA Notice: the following files are setXid, dyn linked, and using lazy bindings"
			echo " This combination is generally discouraged.  Try forcing via bashrc"
			echo " LDFLAGS='-Wl,-z,now' for the pkg, or disable FEATURES=stricter"
			echo "${f}"
			echo -ne '\a\n'
			__feature_is_enabled stricter && die "Aborting due to lazy bindings"
			sleep 1
		fi

		# TEXTREL's are baaaaaaaad
		f=$(scanelf -qyRF '%t %p' "${ED}")
		if [[ -n ${f} ]]; then
			echo -ne '\a\n'
			echo "QA Notice: the following files contain runtime text relocations"
			echo " Text relocations require a lot of extra work to be preformed by the"
			echo " dynamic linker which will cause serious performance impact on IA-32"
			echo " and might not function properly on other architectures hppa for example."
			echo " If you are a programmer please take a closer look at this package and"
			echo " consider writing a patch which addresses this problem."
			echo "${f}"
			echo -ne '\a\n'
			__feature_is_enabled stricter && die "Aborting due to textrels"
			sleep 1
		fi

		# Check for files with executable stacks
		f=$(scanelf -qyRF '%e %p' "${ED}")
		if [[ -n ${f} ]]; then
			echo -ne '\a\n'
			echo "QA Notice: the following files contain executable stacks"
			echo " Files with executable stacks will not work properly (or at all!)"
			echo " on some architectures/operating systems.  A bug should be filed"
			echo " at http://bugs.gentoo.org/ to make sure the file is fixed."
			echo "${f}"
			echo -ne '\a\n'
			__feature_is_enabled stricter && die "Aborting due to +x stack"
			sleep 1
		fi

		# Create NEEDED and NEEDED.ELF.2 files required for things like preserve-libs
		# TODO: someday find a way to move this to the triggers implementation to allow
		# for parallelization of the scanning- if useful.
		scanelf -qyRF '%a;%p;%S;%r;%n' "${ED}" | { while IFS= read -r l; do
			arch=${l%%;*}; l=${l#*;}
			obj="/${l%%;*}"; l=${l#*;}
			soname=${l%%;*}; l=${l#*;}
			rpath=${l%%;*}; l=${l#*;}; [[ ${rpath} == "  -  " ]] && rpath=""
			needed=${l%%;*}; l=${l#*;}
			echo "${obj} ${needed}" >> "${T}"/NEEDED
			echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${T}"/NEEDED.ELF.2
		done }
	fi

	echo ">>> Completed installing ${PF} into ${ED}"
	echo
	unset dir
}

__dyn_pkg_preinst() {
	if __is_function pkg_preinst; then
		__qa_invoke pkg_preinst
	else
		__qa_run_function_if_exists __phase_pkg_preinst
	fi

	${PKGCORE_PREFIX_SUPPORT} || local ED=${D}

	# total suid control.
	if __feature_is_enabled suidctl > /dev/null; then
		sfconf=/etc/portage/suidctl.conf
		echo ">>> Preforming suid scan in ${ED}"
		local i
		for i in $(find "${ED}"/ -type f \( -perm -4000 -o -perm -2000 \) ); do
			if [[ -s ${sfconf} ]]; then
				suid=$(grep ^${i/${ED}/}$ "${sfconf}")
				if [[ ${suid} == ${i/${ED}/} ]]; then
					echo "- ${i/${ED}/} is an approved suid file"
				else
					echo ">>> Removing sbit on non registered ${i/${ED}/}"
					chmod ugo-s "${i}"
					grep ^#${i/${ED}/}$ ${sfconf} > /dev/null || {
						# sandbox prevents us from writing directly
						# to files outside of the sandbox, but this
						# can easly be bypassed using the addwrite() function
						addwrite "${sfconf}"
						echo ">>> Appending commented out entry to ${sfconf} for ${PF}"
						ls_ret=$(ls -ldh "${i}")
						echo "## ${ls_ret%${ED}*}${ls_ret#*${ED}}" >> "${sfconf}"
						echo "#${i/${ED}/}" >> "${sfconf}"
						# no delwrite() eh?
						# delwrite ${sconf}
					}
				fi
			else
				echo "suidctl feature set but you are lacking a ${sfconf}"
			fi
		done
	fi

	# SELinux file labeling (needs to always be last in dyn_preinst)
	if __feature_is_enabled selinux; then
		# only attempt to label if setfiles is executable
		# and 'context' is available on selinuxfs.
		if [[ -f /selinux/context && -x /usr/sbin/setfiles ]]; then
			echo ">>> Setting SELinux security labels"
			if [[ -f ${POLICYDIR}/file_contexts/file_contexts ]]; then
				cp -f "${POLICYDIR}"/file_contexts/file_contexts "${T}"
			else
				make -C "${POLICYDIR}" FC=${T}/file_contexts "${T}"/file_contexts
			fi

			addwrite /selinux/context
			/usr/sbin/setfiles -r "${ED}" "${T}"/file_contexts "${ED}" \
				|| die "Failed to set SELinux security labels."
		else
			# nonfatal, since merging can happen outside a SE kernel
			# like during a recovery situation
			echo "!!! Unable to set SELinux security labels"
		fi
	fi
}

__internal_inherit() {
	# default, backwards compatible beast.
	local location overlay
	location=${ECLASSDIR}/${1}.eclass

	if [[ -n ${PORTDIR_OVERLAY} ]]; then
		local overlay
		for overlay in ${PORTDIR_OVERLAY}; do
			if [[ -e ${overlay}/eclass/${1}.eclass ]]; then
				location=${overlay}/eclass/${1}.eclass
				debug-print "  eclass exists: ${location}"
			fi
		done
	fi
	debug-print "inherit: $1 -> ${location}"
	__qa_invoke source "${location}" >&2 || die "died sourcing ${location} in inherit()"
	return 0
}

inherit() {
	local ECLASS_DEPTH=$(( ${ECLASS_DEPTH-0} + 1 ))

	if [[ ${ECLASS_DEPTH} -gt 1 ]]; then
		debug-print "*** Multiple Inheritance (Level: ${ECLASS_DEPTH})"
	fi

	local location olocation
	local ECLASS

	# note that this ensures any later unsets/mangling, the ebuilds original
	# setting is protected.
	local IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND

	for ECLASS in "$@"; do
		if [[ ${EBUILD_PHASE} != "depend" ]]; then
			if ! __safe_has "${ECLASS}" ${INHERITED}; then
				echo
				echo "QA Notice: ECLASS '${ECLASS}' illegal conditional inherit in ${CATEGORY}/${PF}" >&2
				echo
			fi
		fi

		unset IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND

		__internal_inherit "$1" || die "failed sourcing $1 in inherit()"

		# If each var has a value, append it to the global variable E_* to
		# be applied after everything is finished. New incremental behavior.
		[[ -n ${IUSE}         ]] && E_IUSE+=${E_IUSE:+ }${IUSE}
		[[ -n ${REQUIRED_USE} ]] && E_REQUIRED_USE+=${E_REQUIRED_USE:+ }${REQUIRED_USE}
		[[ -n ${DEPEND}       ]] && E_DEPEND+=${E_DEPEND:+ }${DEPEND}
		[[ -n ${RDEPEND}      ]] && E_RDEPEND+=${E_RDEPEND:+ }${RDEPEND}
		[[ -n ${PDEPEND}      ]] && E_PDEPEND+=${E_PDEPEND:+ }${PDEPEND}

		# while other PMs have checks to keep this unique, we don't; no need,
		# further up the stack (python side) we uniquify this.
		# if you try to do it in bash rather than python, it's ~10% slower regen
		INHERITED+=" ${ECLASS}"

		shift
	done
}

# Exports stub functions that call the eclass's functions, thereby making them default.
# For example, if ECLASS="base" and you call "EXPORT_FUNCTIONS src_unpack", the following
# code will be eval'd:
# src_unpack() { base_src_unpack; }
EXPORT_FUNCTIONS() {
	if [[ -z ${ECLASS} ]]; then
		echo "EXPORT_FUNCTIONS without a defined ECLASS" >&2
		exit 1
	fi
	while [[ -n $1 ]]; do
		debug-print "EXPORT_FUNCTIONS: $1 -> ${ECLASS}_$1"
		eval "$1() { ${ECLASS}_$1 "\$@" ; }" > /dev/null
		shift
	done
}

PKGCORE_QA_INTERCEPTORS=(
	javac java-config python python-config perl grep egrep fgrep sed
	gcc "g++" cc bash awk nawk pkg-config
)
__QA_INTERCEPTORS_ACTIVE=false

__qa_interceptors_enable() {
	# Turn off extended glob matching so that g++ doesn't get incorrectly matched.
	shopt -u extglob

	${__QA_INTERCEPTORS_ACTIVE} && return
	# QA INTERCEPTORS
	local BIN BODY BIN_PATH
	for BIN in "${PKGCORE_QA_INTERCEPTORS[@]}"; do
		BIN_PATH=$(type -pf ${BIN})
		if [[ $? != 0 ]]; then
			BODY="echo \"*** missing command: ${BIN}\" >&2; return 127"
		else
			BODY="${BIN_PATH} \"\$@\"; return \$?"
		fi
		eval "${BIN}() {
			echo -n \"QA Notice: ${BIN} in global scope: \" >&2
			if [[ \${ECLASS_DEPTH} -gt 0 ]]; then
				echo \"eclass \${ECLASS}\" >&2
			else
				echo \"\${CATEGORY}/\${PF}\" >&2
			fi
			${BODY}
		}" || echo "error creating QA interceptor ${BIN}" >&2
	done
	__QA_INTERCEPTORS_ACTIVE=true
} &> /dev/null

__qa_interceptors_disable() {
	${__QA_INTERCEPTORS_ACTIVE} || return
	local x
	for x in "${PKGCORE_QA_INTERCEPTORS[@]}"; do
		unset -f ${x}
	done
	__QA_INTERCEPTORS_ACTIVE=false
} &> /dev/null

DONT_EXPORT_VARS+=" ECLASS_DEPTH __QA_INTERCEPTORS_ACTIVE"

: