summaryrefslogtreecommitdiff
blob: 7322e9035659d31debab3da645d0a06ffee30f8f (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
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/eclass/pax-utils.eclass,v 1.9 2008/07/07 16:54:56 betelgeuse Exp $

# Author:
#	Kevin F. Quinn <kevquinn@gentoo.org>
#
# This eclass provides support for manipulating PaX markings on ELF
# binaries, wrapping the use of the chpaxi, paxctl and scanelf utilities.
# Currently it decides which to use depending on what is installed on the
# build host; this may change in the future to use a control variable
# (which would also mean modifying DEPEND to bring in sys-apps/paxctl etc).
#
#
# CONTROL
# -------
#
# To control what markings are set, assign PAX_MARKINGS in
# /etc/make.conf to contain the strings "EI" and/or "PT".
# If EI is present in PAX_MARKINGS (and the chpax utility
# is present), the legacy 'chpax' style markings will be
# set.  If PT is present in PAX_MARKINGS (and the paxctl
# utility is present), the 'paxctl' markings will be set.
# Default is to try to do both.  Set it to "NONE" to prevent
# any markings being made.
#
#
# PROVIDED FUNCTIONS
# ------------------
#
#### pax-mark <flags> {<ELF files>}
# Marks files <files> with provided PaX flags <flags>
#
# Please confirm any relaxation of restrictions with the
# Gentoo Hardened team; either ask on the gentoo-hardened
# mailing list, or CC/assign hardened@g.o on a bug.
#
# Flags are passed directly to the utilities unchanged.  Possible
# flags at the time of writing, taken from /sbin/paxctl, are:
#
#	p: disable PAGEEXEC		P: enable PAGEEXEC
#	e: disable EMUTRMAP		E: enable EMUTRMAP
#	m: disable MPROTECT		M: enable MPROTECT
#	r: disable RANDMMAP		R: enable RANDMMAP
#	s: disable SEGMEXEC		S: enable SEGMEXEC
#
# Default flags are 'PeMRS', which are the most restrictive
# settings.  Refer to http://pax.grsecurity.net/ for details
# on what these flags are all about.  There is an obsolete
# flag 'x'/'X' which has been removed from PaX.
#
# If chpax is not installed, the legacy EI flags (which are
# not strip-safe, and strictly speaking violate the ELF spec)
# will not be set.  If paxctl is not installed, it falls back
# to scanelf.  scanelf is always present, but currently doesn't
# quite do all that paxctl can do.
# Returns fail if one or more files could not be marked.
#
#
#### list-paxables {<files>}
# Prints to stdout all of <files> that are suitable to having PaX
# flags (i.e. filter to just ELF files).  Useful for passing wild-card
# lists of files to pax-mark, although in general it is preferable
# for ebuilds to list precisely which executables are to be marked.
# Use like:
#     pax-mark -m $(list-paxables ${S}/{,usr/}bin/*)
#
#
#### host-is-pax
# Returns true if the host has a PaX-enabled kernel, false otherwise.
# Intended for use where the build process must be modified conditionally
# in order to satisfy PaX.  Note; it is _not_ intended to indicate
# whether the final executables should satisfy PaX - executables should
# always be marked appropriately even if they're only going to be
# installed on a non-PaX system.

inherit eutils

# Default to both EI and PT markings.
PAX_MARKINGS=${PAX_MARKINGS:="EI PT"}

# pax-mark <flags> {<ELF files>}
pax-mark() {
	local f flags fail=0 failures="" zero_load_alignment
	# Ignore '-' characters - in particular so that it doesn't matter if
	# the caller prefixes with -
	flags=${1//-}
	shift
	# Try chpax, for (deprecated) EI legacy marking.
	if type -p chpax > /dev/null && hasq EI ${PAX_MARKINGS}; then
		elog "Legacy EI PaX marking -${flags}"
		_pax_list_files elog "$@"
		for f in "$@"; do
			chpax -${flags} "${f}" && continue
			fail=1
			failures="${failures} ${f}"
		done
	fi
	# Try paxctl, then scanelf - paxctl takes precedence
	# over scanelf.
	if type -p paxctl > /dev/null && hasq PT ${PAX_MARKINGS}; then
		# Try paxctl, the upstream supported tool.
		elog "PT PaX marking -${flags}"
		_pax_list_files elog "$@"
		for f in "$@"; do
			# First, try modifying the existing PAX_FLAGS header
			paxctl -q${flags} "${f}" && continue
			# Second, try stealing the (unused under PaX) PT_GNU_STACK header
			paxctl -qc${flags} "${f}" && continue
			# Third, try pulling the base down a page, to create space and
			# insert a PT_GNU_STACK header (works on ET_EXEC)
			paxctl -qC${flags} "${f}" && continue
			# Fourth - check if it loads to 0 (probably an ET_DYN) and if so,
			# try rebasing with prelink first to give paxctl some space to
			# grow downwards into.
			if type -p objdump > /dev/null && type -p prelink > /dev/null; then
				zero_load_alignment=$(objdump -p "${f}" | \
					grep -E '^[[:space:]]*LOAD[[:space:]]*off[[:space:]]*0x0+[[:space:]]' | \
					sed -e 's/.*align\(.*\)/\1/')
				if [[ ${zero_load_alignment} != "" ]]; then
					prelink -r $(( 2*(${zero_load_alignment}) )) &&
					paxctl -qC${flags} "${f}" && continue
				fi
			fi
			fail=1
			failures="${failures} ${f}"
		done
	elif type -p scanelf > /dev/null && [[ ${PAX_MARKINGS} != "none" ]]; then
		# Try scanelf, the Gentoo swiss-army knife ELF utility
		# Currently this sets EI and PT if it can, no option to
		# control what it does.
		elog "Fallback PaX marking -${flags}"
		_pax_list_files elog "$@"
		scanelf -Xxz ${flags} "$@"
	elif [[ ${PAX_MARKINGS} != "none" ]]; then
		# Out of options!
		failures="$*"
		fail=1
	fi
	if [[ ${fail} == 1 ]]; then
		ewarn "Failed to set PaX markings -${flags} for:"
		_pax_list_files ewarn ${failures}
		ewarn "Executables may be killed by PaX kernels."
	fi
	return ${fail}
}

# list-paxables {<files>}
list-paxables() {
	file "$@" 2> /dev/null | grep -E 'ELF.*(executable|shared object)' | sed -e 's/: .*$//'
}

# host-is-pax
# Note: if procfs is not on /proc, this returns False (e.g. Gentoo/FBSD).
host-is-pax() {
	grep -qs ^PaX: /proc/self/status
}


# INTERNAL FUNCTIONS
# ------------------
#
# These functions are for use internally by the eclass - do not use
# them elsewhere as they are not supported (i.e. they may be removed
# or their function may change arbitratily).

# Display a list of things, one per line, indented a bit, using the
# display command in $1.
_pax_list_files() {
	local f cmd
	cmd=$1
	shift
	for f in "$@"; do
		${cmd} "     ${f}"
	done
}