| 1 |
# Copyright 1999-2006 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.5 2006/12/02 12:24:50 kevquinn Exp $ |
| 4 |
|
| 5 |
# Author: |
| 6 |
# Kevin F. Quinn <kevquinn@gentoo.org> |
| 7 |
# |
| 8 |
# This eclass provides support for manipulating PaX markings on ELF |
| 9 |
# binaries, wrapping the use of the chpaxi, paxctl and scanelf utilities. |
| 10 |
# Currently it decides which to use depending on what is installed on the |
| 11 |
# build host; this may change in the future to use a control variable |
| 12 |
# (which would also mean modifying DEPEND to bring in sys-apps/paxctl etc). |
| 13 |
# |
| 14 |
# |
| 15 |
# CONTROL |
| 16 |
# ------- |
| 17 |
# |
| 18 |
# To control what markings are set, assign PAX_MARKINGS in |
| 19 |
# /etc/make.conf to contain the strings "EI" and/or "PT". |
| 20 |
# If EI is present in PAX_MARKINGS (and the chpax utility |
| 21 |
# is present), the legacy 'chpax' style markings will be |
| 22 |
# set. If PT is present in PAX_MARKINGS (and the paxctl |
| 23 |
# utility is present), the 'paxctl' markings will be set. |
| 24 |
# Default is to try to do both. Set it to "NONE" to prevent |
| 25 |
# any markings being made. |
| 26 |
# |
| 27 |
# |
| 28 |
# PROVIDED FUNCTIONS |
| 29 |
# ------------------ |
| 30 |
# |
| 31 |
#### pax-mark <flags> {<ELF files>} |
| 32 |
# Marks files <files> with provided PaX flags <flags> |
| 33 |
# |
| 34 |
# Please confirm any relaxation of restrictions with the |
| 35 |
# Gentoo Hardened team; either ask on the gentoo-hardened |
| 36 |
# mailing list, or CC/assign hardened@g.o on a bug. |
| 37 |
# |
| 38 |
# Flags are passed directly to the utilities unchanged. Possible |
| 39 |
# flags at the time of writing, taken from /sbin/paxctl, are: |
| 40 |
# |
| 41 |
# p: disable PAGEEXEC P: enable PAGEEXEC |
| 42 |
# e: disable EMUTRMAP E: enable EMUTRMAP |
| 43 |
# m: disable MPROTECT M: enable MPROTECT |
| 44 |
# r: disable RANDMMAP R: enable RANDMMAP |
| 45 |
# s: disable SEGMEXEC S: enable SEGMEXEC |
| 46 |
# |
| 47 |
# Default flags are 'PeMRS', which are the most restrictive |
| 48 |
# settings. Refer to http://pax.grsecurity.net/ for details |
| 49 |
# on what these flags are all about. There is an obsolete |
| 50 |
# flag 'x'/'X' which has been removed from PaX. |
| 51 |
# |
| 52 |
# If chpax is not installed, the legacy EI flags (which are |
| 53 |
# not strip-safe, and strictly speaking violate the ELF spec) |
| 54 |
# will not be set. If paxctl is not installed, it falls back |
| 55 |
# to scanelf. scanelf is always present, but currently doesn't |
| 56 |
# quite do all that paxctl can do. |
| 57 |
# Returns fail if one or more files could not be marked. |
| 58 |
# |
| 59 |
# |
| 60 |
#### list-paxables {<files>} |
| 61 |
# Prints to stdout all of <files> that are suitable to having PaX |
| 62 |
# flags (i.e. filter to just ELF files). Useful for passing wild-card |
| 63 |
# lists of files to pax-mark, although in general it is preferable |
| 64 |
# for ebuilds to list precisely which executables are to be marked. |
| 65 |
# Use like: |
| 66 |
# pax-mark -m $(list-paxables ${S}/{,usr/}bin/*) |
| 67 |
# |
| 68 |
# |
| 69 |
#### host-is-pax |
| 70 |
# Returns true if the host has a PaX-enabled kernel, false otherwise. |
| 71 |
# Intended for use where the build process must be modified conditionally |
| 72 |
# in order to satisfy PaX. Note; it is _not_ intended to indicate |
| 73 |
# whether the final executables should satisfy PaX - executables should |
| 74 |
# always be marked appropriately even if they're only going to be |
| 75 |
# installed on a non-PaX system. |
| 76 |
|
| 77 |
inherit eutils |
| 78 |
|
| 79 |
# Default to both EI and PT markings. |
| 80 |
PAX_MARKINGS=${PAX_MARKINGS:="EI PT"} |
| 81 |
|
| 82 |
# pax-mark <flags> {<ELF files>} |
| 83 |
pax-mark() { |
| 84 |
local f flags fail=0 failures="" zero_load_alignment |
| 85 |
# Ignore '-' characters - in particular so that it doesn't matter if |
| 86 |
# the caller prefixes with - |
| 87 |
flags=${1//-} |
| 88 |
shift |
| 89 |
# Try chpax, for (deprecated) EI legacy marking. |
| 90 |
if type -p chpax > /dev/null && hasq EI ${PAX_MARKINGS}; then |
| 91 |
einfo "Legacy EI PaX marking -${flags}" |
| 92 |
_pax_list_files elog "$@" |
| 93 |
for f in "$@"; do |
| 94 |
chpax -${flags} "${f}" && continue |
| 95 |
fail=1 |
| 96 |
failures="${failures} ${f}" |
| 97 |
done |
| 98 |
fi |
| 99 |
# Try paxctl, then scanelf - paxctl takes precedence |
| 100 |
# over scanelf. |
| 101 |
if type -p paxctl > /dev/null && hasq PT ${PAX_MARKINGS}; then |
| 102 |
# Try paxctl, the upstream supported tool. |
| 103 |
einfo "PT PaX marking -${flags}" |
| 104 |
_pax_list_files elog "$@" |
| 105 |
for f in "$@"; do |
| 106 |
# First, try modifying the existing PAX_FLAGS header |
| 107 |
paxctl -q${flags} "${f}" && continue |
| 108 |
# Second, try stealing the (unused under PaX) PT_GNU_STACK header |
| 109 |
paxctl -qc${flags} "${f}" && continue |
| 110 |
# Third, try pulling the base down a page, to create space and |
| 111 |
# insert a PT_GNU_STACK header (works on ET_EXEC) |
| 112 |
paxctl -qC${flags} "${f}" && continue |
| 113 |
# Fourth - check if it loads to 0 (probably an ET_DYN) and if so, |
| 114 |
# try rebasing with prelink first to give paxctl some space to |
| 115 |
# grow downwards into. |
| 116 |
if type -p objdump > /dev/null && type -p prelink > /dev/null; then |
| 117 |
zero_load_alignment=$(objdump -p "${f}" | \ |
| 118 |
grep -E '^[[:space:]]*LOAD[[:space:]]*off[[:space:]]*0x0+[[:space:]]' | \ |
| 119 |
sed -e 's/.*align\(.*\)/\1/') |
| 120 |
if [[ ${zero_load_alignment} != "" ]]; then |
| 121 |
prelink -r $(( 2*(${zero_load_alignment}) )) && |
| 122 |
paxctl -qC${flags} "${f}" && continue |
| 123 |
fi |
| 124 |
fi |
| 125 |
fail=1 |
| 126 |
failures="${failures} ${f}" |
| 127 |
done |
| 128 |
elif type -p scanelf > /dev/null && [[ ${PAX_MARKINGS} != "none" ]]; then |
| 129 |
# Try scanelf, the Gentoo swiss-army knife ELF utility |
| 130 |
# Currently this sets EI and PT if it can, no option to |
| 131 |
# control what it does. |
| 132 |
einfo "Fallback PaX marking -${flags}" |
| 133 |
_pax_list_files elog "$@" |
| 134 |
scanelf -Xxz ${flags} "$@" |
| 135 |
elif [[ ${PAX_MARKINGS} != "none" ]]; then |
| 136 |
# Out of options! |
| 137 |
failures="$*" |
| 138 |
fail=1 |
| 139 |
fi |
| 140 |
if [[ ${fail} == 1 ]]; then |
| 141 |
ewarn "Failed to set PaX markings -${flags} for:" |
| 142 |
_pax_list_files ewarn ${failures} |
| 143 |
ewarn "Executables may be killed by PaX kernels." |
| 144 |
fi |
| 145 |
return ${fail} |
| 146 |
} |
| 147 |
|
| 148 |
# list-paxables {<files>} |
| 149 |
list-paxables() { |
| 150 |
file "$@" 2> /dev/null | grep -E 'ELF.*(executable|shared object)' | sed -e 's/: .*$//' |
| 151 |
} |
| 152 |
|
| 153 |
# host-is-pax |
| 154 |
# Note: if procfs is not on /proc, this returns False (e.g. Gentoo/FBSD). |
| 155 |
host-is-pax() { |
| 156 |
grep -qs ^PaX: /proc/self/status |
| 157 |
} |
| 158 |
|
| 159 |
|
| 160 |
# INTERNAL FUNCTIONS |
| 161 |
# ------------------ |
| 162 |
# |
| 163 |
# These functions are for use internally by the eclass - do not use |
| 164 |
# them elsewhere as they are not supported (i.e. they may be removed |
| 165 |
# or their function may change arbitratily). |
| 166 |
|
| 167 |
# Display a list of things, one per line, indented a bit, using the |
| 168 |
# display command in $1. |
| 169 |
_pax_list_files() { |
| 170 |
local f cmd |
| 171 |
cmd=$1 |
| 172 |
shift |
| 173 |
for f in "$@"; do |
| 174 |
${cmd} " ${f}" |
| 175 |
done |
| 176 |
} |