1 |
# Copyright 1999-2014 Gentoo Foundation |
2 |
# Distributed under the terms of the GNU General Public License v2 |
3 |
# $Header: /var/cvsroot/gentoo-x86/eclass/pax-utils.eclass,v 1.23 2014/08/30 14:06:04 blueness Exp $ |
4 |
|
5 |
# @ECLASS: pax-utils.eclass |
6 |
# @MAINTAINER: |
7 |
# The Gentoo Linux Hardened Team <hardened@gentoo.org> |
8 |
# @AUTHOR: |
9 |
# Original Author: Kevin F. Quinn <kevquinn@gentoo.org> |
10 |
# Modifications for bugs #365825, #431092, #520198, @ ECLASS markup: Anthony G. Basile <blueness@gentoo.org> |
11 |
# @BLURB: functions to provide pax markings |
12 |
# @DESCRIPTION: |
13 |
# |
14 |
# This eclass provides support for manipulating PaX markings on ELF binaries, |
15 |
# whether the system is using legacy PT_PAX markings or the newer XATTR_PAX. |
16 |
# The eclass wraps the use of paxctl-ng, paxctl, set/getattr and scanelf utilities, |
17 |
# deciding which to use depending on what's installed on the build host, and |
18 |
# whether we're working with PT_PAX, XATTR_PAX or both. |
19 |
# |
20 |
# To control what markings are made, set PAX_MARKINGS in /etc/portage/make.conf |
21 |
# to contain either "PT", "XT" or "none". The default is to attempt both |
22 |
# PT_PAX and XATTR_PAX. |
23 |
|
24 |
if [[ -z ${_PAX_UTILS_ECLASS} ]]; then |
25 |
_PAX_UTILS_ECLASS=1 |
26 |
|
27 |
# @ECLASS-VARIABLE: PAX_MARKINGS |
28 |
# @DESCRIPTION: |
29 |
# Control which markings are made: |
30 |
# PT = PT_PAX markings, XT = XATTR_PAX markings |
31 |
# Default to PT markings. |
32 |
PAX_MARKINGS=${PAX_MARKINGS:="PT"} |
33 |
|
34 |
# @FUNCTION: pax-mark |
35 |
# @USAGE: <flags> {<ELF files>} |
36 |
# @RETURN: Shell true if we succeed, shell false otherwise |
37 |
# @DESCRIPTION: |
38 |
# Marks <ELF files> with provided PaX <flags> |
39 |
# |
40 |
# Flags are passed directly to the utilities unchanged |
41 |
# |
42 |
# p: disable PAGEEXEC P: enable PAGEEXEC |
43 |
# e: disable EMUTRAMP E: enable EMUTRAMP |
44 |
# m: disable MPROTECT M: enable MPROTECT |
45 |
# r: disable RANDMMAP R: enable RANDMMAP |
46 |
# s: disable SEGMEXEC S: enable SEGMEXEC |
47 |
# |
48 |
# Default flags are 'PeMRS', which are the most restrictive settings. Refer |
49 |
# to http://pax.grsecurity.net/ for details on what these flags are all about. |
50 |
# |
51 |
# Please confirm any relaxation of restrictions with the Gentoo Hardened team. |
52 |
# Either ask on the gentoo-hardened mailing list, or CC/assign hardened@g.o on |
53 |
# the bug report. |
54 |
pax-mark() { |
55 |
|
56 |
local f # loop over paxables |
57 |
local flags # pax flags |
58 |
local ret=0 # overal return code of this function |
59 |
|
60 |
# Only the actual PaX flags and z are accepted |
61 |
# 1. The leading '-' is optional |
62 |
# 2. -C -c only make sense for paxctl, but are unnecessary |
63 |
# because we progressively do -q -qc -qC |
64 |
# 3. z is allowed for the default |
65 |
|
66 |
flags="${1//[!zPpEeMmRrSs]}" |
67 |
[[ "${flags}" ]] || return 0 |
68 |
shift |
69 |
|
70 |
# z = default. For XATTR_PAX, the default is no xattr field at all |
71 |
local dodefault="" |
72 |
[[ "${flags//[!z]}" ]] && dodefault="yes" |
73 |
|
74 |
if has PT ${PAX_MARKINGS}; then |
75 |
_pax_list_files einfo "$@" |
76 |
for f in "$@"; do |
77 |
|
78 |
#First try paxctl -> this might try to create/convert program headers |
79 |
if type -p paxctl > /dev/null; then |
80 |
einfo "PT PaX marking -${flags} ${f} with paxctl" |
81 |
# First, try modifying the existing PAX_FLAGS header |
82 |
paxctl -q${flags} "${f}" && continue |
83 |
# Second, try creating a PT_PAX header (works on ET_EXEC) |
84 |
# Even though this is less safe, most exes need it, eg bug #463170 |
85 |
paxctl -qC${flags} "${f}" && continue |
86 |
# Third, try stealing the (unused under PaX) PT_GNU_STACK header |
87 |
paxctl -qc${flags} "${f}" && continue |
88 |
fi |
89 |
|
90 |
#Next try paxctl-ng -> this will not create/convert any program headers |
91 |
if type -p paxctl-ng > /dev/null && paxctl-ng -L ; then |
92 |
einfo "PT PaX marking -${flags} ${f} with paxctl-ng" |
93 |
flags="${flags//z}" |
94 |
[[ ${dodefault} == "yes" ]] && paxctl-ng -L -z "${f}" |
95 |
[[ "${flags}" ]] || continue |
96 |
paxctl-ng -L -${flags} "${f}" && continue |
97 |
fi |
98 |
|
99 |
#Finally fall back on scanelf |
100 |
if type -p scanelf > /dev/null && [[ ${PAX_MARKINGS} != "none" ]]; then |
101 |
scanelf -Xxz ${flags} "$f" |
102 |
#We failed to set PT_PAX flags |
103 |
elif [[ ${PAX_MARKINGS} != "none" ]]; then |
104 |
elog "Failed to set PT_PAX markings -${flags} ${f}." |
105 |
ret=1 |
106 |
fi |
107 |
done |
108 |
fi |
109 |
|
110 |
if has XT ${PAX_MARKINGS}; then |
111 |
_pax_list_files einfo "$@" |
112 |
flags="${flags//z}" |
113 |
for f in "$@"; do |
114 |
|
115 |
#First try paxctl-ng |
116 |
if type -p paxctl-ng > /dev/null && paxctl-ng -l ; then |
117 |
einfo "XT PaX marking -${flags} ${f} with paxctl-ng" |
118 |
[[ ${dodefault} == "yes" ]] && paxctl-ng -d "${f}" |
119 |
[[ "${flags}" ]] || continue |
120 |
paxctl-ng -l -${flags} "${f}" && continue |
121 |
fi |
122 |
|
123 |
#Next try setfattr |
124 |
if type -p setfattr > /dev/null; then |
125 |
[[ "${flags//[!Ee]}" ]] || flags+="e" # bug 447150 |
126 |
einfo "XT PaX marking -${flags} ${f} with setfattr" |
127 |
[[ ${dodefault} == "yes" ]] && setfattr -x "user.pax.flags" "${f}" |
128 |
setfattr -n "user.pax.flags" -v "${flags}" "${f}" && continue |
129 |
fi |
130 |
|
131 |
#We failed to set XATTR_PAX flags |
132 |
if [[ ${PAX_MARKINGS} != "none" ]]; then |
133 |
elog "Failed to set XATTR_PAX markings -${flags} ${f}." |
134 |
ret=1 |
135 |
fi |
136 |
done |
137 |
fi |
138 |
|
139 |
# [[ ${ret} == 1 ]] && elog "Executables may be killed by PaX kernels." |
140 |
|
141 |
return ${ret} |
142 |
} |
143 |
|
144 |
# @FUNCTION: list-paxables |
145 |
# @USAGE: {<files>} |
146 |
# @RETURN: Subset of {<files>} which are ELF executables or shared objects |
147 |
# @DESCRIPTION: |
148 |
# Print to stdout all of the <files> that are suitable to have PaX flag |
149 |
# markings, i.e., filter out the ELF executables or shared objects from a list |
150 |
# of files. This is useful for passing wild-card lists to pax-mark, although |
151 |
# in general it is preferable for ebuilds to list precisely which ELFS are to |
152 |
# be marked. Often not all the ELF installed by a package need remarking. |
153 |
# @EXAMPLE: |
154 |
# pax-mark -m $(list-paxables ${S}/{,usr/}bin/*) |
155 |
list-paxables() { |
156 |
file "$@" 2> /dev/null | grep -E 'ELF.*(executable|shared object)' | sed -e 's/: .*$//' |
157 |
} |
158 |
|
159 |
# @FUNCTION: host-is-pax |
160 |
# @RETURN: Shell true if the build process is PaX enabled, shell false otherwise |
161 |
# @DESCRIPTION: |
162 |
# This is intended for use where the build process must be modified conditionally |
163 |
# depending on whether the host is PaX enabled or not. It is not intedened to |
164 |
# determine whether the final binaries need PaX markings. Note: if procfs is |
165 |
# not mounted on /proc, this returns shell false (e.g. Gentoo/FBSD). |
166 |
host-is-pax() { |
167 |
grep -qs ^PaX: /proc/self/status |
168 |
} |
169 |
|
170 |
|
171 |
# INTERNAL FUNCTIONS |
172 |
# ------------------ |
173 |
# |
174 |
# These functions are for use internally by the eclass - do not use |
175 |
# them elsewhere as they are not supported (i.e. they may be removed |
176 |
# or their function may change arbitratily). |
177 |
|
178 |
# Display a list of things, one per line, indented a bit, using the |
179 |
# display command in $1. |
180 |
_pax_list_files() { |
181 |
local f cmd |
182 |
cmd=$1 |
183 |
shift |
184 |
for f in "$@"; do |
185 |
${cmd} " ${f}" |
186 |
done |
187 |
} |
188 |
|
189 |
fi |