aboutsummaryrefslogtreecommitdiff
path: root/pocs
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2014-07-30 15:40:36 -0400
committerAnthony G. Basile <blueness@gentoo.org>2014-07-30 15:40:36 -0400
commitc206aab32dce7db944996628f160a3dcbaeb6c6f (patch)
tree808d1e0bd0877f367182b1ffc072fa9c4f9a5da0 /pocs
parentconfigure.ac: replace tabs with 4 spaces (diff)
downloadelfix-c206aab32dce7db944996628f160a3dcbaeb6c6f.tar.gz
elfix-c206aab32dce7db944996628f160a3dcbaeb6c6f.tar.bz2
elfix-c206aab32dce7db944996628f160a3dcbaeb6c6f.zip
Split misc/ into misc/ for production and poc/ for experimental stuff.
Diffstat (limited to 'pocs')
-rw-r--r--pocs/change-interp/.gitignore1
-rw-r--r--pocs/change-interp/Makefile7
-rw-r--r--pocs/change-interp/change-interp.c105
-rw-r--r--pocs/eclass/pax-utils.eclass218
-rw-r--r--pocs/elf-manipulate/.gitignore1
-rw-r--r--pocs/elf-manipulate/Makefile7
-rw-r--r--pocs/elf-manipulate/clear-dt-path.c80
-rw-r--r--pocs/elf-manipulate/parse-elf.c262
-rw-r--r--pocs/elf-manipulate/print-sections.c94
-rw-r--r--pocs/elf-manipulate/remove-ptpax.c103
-rwxr-xr-xpocs/ldd/ldd.py161
-rwxr-xr-xpocs/link-maps/link_map.py198
-rwxr-xr-xpocs/link-maps/link_map_test61
-rw-r--r--pocs/mangle-paxflags/.gitignore1
-rw-r--r--pocs/mangle-paxflags/Makefile7
-rw-r--r--pocs/mangle-paxflags/bad-mmap.c33
-rw-r--r--pocs/mangle-paxflags/mangle-paxflags.c266
-rwxr-xr-xpocs/mangle-paxflags/poc.sh20
-rw-r--r--pocs/paxmark-libs/Makefile.am94
-rwxr-xr-xpocs/paxmark-libs/autogen.sh7
-rw-r--r--pocs/paxmark-libs/configure.ac27
-rw-r--r--pocs/paxmark-libs/libmypax.c11
-rw-r--r--pocs/paxmark-libs/testdlpax.c17
-rw-r--r--pocs/paxmark-libs/testpax.c6
-rwxr-xr-xpocs/revdep-pax-ng/revdep-pax-ng500
25 files changed, 2287 insertions, 0 deletions
diff --git a/pocs/change-interp/.gitignore b/pocs/change-interp/.gitignore
new file mode 100644
index 0000000..2460008
--- /dev/null
+++ b/pocs/change-interp/.gitignore
@@ -0,0 +1 @@
+!Makefile
diff --git a/pocs/change-interp/Makefile b/pocs/change-interp/Makefile
new file mode 100644
index 0000000..c5d8fcb
--- /dev/null
+++ b/pocs/change-interp/Makefile
@@ -0,0 +1,7 @@
+all: change-interp
+
+%: %.c
+ gcc -o $@ $^ -lelf
+
+clean:
+ rm -rf change-interp
diff --git a/pocs/change-interp/change-interp.c b/pocs/change-interp/change-interp.c
new file mode 100644
index 0000000..3c21c26
--- /dev/null
+++ b/pocs/change-interp/change-interp.c
@@ -0,0 +1,105 @@
+
+#include <stdio.h> // printf
+#include <stdlib.h> // EXIT_FAILURE
+#include <error.h> // error
+#include <string.h> // strncpy
+
+#include <gelf.h> // elf_* and gelf_*
+
+#include <sys/types.h> // open
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h> // close
+
+
+int main( int argc, char *argv[])
+{
+ int fd, cmd;
+ char *scn_name;
+
+ Elf *elf;
+ GElf_Ehdr ehdr;
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ GElf_Dyn dyn;
+
+ if(argc != 3)
+ error(EXIT_FAILURE, 0, "Usage: %s <elf> <ld.so>", argv[0]);
+
+ if(elf_version(EV_CURRENT) == EV_NONE)
+ error(EXIT_FAILURE, 0, "Library out of date.");
+
+ if((fd = open(argv[1], O_RDWR)) == -1)
+ error(EXIT_FAILURE, 0, "Failed open file.");
+
+ if((elf = elf_begin(fd, ELF_C_RDWR_MMAP, elf)) != NULL)
+ {
+ if(gelf_getehdr(elf,&ehdr) != NULL)
+ {
+ scn = NULL;
+ while((scn = elf_nextscn(elf, scn)) != NULL)
+ {
+ gelf_getshdr(scn, &shdr);
+ scn_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
+
+ if(strcmp(scn_name, ".interp"))
+ continue;
+
+ printf("Section name: %s\n", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
+
+ if((data = elf_getdata(scn, data)) != NULL)
+ {
+ printf("Old ld.so: %s\n", (char *)data->d_buf);
+ printf("Data size: %zu\n", data->d_size);
+ /*
+ printf( "Data:\t\t%s\nType:\t\t%d\nSize:\t\t%lu\n"
+ "Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n",
+ (char *)data->d_buf,
+ data->d_type,
+ data->d_size,
+ data->d_off,
+ data->d_align,
+ data->d_version
+ );
+ */
+
+ if(data->d_size >= strlen(argv[2]))
+ {
+ memset(data->d_buf, 0, data->d_size);
+ strncpy(data->d_buf, argv[2], data->d_size);
+
+ if(!gelf_update_shdr(scn, &shdr))
+ {
+ elf_end(elf);
+ close(fd);
+ error(EXIT_FAILURE, 0, "\tELF ERROR: gelf_update_shdr(): %s", elf_errmsg(elf_errno()));
+ }
+ }
+ else
+ {
+ elf_end(elf);
+ close(fd);
+ error(EXIT_FAILURE, 0, "\tld.so path too long: max=%zu", data->d_size);
+ }
+
+ printf( "New ld.so: %s\n", (char *)data->d_buf);
+ /*
+ printf( "Data:\t\t%s\nType:\t\t%d\nSize:\t\t%lu\n"
+ "Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n",
+ (char *)data->d_buf,
+ data->d_type,
+ data->d_size,
+ data->d_off,
+ data->d_align,
+ data->d_version
+ );
+ */
+ }
+ }
+ }
+ }
+
+ elf_end(elf);
+ close(fd);
+}
diff --git a/pocs/eclass/pax-utils.eclass b/pocs/eclass/pax-utils.eclass
new file mode 100644
index 0000000..719e15b
--- /dev/null
+++ b/pocs/eclass/pax-utils.eclass
@@ -0,0 +1,218 @@
+# Copyright 1999-2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/eclass/pax-utils.eclass,v 1.22 2014/07/11 08:21:58 ulm Exp $
+
+# @ECLASS: pax-utils.eclass
+# @MAINTAINER:
+# The Gentoo Linux Hardened Team <hardened@gentoo.org>
+# @AUTHOR:
+# Original Author: Kevin F. Quinn <kevquinn@gentoo.org>
+# Modifications for bug #365825, @ ECLASS markup: Anthony G. Basile <blueness@gentoo.org>
+# Modifications for bug #431092: Anthony G. Basile <blueness@gentoo.org>
+# @BLURB: functions to provide pax markings
+# @DESCRIPTION:
+#
+# This eclass provides support for manipulating PaX markings on ELF binaries,
+# whether the system is using legacy PT_PAX markings or the newer XATTR_PAX.
+# The eclass wraps the use of paxctl-ng, paxctl, set/getattr and scanelf utilities,
+# deciding which to use depending on what's installed on the build host, and
+# whether we're working with PT_PAX, XATTR_PAX or both.
+#
+# To control what markings are made, set PAX_MARKINGS in /etc/portage/make.conf
+# to contain either "PT", "XT" or "none". The default is to attempt both
+# PT_PAX and XATTR_PAX.
+
+if [[ -z ${_PAX_UTILS_ECLASS} ]]; then
+_PAX_UTILS_ECLASS=1
+
+# @ECLASS-VARIABLE: PAX_MARKINGS
+# @DESCRIPTION:
+# Control which markings are made:
+# PT = PT_PAX markings, XT = XATTR_PAX markings
+# Default to PT markings.
+PAX_MARKINGS=${PAX_MARKINGS:="PT"}
+
+# @FUNCTION: pax-mark
+# @USAGE: <flags> {<ELF files>}
+# @RETURN: Shell true if we succeed, shell false otherwise
+# @DESCRIPTION:
+# Marks <ELF files> with provided PaX <flags>
+#
+# Flags are passed directly to the utilities unchanged
+#
+# p: disable PAGEEXEC P: enable PAGEEXEC
+# e: disable EMUTRAMP E: enable EMUTRAMP
+# 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.
+#
+# 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
+# the bug report.
+pax-mark() {
+
+ local f # loop over paxables
+ local flags # pax flags
+ local pt_fail=0 pt_failures="" # record PT_PAX failures
+ local xt_fail=0 xt_failures="" # record xattr PAX marking failures
+ local ret=0 # overal return code of this function
+
+ # Only the actual PaX flags and z are accepted
+ # 1. The leading '-' is optional
+ # 2. -C -c only make sense for paxctl, but are unnecessary
+ # because we progressively do -q -qc -qC
+ # 3. z is allowed for the default
+
+ flags="${1//[!zPpEeMmRrSs]}"
+ [[ "${flags}" ]] || return 0
+ shift
+
+ # z = default. For XATTR_PAX, the default is no xattr field at all
+ local dodefault=""
+ [[ "${flags//[!z]}" ]] && dodefault="yes"
+
+ if has PT ${PAX_MARKINGS}; then
+
+ #First try paxctl -> this might try to create/convert program headers
+ if type -p paxctl > /dev/null; then
+ einfo "PT PaX marking -${flags} with paxctl"
+ _pax_list_files einfo "$@"
+ for f in "$@"; do
+ # First, try modifying the existing PAX_FLAGS header
+ paxctl -q${flags} "${f}" && continue
+ # Second, try creating a PT_PAX header (works on ET_EXEC)
+ # Even though this is less safe, most exes need it, eg bug #463170
+ paxctl -qC${flags} "${f}" && continue
+ # Third, try stealing the (unused under PaX) PT_GNU_STACK header
+ paxctl -qc${flags} "${f}" && continue
+ pt_fail=1
+ pt_failures="${pt_failures} ${f}"
+ done
+
+ #Next try paxctl-ng -> this will not create/convert any program headers
+ elif type -p paxctl-ng > /dev/null && paxctl-ng -L ; then
+ einfo "PT PaX marking -${flags} with paxctl-ng"
+ flags="${flags//z}"
+ _pax_list_files einfo "$@"
+ for f in "$@"; do
+ [[ ${dodefault} == "yes" ]] && paxctl-ng -L -z "${f}"
+ [[ "${flags}" ]] || continue
+ paxctl-ng -L -${flags} "${f}" && continue
+ pt_fail=1
+ pt_failures="${pt_failures} ${f}"
+ done
+
+ #Finally fall back on scanelf
+ elif type -p scanelf > /dev/null && [[ ${PAX_MARKINGS} != "none" ]]; then
+ einfo "Fallback PaX marking -${flags} with scanelf"
+ _pax_list_files einfo "$@"
+ scanelf -Xxz ${flags} "$@"
+
+ #We failed to set PT_PAX flags
+ elif [[ ${PAX_MARKINGS} != "none" ]]; then
+ pt_failures="$*"
+ pt_fail=1
+ fi
+
+ if [[ ${pt_fail} == 1 ]]; then
+ elog "Failed to set PT_PAX markings -${flags} for:"
+ _pax_list_files elog ${pt_failures}
+ ret=1
+ fi
+ fi
+
+ if has XT ${PAX_MARKINGS}; then
+
+ flags="${flags//z}"
+
+ #First try paxctl-ng
+ if type -p paxctl-ng > /dev/null && paxctl-ng -l ; then
+ einfo "XT PaX marking -${flags} with paxctl-ng"
+ _pax_list_files einfo "$@"
+ for f in "$@"; do
+ [[ ${dodefault} == "yes" ]] && paxctl-ng -d "${f}"
+ [[ "${flags}" ]] || continue
+ paxctl-ng -l -${flags} "${f}" && continue
+ xt_fail=1
+ xt_failures="${tx_failures} ${f}"
+ done
+
+ #Next try setfattr
+ elif type -p setfattr > /dev/null; then
+ [[ "${flags//[!Ee]}" ]] || flags+="e" # bug 447150
+ einfo "XT PaX marking -${flags} with setfattr"
+ _pax_list_files einfo "$@"
+ for f in "$@"; do
+ [[ ${dodefault} == "yes" ]] && setfattr -x "user.pax.flags" "${f}"
+ setfattr -n "user.pax.flags" -v "${flags}" "${f}" && continue
+ xt_fail=1
+ xt_failures="${tx_failures} ${f}"
+ done
+
+ #We failed to set XATTR_PAX flags
+ elif [[ ${PAX_MARKINGS} != "none" ]]; then
+ xt_failures="$*"
+ xt_fail=1
+ fi
+
+ if [[ ${xt_fail} == 1 ]]; then
+ elog "Failed to set XATTR_PAX markings -${flags} for:"
+ _pax_list_files elog ${xt_failures}
+ ret=1
+ fi
+ fi
+
+ # [[ ${ret} == 1 ]] && elog "Executables may be killed by PaX kernels."
+
+ return ${ret}
+}
+
+# @FUNCTION: list-paxables
+# @USAGE: {<files>}
+# @RETURN: Subset of {<files>} which are ELF executables or shared objects
+# @DESCRIPTION:
+# Print to stdout all of the <files> that are suitable to have PaX flag
+# markings, i.e., filter out the ELF executables or shared objects from a list
+# of files. This is useful for passing wild-card lists to pax-mark, although
+# in general it is preferable for ebuilds to list precisely which ELFS are to
+# be marked. Often not all the ELF installed by a package need remarking.
+# @EXAMPLE:
+# pax-mark -m $(list-paxables ${S}/{,usr/}bin/*)
+list-paxables() {
+ file "$@" 2> /dev/null | grep -E 'ELF.*(executable|shared object)' | sed -e 's/: .*$//'
+}
+
+# @FUNCTION: host-is-pax
+# @RETURN: Shell true if the build process is PaX enabled, shell false otherwise
+# @DESCRIPTION:
+# This is intended for use where the build process must be modified conditionally
+# depending on whether the host is PaX enabled or not. It is not intedened to
+# determine whether the final binaries need PaX markings. Note: if procfs is
+# not mounted on /proc, this returns shell 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
+}
+
+fi
diff --git a/pocs/elf-manipulate/.gitignore b/pocs/elf-manipulate/.gitignore
new file mode 100644
index 0000000..2460008
--- /dev/null
+++ b/pocs/elf-manipulate/.gitignore
@@ -0,0 +1 @@
+!Makefile
diff --git a/pocs/elf-manipulate/Makefile b/pocs/elf-manipulate/Makefile
new file mode 100644
index 0000000..265cf25
--- /dev/null
+++ b/pocs/elf-manipulate/Makefile
@@ -0,0 +1,7 @@
+all: clear-dt-path parse-elf print-sections remove-ptpax
+
+%: %.c
+ gcc -o $@ $^ -lelf
+
+clean:
+ rm -rf clear-dt-path parse-elf print-sections remove-ptpax
diff --git a/pocs/elf-manipulate/clear-dt-path.c b/pocs/elf-manipulate/clear-dt-path.c
new file mode 100644
index 0000000..ae5ff9a
--- /dev/null
+++ b/pocs/elf-manipulate/clear-dt-path.c
@@ -0,0 +1,80 @@
+
+#include <stdio.h> // printf
+#include <stdlib.h> // EXIT_FAILURE
+#include <error.h> // error
+
+#include <gelf.h> // elf_* and gelf_*
+
+#include <sys/types.h> // open
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h> // close
+
+
+int main( int argc, char *argv[])
+{
+ int fd, cmd;
+ size_t i, n;
+ char *p;
+
+ Elf *arf, *elf;
+ GElf_Ehdr ehdr;
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ GElf_Dyn dyn;
+
+ if(elf_version(EV_CURRENT) == EV_NONE)
+ error(EXIT_FAILURE, 0, "Library out of date.");
+
+ if(argc != 2)
+ error(EXIT_FAILURE, 0, "Usage: %s <filename>", argv[0]);
+
+ if((fd = open(argv[1], O_RDONLY)) == -1)
+ error(EXIT_FAILURE, 0, "Failed open file.");
+
+
+ cmd = ELF_C_READ;
+
+ if((arf = elf_begin(fd, cmd, (Elf *)0)) == NULL)
+ error(EXIT_FAILURE, 0, "Failed open elf: %s", elf_errmsg ( -1));
+
+
+ while((elf = elf_begin(fd, cmd, arf)) != NULL)
+ {
+ if(gelf_getehdr(elf,&ehdr) != NULL)
+ {
+ scn = NULL;
+ while((scn = elf_nextscn(elf, scn)) != NULL)
+ {
+ gelf_getshdr(scn, &shdr);
+
+ if(shdr.sh_type != SHT_DYNAMIC)
+ continue;
+
+ printf("Section name: %s\n", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
+
+ data = NULL;
+ while((data = elf_getdata(scn, data)) != NULL)
+ {
+ if(data != NULL)
+ for( i=0; gelf_getdyn(data, i, &dyn) != NULL; i++)
+ {
+ if(dyn.d_tag == DT_RPATH)
+ printf("DT_RPATH found\n");
+ if(dyn.d_tag == DT_RUNPATH)
+ printf("DT_RUNPATH found\n");
+ }
+ }
+ }
+ }
+
+ cmd = elf_next(elf);
+ elf_end(elf);
+
+ }
+
+ elf_end(arf);
+
+ close(fd);
+}
diff --git a/pocs/elf-manipulate/parse-elf.c b/pocs/elf-manipulate/parse-elf.c
new file mode 100644
index 0000000..1ba8024
--- /dev/null
+++ b/pocs/elf-manipulate/parse-elf.c
@@ -0,0 +1,262 @@
+
+#include <stdio.h> // printf
+#include <stdlib.h> // EXIT_FAILURE
+#include <error.h> // error
+
+#include <gelf.h> // elf_* and gelf_*
+
+#include <sys/types.h> // open
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h> // close
+
+
+int main( int argc, char *argv[])
+{
+ int fd, cmd;
+ size_t i, n;
+ char *p;
+
+ Elf *arf, *elf;
+ Elf_Arhdr *arhdr;
+ GElf_Ehdr ehdr;
+ GElf_Phdr phdr;
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+
+ if(elf_version(EV_CURRENT) == EV_NONE)
+ error(EXIT_FAILURE, 0, "Library out of date.");
+
+ if(argc != 2)
+ error(EXIT_FAILURE, 0, "Usage: %s <filename>", argv[0]);
+
+ if((fd = open(argv[1], O_RDONLY)) == -1)
+ error(EXIT_FAILURE, 0, "Failed open file.");
+
+
+ cmd = ELF_C_READ;
+
+ if((arf = elf_begin(fd, cmd, (Elf *)0)) == NULL)
+ error(EXIT_FAILURE, 0, "Failed open elf: %s", elf_errmsg ( -1));
+
+
+ switch(elf_kind(arf))
+ {
+ case ELF_K_AR:
+ printf("This is an archive.\n");
+ arhdr = elf_getarhdr(arf);
+ /*
+ printf("\n ********** ARCHIVE HEADER ********** \n");
+ printf( "Name:\t\t%s\nDate:\t\t%lu\nUID:\t\t%d\nGID:\t\t%d\n"
+ "Mode:\t\t%d\n:Size:\t\t%lu\nRaw:\t\t%s\n\n ",
+ arhdr->ar_name,
+ arhdr->ar_date,
+ arhdr->ar_uid,
+ arhdr->ar_gid,
+ arhdr->ar_mode,
+ arhdr->ar_size,
+ arhdr->ar_rawname
+ );
+ */
+ break;
+ case ELF_K_COFF:
+ printf("This is a COFF.\n"); break;
+ case ELF_K_ELF:
+ printf("This is an ELF.\n"); break;
+ default:
+ case ELF_K_NONE:
+ printf("This is an unknown.\n"); break;
+ }
+
+ while((elf = elf_begin(fd, cmd, arf)) != NULL)
+ {
+ if(gelf_getehdr(elf,&ehdr) != NULL)
+ {
+ printf("\n ********** HEADER ********** \n");
+ switch(ehdr.e_type)
+ {
+ case ET_NONE: printf("This is a ET_NONE Type.\n"); break;
+ case ET_REL: printf("This is a ET_REL Type.\n"); break;
+ case ET_EXEC: printf("This is a ET_EXEC Type.\n"); break;
+ case ET_DYN: printf("This is a ET_DYN Type.\n"); break;
+ case ET_CORE: printf("This is a ET_CORE Type.\n"); break;
+ case ET_NUM: printf("This is a ET_NUM Type.\n"); break;
+ case ET_LOOS: printf("This is a ET_LOOS Type.\n"); break;
+ case ET_HIOS: printf("This is a ET_HIOS Type.\n"); break;
+ case ET_LOPROC: printf("This is a ET_LOPROC Type.\n"); break;
+ case ET_HIPROC: printf("This is a ET_HIPROC Type.\n"); break;
+ }
+
+ printf( "Ident:\t\t%d\nType:\t\t%d\nMachine:\t%d\nVersion:\t%d\n"
+ "Entry:\t\t%lu\nPHoff:\t\t%lu\nSHoff:\t\t%lu\n"
+ "Flags:\t\t%d\nEHSize:\t\t%d\nPHentsize:\t%d\n"
+ "PHnum:\t\t%d\nSHentsize\t%d\nSHnum\t\t%d\nSHstrndx\t%d\n\n",
+ ehdr.e_ident[EI_NIDENT],
+ ehdr.e_type,
+ ehdr.e_machine,
+ ehdr.e_version,
+
+ ehdr.e_entry,
+ ehdr.e_phoff,
+ ehdr.e_shoff,
+
+ ehdr.e_flags,
+ ehdr.e_ehsize,
+ ehdr.e_phentsize,
+
+ ehdr.e_phnum,
+ ehdr.e_shentsize,
+ ehdr.e_shnum,
+ ehdr.e_shstrndx
+ );
+
+ elf_getphdrnum(elf, &n);
+ printf("NOTE: elf_getphdrnum=%lu ehdr.e_phnum=%d\n", n, ehdr.e_phnum );
+
+ for (i = 0; i < ehdr.e_phnum; ++i)
+ {
+ if(gelf_getphdr(elf, i, &phdr) != &phdr)
+ error(EXIT_FAILURE, 0, "Failed getphdr: %s", elf_errmsg ( -1));
+
+ printf("\n ********** PROGRAM HEADER TABLE ENTRY ********** \n");
+ switch(phdr.p_type)
+ {
+ case PT_NULL: printf("This is a PT_NULL type\n"); break;
+ case PT_LOAD: printf("This is a PT_LOAD type\n"); break;
+ case PT_DYNAMIC: printf("This is a PT_DYNAMIC type\n"); break;
+ case PT_INTERP: printf("This is a PT_INTERP type\n"); break;
+ case PT_NOTE: printf("This is a PT_NOTE type\n"); break;
+ case PT_SHLIB: printf("This is a PT_SHLIB type\n"); break;
+ case PT_PHDR: printf("This is a PT_PHDR type\n"); break;
+ case PT_TLS: printf("This is a PT_TLS type\n"); break;
+ case PT_NUM: printf("This is a PT_NUM type\n"); break;
+ case PT_LOOS: printf("This is a PT_LOOS type\n"); break;
+ case PT_GNU_EH_FRAME: printf("This is a PT_GNU_EH_FRAME type\n"); break;
+ case PT_GNU_STACK: printf("This is a PT_GNU_STACK type\n"); break;
+ case PT_GNU_RELRO: printf("This is a PT_GNU_RELRO type\n"); break;
+ case PT_PAX_FLAGS: printf("This is a PT_PAX_FLAGS type\n"); break;
+ case PT_LOSUNW: printf("This is a PT_LOSUNW type\n"); break;
+ //case PT_SUNWBSS: printf("This is a PT_SUNWBSS type\n"); break;
+ case PT_SUNWSTACK: printf("This is a PT_SUNWSTACK type\n"); break;
+ case PT_HISUNW: printf("This is a PT_HISUNW type\n"); break;
+ //case PT_HIOS: printf("This is a PT_HIOS type\n"); break;
+ case PT_LOPROC: printf("This is a PT_LOPROC type\n"); break;
+ case PT_HIPROC: printf("This is a PT_HIPROC type\n"); break;
+ }
+
+ printf("Flags:\t\t");
+ if( phdr.p_flags & PF_R ) printf("R");
+ if( phdr.p_flags & PF_W ) printf("W");
+ if( phdr.p_flags & PF_X ) printf("X");
+ printf("\n");
+
+ printf( "Type:\t\t%d\nFlags:\t\t%d\nOffset:\t\t%lu\nVaddr:\t\t%lu\nPaddr:\t\t%lu\n"
+ "Filesz:\t\t%lu\nMemsz:\t\t%lu\nAlign:\t\t%lu\n",
+ phdr.p_type,
+ phdr.p_flags,
+ phdr.p_offset,
+ phdr.p_vaddr,
+ phdr.p_paddr,
+ phdr.p_filesz,
+ phdr.p_memsz,
+ phdr.p_align
+ );
+
+ printf("\n\n");
+ }
+
+ scn = NULL;
+ while((scn = elf_nextscn(elf, scn)) != NULL)
+ {
+ gelf_getshdr(scn, &shdr);
+ printf("\n ********** SECTION ********** \n");
+
+ printf("Section name: %s\n", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
+
+ switch(shdr.sh_type)
+ {
+ case SHT_DYNAMIC: printf("This is a SHT_DYNAMIC type\n"); break;
+ case SHT_DYNSYM: printf("This is a SHT_DYNSYM type\n"); break;
+ case SHT_HASH: printf("This is a SHT_HASH type\n"); break;
+ case SHT_NOBITS: printf("This is a SHT_NOBITS type\n"); break;
+ case SHT_NOTE: printf("This is a SHT_NOTE type\n"); break;
+ case SHT_NULL: printf("This is a SHT_NULL type\n"); break;
+ case SHT_PROGBITS: printf("This is a SHT_PROGBITS type\n"); break;
+ case SHT_REL: printf("This is a SHT_REL type\n"); break;
+ case SHT_RELA: printf("This is a SHT_RELA type\n"); break;
+ case SHT_STRTAB: printf("This is a SHT_STRTAB type\n"); break;
+ case SHT_SYMTAB: printf("This is a SHT_SYMTAB type\n"); break;
+ default: printf("This is an unknown section type\n"); break;
+ }
+
+ printf(
+ "Name:\t\t%d\nType:\t\t%d\nFlags:\t\t%lu\n"
+ "Addr:\t\t%lu\nOffset:\t\t%lu\nSize:\t\t%lu\n"
+ "Link:\t\t%d\nInfo:\t\t%d\nAddrAlign:\t%lu\nEntsize:\t%lu\n",
+ shdr.sh_name,
+ shdr.sh_type,
+ shdr.sh_flags,
+ shdr.sh_addr,
+ shdr.sh_offset,
+ shdr.sh_size,
+ shdr.sh_link,
+ shdr.sh_info,
+ shdr.sh_addralign,
+ shdr.sh_entsize
+ );
+
+ if(shdr.sh_type == SHT_NOBITS)
+ continue;
+
+ data = NULL;
+ while((data = elf_getdata(scn, data)) != NULL)
+ {
+ printf("\n ***** DATA ***** \n");
+ printf( "Data:\t\t%s\nType:\t\t%d\nSize:\t\t%lu\n"
+ "Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n",
+ (char *)data->d_buf,
+ data->d_type,
+ data->d_size,
+ data->d_off,
+ data->d_align,
+ data->d_version
+ );
+ }
+ printf("\n\n");
+ }
+
+
+ //Print out data in .shstrtab section
+ if((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL)
+ error(EXIT_FAILURE, 0, "getscn() failed: %s.", elf_errmsg(-1));
+
+ if(gelf_getshdr( scn, &shdr ) != &shdr)
+ error(EXIT_FAILURE, 0, "getshdr(ehdr.e_shstrndx) failed: %s.", elf_errmsg(-1));
+
+ printf(" .shstrab: size=%jd\n", (uintmax_t)shdr.sh_size);
+
+ data = NULL;
+ n = 0;
+ while( n < shdr.sh_size && (data = elf_getdata(scn, data)) != NULL )
+ {
+ p = (char *)data->d_buf ;
+ while(p < (char *)data->d_buf + data->d_size)
+ {
+ printf("%c", *p);
+ n++;
+ p++;
+ if(!(n%16)) printf("\n");
+ }
+ }
+ printf("\n");
+
+ }
+ cmd = elf_next(elf);
+ elf_end(elf);
+ }
+
+ elf_end(arf);
+
+ close(fd);
+}
diff --git a/pocs/elf-manipulate/print-sections.c b/pocs/elf-manipulate/print-sections.c
new file mode 100644
index 0000000..ba8d4ee
--- /dev/null
+++ b/pocs/elf-manipulate/print-sections.c
@@ -0,0 +1,94 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+
+#include <gelf.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+int main( int argc, char *argv[])
+{
+ int fd, cmd;
+ size_t i;
+ char shname[1024];
+
+ Elf *arf, *elf;
+ GElf_Ehdr ehdr;
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+
+ if(elf_version(EV_CURRENT) == EV_NONE)
+ error(EXIT_FAILURE, 0, "Library out of date.");
+
+ if(argc != 2)
+ error(EXIT_FAILURE, 0, "Usage: %s <filename>", argv[0]);
+
+ if((fd = open(argv[1], O_RDONLY)) == -1)
+ error(EXIT_FAILURE, 0, "Failed open file.");
+
+
+ cmd = ELF_C_READ;
+
+ if((arf = elf_begin(fd, cmd, (Elf *)0)) == NULL)
+ error(EXIT_FAILURE, 0, "Failed open elf: %s", elf_errmsg ( -1));
+
+
+ while((elf = elf_begin(fd, cmd, arf)) != NULL)
+ {
+ if(gelf_getehdr(elf,&ehdr) != NULL)
+ {
+ scn = NULL;
+ while((scn = elf_nextscn(elf, scn)) != NULL)
+ {
+ gelf_getshdr(scn, &shdr);
+
+ strcpy(shname, elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
+ printf("%s\n", shname);
+
+ /*
+ if( !strcmp(shname, ".bss") || !strcmp(shname, ".tbss") )
+ continue;
+ */
+ if(shdr.sh_type == SHT_NOBITS)
+ continue;
+
+ data = NULL;
+ while((data = elf_getdata(scn, data)) != NULL)
+ {
+ printf( "Type:\t\t%d\nSize:\t\t%lu\n"
+ "Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n",
+ data->d_type,
+ data->d_size,
+ data->d_off,
+ data->d_align,
+ data->d_version
+ );
+
+ for(i = 0; i < (int)data->d_size; i++)
+ {
+ printf("%2x ", (uint8_t)((char *)(data->d_buf))[i]);
+ if((i+1)%16 == 0)
+ printf("\n");
+ }
+ }
+
+ printf("\n\n");
+ }
+ }
+
+ cmd = elf_next(elf);
+ elf_end(elf);
+
+ }
+
+ elf_end(arf);
+
+ close(fd);
+}
diff --git a/pocs/elf-manipulate/remove-ptpax.c b/pocs/elf-manipulate/remove-ptpax.c
new file mode 100644
index 0000000..ba441a5
--- /dev/null
+++ b/pocs/elf-manipulate/remove-ptpax.c
@@ -0,0 +1,103 @@
+/*
+ remove-ptpax.c: this file is part of the elfix package
+ Copyright (C) 2013 Anthony G. Basile
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <gelf.h>
+
+#ifndef PT_PAX_FLAGS
+ #define PT_PAX_FLAGS 0x65041580
+#endif
+
+int
+remove_ptpax(int fd)
+{
+ Elf *elf;
+ GElf_Phdr phdr;
+ size_t i, phnum;
+
+ if(elf_version(EV_CURRENT) == EV_NONE)
+ {
+ printf("\tELF ERROR: Library out of date.\n");
+ return EXIT_FAILURE;
+ }
+
+ if((elf = elf_begin(fd, ELF_C_RDWR_MMAP, NULL)) == NULL)
+ {
+ printf("\tELF ERROR: elf_begin() fail: %s\n", elf_errmsg(elf_errno()));
+ return EXIT_FAILURE;
+ }
+
+ if(elf_kind(elf) != ELF_K_ELF)
+ {
+ elf_end(elf);
+ printf("\tELF ERROR: elf_kind() fail: this is not an elf file.\n");
+ return EXIT_FAILURE;
+ }
+
+ elf_getphdrnum(elf, &phnum);
+
+ for(i=0; i<phnum; i++)
+ {
+ if(gelf_getphdr(elf, i, &phdr) != &phdr)
+ {
+ elf_end(elf);
+ printf("\tELF ERROR: gelf_getphdr(): %s\n", elf_errmsg(elf_errno()));
+ return EXIT_FAILURE;
+ }
+
+ if(phdr.p_type == PT_PAX_FLAGS)
+ {
+ phdr.p_type = PT_NULL;
+ if(!gelf_update_phdr(elf, i, &phdr))
+ {
+ elf_end(elf);
+ printf("\tELF ERROR: gelf_update_phdr(): %s", elf_errmsg(elf_errno()));
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ elf_end(elf);
+ return EXIT_SUCCESS;
+}
+
+
+int
+main( int argc, char *argv[])
+{
+ int fd;
+
+ if(argc != 2)
+ {
+ fprintf(stderr, "Usage: %s <filename>\n", argv[0]) ;
+ exit(EXIT_SUCCESS);
+ }
+
+ if((fd = open(argv[1], O_RDWR)) < 0)
+ {
+ printf("\topen(O_RDWR) failed: cannot change PT_PAX flags\n");
+ exit(EXIT_FAILURE);
+ }
+ else
+ exit(remove_ptpax(fd));
+
+}
diff --git a/pocs/ldd/ldd.py b/pocs/ldd/ldd.py
new file mode 100755
index 0000000..447614e
--- /dev/null
+++ b/pocs/ldd/ldd.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+
+import os, sys
+import re, glob
+from optparse import OptionParser
+
+from elftools import __version__
+from elftools.common.exceptions import ELFError
+from elftools.common.py3compat import bytes2str
+from elftools.elf.elffile import ELFFile
+from elftools.elf.dynamic import DynamicSection
+from elftools.elf.descriptions import describe_ei_class
+
+class ReadElf(object):
+ def __init__(self, file):
+ """ file: stream object with the ELF file to read
+ """
+ self.elffile = ELFFile(file)
+
+
+ def elf_class(self):
+ """ Return the ELF Class
+ """
+ header = self.elffile.header
+ e_ident = header['e_ident']
+ return describe_ei_class(e_ident['EI_CLASS'])
+
+ def dynamic_dt_needed(self):
+ """ Return a list of the DT_NEEDED
+ """
+ dt_needed = []
+ for section in self.elffile.iter_sections():
+ if not isinstance(section, DynamicSection):
+ continue
+
+ for tag in section.iter_tags():
+ if tag.entry.d_tag == 'DT_NEEDED':
+ dt_needed.append(bytes2str(tag.needed))
+ #sys.stdout.write('\t%s\n' % bytes2str(tag.needed) )
+
+ return dt_needed
+
+
+def ldpaths(ld_so_conf='/etc/ld.so.conf'):
+ """ Generate paths to search for libraries from ld.so.conf. Recursively
+ parse included files. We assume correct syntax and the ld.so.cache
+ is in sync with ld.so.conf.
+ """
+ with open(ld_so_conf, 'r') as path_file:
+ lines = path_file.read()
+ lines = re.sub('#.*', '', lines) # kill comments
+ lines = list(re.split(':+|\s+|\t+|\n+|,+', lines)) # man 8 ldconfig
+
+ paths = []
+ include_globs = []
+ for i in range(0,len(lines)):
+ if lines[i] == '':
+ continue
+ if lines[i] == 'include':
+ f = lines[i + 1]
+ include_globs.append(f)
+ continue
+ if lines[i] not in include_globs:
+ real_path = os.path.realpath(lines[i])
+ if os.path.exists(real_path):
+ paths.append(real_path)
+
+ include_files = []
+ for g in include_globs:
+ include_files = include_files + glob.glob('/etc/' + g)
+ for c in include_files:
+ paths = paths + ldpaths(os.path.realpath(c))
+
+ paths = list(set(paths))
+ paths.sort()
+ return paths
+
+
+# We cache the dependencies for speed. The structure is
+# { ELFClass : { SONAME : library, ... }, ELFClass : ... }
+cache = {}
+
+def dynamic_dt_needed_paths( dt_needed, eclass, paths):
+ """ Search library paths for the library file corresponding
+ to the given DT_NEEDED and ELF Class.
+ """
+ global cache
+ if not eclass in cache:
+ cache[eclass] = {}
+
+ dt_needed_paths = {}
+ for n in dt_needed:
+ if n in cache[eclass].keys():
+ dt_needed_paths[n] = cache[eclass][n]
+ else:
+ for p in paths:
+ lib = p + os.sep + n
+ if os.path.exists(lib):
+ with open(lib, 'rb') as file:
+ try:
+ readlib = ReadElf(file)
+ if eclass == readlib.elf_class():
+ dt_needed_paths[n] = lib
+ cache[eclass][n] = lib
+ except ELFError as ex:
+ sys.stderr.write('ELF error: %s\n' % ex)
+ sys.exit(1)
+
+ return dt_needed_paths
+
+
+def all_dynamic_dt_needed_paths(f, paths):
+ """ Return a dictionary of all the DT_NEEDED => Library Paths for
+ a given ELF file obtained by recursively following linkage.
+ """
+ with open(f, 'rb') as file:
+ try:
+ readelf = ReadElf(file)
+ eclass = readelf.elf_class()
+ # This needs to be iterated until we traverse the entire linkage tree
+ dt_needed = readelf.dynamic_dt_needed()
+ dt_needed_paths = dynamic_dt_needed_paths(dt_needed, eclass, paths)
+ for n, lib in dt_needed_paths.items():
+ dt_needed_paths = dict(all_dynamic_dt_needed_paths(lib, paths), **dt_needed_paths)
+ except ELFError as ex:
+ sys.stderr.write('ELF error: %s\n' % ex)
+ sys.exit(1)
+
+ return dt_needed_paths
+
+
+SCRIPT_DESCRIPTION = 'Print shared library dependencies'
+VERSION_STRING = '%%prog: based on pyelftools %s' % __version__
+
+def main():
+ optparser = OptionParser(
+ usage='usage: %prog <elf-file>',
+ description=SCRIPT_DESCRIPTION,
+ add_help_option=False, # -h is a real option of readelf
+ prog='ldd.py',
+ version=VERSION_STRING)
+ optparser.add_option('-h', '--help',
+ action='store_true', dest='help',
+ help='Display this information')
+ options, args = optparser.parse_args()
+
+ if options.help or len(args) == 0:
+ optparser.print_help()
+ sys.exit(0)
+
+ paths = ldpaths()
+
+ for f in args:
+ if len(args) > 1:
+ sys.stdout.write('%s : \n' % f)
+ all_dt_needed_paths = all_dynamic_dt_needed_paths(f, paths)
+ for n, lib in all_dt_needed_paths.items():
+ sys.stdout.write('\t%s => %s\n' % (n, lib))
+
+if __name__ == '__main__':
+ main()
diff --git a/pocs/link-maps/link_map.py b/pocs/link-maps/link_map.py
new file mode 100755
index 0000000..5b0e822
--- /dev/null
+++ b/pocs/link-maps/link_map.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+#
+# LinkMap.py: this file is part of the elfix package
+# Copyright (C) 2011 Anthony G. Basile
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import re
+import portage
+
+class LinkMap:
+
+ def __init__(self):
+ """ Put all the NEEDED.ELF.2 files for all installed packages
+ into a dictionary of the form
+
+ { pkg : line_from_NEEDED.ELF.2, ... }
+
+ where the line has the following form:
+
+ echo "${arch:3};${obj};${soname};${rpath};${needed}" >> \
+ "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
+
+ See /usr/lib/portage/bin/misc-functions.sh ~line 520
+ """
+
+ vardb = portage.db[portage.root]["vartree"].dbapi
+
+ self.pkgs = []
+ self.pkgs_needed = {}
+
+ for pkg in vardb.cpv_all():
+ needed = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip()
+ if needed: # Some packages have no NEEDED.ELF.2
+ self.pkgs.append(pkg)
+ for line in re.split('\n', needed):
+ self.pkgs_needed.setdefault(pkg,[]).append(re.split(';', line))
+
+
+ def get_object_needed(self):
+ """ Return object_needed dictionary which has structure
+
+ {
+ abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+ abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+ ....
+ }
+
+ Here the sonames were obtained from the ELF object by scanelf -nm
+ (like readelf -d) during emerge.
+ """
+ object_needed = {}
+
+ for pkg in self.pkgs:
+ for link in self.pkgs_needed[pkg]:
+ abi = link[0]
+ elf = link[1]
+ sonames = re.split(',', link[4])
+ object_needed.setdefault(abi,{}).update({elf:sonames})
+
+ return object_needed
+
+
+ def get_libraries(self):
+ """ Return library2soname dictionary which has structure
+
+ { full_path_to_library : (soname, abi), ... }
+
+ and its inverse which has structure
+
+ { (soname, abi) : full_path_to_library, ... }
+ """
+ library2soname = {}
+ soname2library = {}
+
+ for pkg in self.pkgs:
+ for link in self.pkgs_needed[pkg]:
+ abi = link[0]
+ elf = link[1]
+ soname = link[2]
+ if soname: #no soname => executable
+ library2soname[elf] = (soname,abi)
+ soname2library[(soname,abi)] = elf
+
+ return ( library2soname, soname2library )
+
+
+ def get_soname_needed(self, object_needed, library2soname ):
+ """ Return soname_needed dictionary which has structure:
+
+ {
+ abi1: { soname: [ soname1, soname2, ... ], .... },
+ abi2: { soname: [ soname1, soname2, ... ], .... },
+ }
+
+ Here the soname1, soname2,... were obtained from soname's corresponding
+ ELF object by scanelf -n during emerge.
+ """
+ soname_needed = {}
+
+ for abi in object_needed:
+ for elf in object_needed[abi]:
+ try:
+ (soname, abi_check) = library2soname[elf]
+ assert abi == abi_check # We should get the same abi associated with the soname
+ soname_needed.setdefault(abi,{}).update({soname:object_needed[abi][elf]})
+ except KeyError:
+ continue # no soname, its probably an executable
+
+ return soname_needed
+
+
+ def expand_linkings(self, object_needed, soname2library):
+ """ Expands the object_needed dictionary which has structure
+
+ {
+ abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+ abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+ ....
+ }
+
+ such that the soname's are traced all the way to the end of
+ the link chain. Here the sonames should be the same as those
+ obtained from the ELF object by ldd.
+ """
+ for abi in object_needed:
+ for elf in object_needed[abi]:
+ while True:
+ found_new_soname = False
+ for so in object_needed[abi][elf]: # For all the first links ...
+ try:
+ for sn in object_needed[abi][soname2library[(so,abi)]]: # go to the next links ...
+ if sn in object_needed[abi][elf]: # skip if already included ...
+ continue
+ if not (sn,abi) in soname2library: # skip if vdso ...
+ continue
+
+ # This appends to the object_needed and soname_needed lists. No copy was
+ # done so its the same lists in memory for both, and its modified for both.
+
+ object_needed[abi][elf].append(sn) # otherwise collapse it back into
+ found_new_soname = True # first links of the chain.
+
+ except KeyError: # Not all nodes in the chain have a next node
+ continue
+
+ if not found_new_soname: # We're done, that last iteration found
+ break # no new nodes
+
+
+ def get_object_reverse_linkings(self, object_linkings):
+ """ Return object_reverse_linkings dictionary which has structure
+
+ {
+ abi1 : { soname : [ path_to_elf1, path_to_elf2, ... ], ... },
+ abi2 : { soname : [ path_to_elf3, path_to_elf4, ... ], ... },
+ ....
+ }
+ """
+ object_reverse_linkings = {}
+
+ for abi in object_linkings:
+ for elf in object_linkings[abi]:
+ for soname in object_linkings[abi][elf]:
+ object_reverse_linkings.setdefault(abi,{}).setdefault(soname,[]).append(elf)
+
+ return object_reverse_linkings
+
+
+ def get_maps(self):
+ """ Generate the full forward and reverse links using the above functions """
+
+ # After get_object_needed() and get_soname_needed(), both object_linkings and
+ # soname_linkings are only one step into the entire link chain.
+
+ object_linkings = self.get_object_needed()
+ ( library2soname, soname2library ) = self.get_libraries()
+ soname_linkings = self.get_soname_needed( object_linkings, library2soname )
+
+ # After the appending in expand_linkings(), forward_linkings and soname_linkings
+ # have been extended through the entire chain of linking. expand_linkings() is
+ # a "side-effect" function, so we note it here.
+ self.expand_linkings( soname_linkings, soname2library )
+ object_reverse_linkings = self.get_object_reverse_linkings( object_linkings )
+
+ return ( object_linkings, object_reverse_linkings, library2soname, soname2library )
+
diff --git a/pocs/link-maps/link_map_test b/pocs/link-maps/link_map_test
new file mode 100755
index 0000000..9a1af8e
--- /dev/null
+++ b/pocs/link-maps/link_map_test
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# link_map_test: this file is part of the elfix package
+# Copyright (C) 2011 Anthony G. Basile
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+from link_map import LinkMap
+
+def main():
+
+ # Run as root to be able to real all files
+ uid = os.getuid()
+ if uid != 0:
+ print('RUN AS ROOT: cannot read all flags')
+ sys.exit(0)
+
+ link_map = LinkMap()
+ ( object_linkings, object_reverse_linkings, library2soname, soname2library ) = link_map.get_maps()
+
+ layout = "{0:<30} => {1:<30}"
+
+ #Print out all ELF objects and the NEEDED sonames and full library paths
+ for abi in object_linkings:
+ for elf in object_linkings[abi]:
+ sonames = object_linkings[abi][elf]
+ print('%s: %s' % (abi,elf))
+ for soname in sorted(object_linkings[abi][elf]):
+ try:
+ print('\t%s' % layout.format(soname, soname2library[(soname,abi)]))
+ except KeyError:
+ print('\t%s' % layout.format(soname, '***' ))
+ print('')
+
+ # Print out all ELF objects and the NEEDED sonames and full library paths
+ for abi in object_linkings:
+ for soname in object_reverse_linkings[abi]:
+ try:
+ print('%s: %s' % (abi, layout.format(soname, soname2library[(soname,abi)])))
+ except KeyError:
+ print('%s: %s' % (abi, layout.format(soname, '***' )))
+ for elf in sorted(object_reverse_linkings[abi][soname]):
+ print('\t%s' % elf)
+ print('')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/pocs/mangle-paxflags/.gitignore b/pocs/mangle-paxflags/.gitignore
new file mode 100644
index 0000000..2460008
--- /dev/null
+++ b/pocs/mangle-paxflags/.gitignore
@@ -0,0 +1 @@
+!Makefile
diff --git a/pocs/mangle-paxflags/Makefile b/pocs/mangle-paxflags/Makefile
new file mode 100644
index 0000000..9c2789d
--- /dev/null
+++ b/pocs/mangle-paxflags/Makefile
@@ -0,0 +1,7 @@
+all: bad-mmap mangle-paxflags
+
+%: %.c
+ gcc -o $@ $^ -lelf
+
+clean:
+ rm -rf bad-mmap mangle-paxflags
diff --git a/pocs/mangle-paxflags/bad-mmap.c b/pocs/mangle-paxflags/bad-mmap.c
new file mode 100644
index 0000000..04df26d
--- /dev/null
+++ b/pocs/mangle-paxflags/bad-mmap.c
@@ -0,0 +1,33 @@
+/*
+ bad-mmap.c: create 4k anonymous mmap with RWX protection
+ Copyright (C) 2011 Anthony G. Basile
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+
+int
+main()
+{
+ if( mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) != MAP_FAILED )
+ printf("mmap(): succeeded\n");
+ else
+ printf("mmap(): %s\n", strerror(errno));
+ return 0;
+}
diff --git a/pocs/mangle-paxflags/mangle-paxflags.c b/pocs/mangle-paxflags/mangle-paxflags.c
new file mode 100644
index 0000000..5e41cd1
--- /dev/null
+++ b/pocs/mangle-paxflags/mangle-paxflags.c
@@ -0,0 +1,266 @@
+/*
+ mangle-paxflags.c: check and optionally remove EI_PAX and/or PT_PAX_FLAGS
+ Copyright (C) 2011 Anthony G. Basile
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <libgen.h>
+
+#include <gelf.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+// From chpax.h
+#define EI_PAX 14 // Index in e_ident[] where to read flags
+#define HF_PAX_PAGEEXEC 1 // 0: Paging based non-exec pages
+#define HF_PAX_EMUTRAMP 2 // 0: Emulate trampolines
+#define HF_PAX_MPROTECT 4 // 0: Restrict mprotect()
+#define HF_PAX_RANDMMAP 8 // 0: Randomize mmap() base
+#define HF_PAX_RANDEXEC 16 // 1: Randomize ET_EXEC base
+#define HF_PAX_SEGMEXEC 32 // 0: Segmentation based non-exec pages
+
+#define PRINT(E,F,I) printf("%s:\t%s\n", #E, E&F? (I? "enabled" : "disabled") : (I? "disabled" : "enabled"));
+#define SPRINT(E,F,A,B) printf("%c", E&F? A : B);
+#define CPRINT(N,P) case P: printf("%d: %s\n", (int)N, #P); break
+#define FPRINT(N,D,F,A,B) printf("%c", N&F? (D&F? '*' : B) : (D&F? A : '-'))
+
+
+void
+print_help(char *v)
+{
+ printf(
+ "Program Name : %s\n"
+ "Description : Check for, or conditionally remove, executable flag from PT_GNU_STACK\n\n"
+ "Usage : %s [-e] [-p] [-v] [-q] ELFfile | [-h]\n"
+ "options : Print out EI_PAX and PT_PAX_FLAGS information\n"
+ " : -e Set all EI_PAX flags to least secure setting, pEmrXs\n"
+ " : -p Remove PT_PAX_FLAGS program header\n"
+ " : -v Verbose expanation of flags (rather than short list)\n"
+ " : -q Surpress all output to stdout (negates verbose)\n"
+ " : -h Print out this help\n",
+ basename(v),
+ basename(v)
+ );
+
+ exit(EXIT_SUCCESS);
+}
+
+
+char *
+parse_cmd_args(int c, char *v[], int *flag_ei_pax, int *flag_pt_pax_flags, int *verbose, int *quiet)
+{
+ int i, oc;
+
+ if((c != 2)&&(c != 3)&&(c != 4))
+ error(EXIT_FAILURE, 0, "Usage: %s {[-e] [-p] [-v] [-q] ELFfile | [-h]}", v[0]);
+
+ *flag_ei_pax = 0;
+ *flag_pt_pax_flags = 0;
+ *verbose = 0;
+ *quiet = 0;
+
+ while((oc = getopt(c, v,":epvqh")) != -1)
+ switch(oc)
+ {
+ case 'e':
+ *flag_ei_pax = 1;
+ break ;
+ case 'p':
+ *flag_pt_pax_flags = 1;
+ break;
+ case 'v':
+ *verbose = 1;
+ break;
+ case 'q':
+ *quiet = 1;
+ break;
+ case 'h':
+ print_help(v[0]);
+ break;
+ case '?':
+ default:
+ error(EXIT_FAILURE, 0, "option -%c is invalid: ignored.", optopt ) ;
+ }
+
+ return v[optind] ;
+}
+
+
+int
+main( int argc, char *argv[])
+{
+ int fd, found_ei_pax;
+ int flag_ei_pax, flag_pt_pax_flags, verbose, quiet;
+ char *f_name;
+ size_t i, phnum;
+
+ Elf *elf;
+ GElf_Ehdr ehdr;
+ GElf_Phdr phdr;
+
+ f_name = parse_cmd_args(argc, argv, &flag_ei_pax, &flag_pt_pax_flags, &verbose, &quiet);
+
+ if(elf_version(EV_CURRENT) == EV_NONE)
+ error(EXIT_FAILURE, 0, "Library out of date.");
+
+ if( flag_ei_pax || flag_pt_pax_flags )
+ {
+ if((fd = open(f_name, O_RDWR)) < 0)
+ error(EXIT_FAILURE, 0, "open() fail.");
+ if((elf = elf_begin(fd, ELF_C_RDWR_MMAP, NULL)) == NULL)
+ error(EXIT_FAILURE, 0, "elf_begin() fail: %s", elf_errmsg(elf_errno()));
+ }
+ else
+ {
+ if((fd = open(f_name, O_RDONLY)) < 0)
+ error(EXIT_FAILURE, 0, "open() fail.");
+ if((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+ error(EXIT_FAILURE, 0, "elf_begin() fail: %s", elf_errmsg(elf_errno()));
+ }
+
+ if(elf_kind(elf) != ELF_K_ELF)
+ error(EXIT_FAILURE, 0, "elf_kind() fail: this is not an elf file.");
+
+ if(gelf_getehdr(elf,&ehdr) != &ehdr)
+ error(EXIT_FAILURE, 0, "gelf_getehdr(): %s", elf_errmsg(elf_errno()));
+
+ found_ei_pax = ((u_long) ehdr.e_ident[EI_PAX + 1] << 8) + (u_long) ehdr.e_ident[EI_PAX];
+
+ if(!quiet)
+ {
+ printf("==== EI_PAX ====\n") ;
+ if(verbose)
+ {
+ PRINT(HF_PAX_PAGEEXEC, found_ei_pax, 0);
+ PRINT(HF_PAX_EMUTRAMP, found_ei_pax, 1);
+ PRINT(HF_PAX_MPROTECT, found_ei_pax, 0);
+ PRINT(HF_PAX_RANDMMAP, found_ei_pax, 0);
+ PRINT(HF_PAX_RANDEXEC, found_ei_pax, 1);
+ PRINT(HF_PAX_SEGMEXEC, found_ei_pax, 0);
+ printf("\n");
+ }
+ else
+ {
+ SPRINT(HF_PAX_PAGEEXEC, found_ei_pax, 'p', 'P');
+ SPRINT(HF_PAX_EMUTRAMP, found_ei_pax, 'E', 'e');
+ SPRINT(HF_PAX_MPROTECT, found_ei_pax, 'm', 'M');
+ SPRINT(HF_PAX_RANDMMAP, found_ei_pax, 'r', 'R');
+ SPRINT(HF_PAX_RANDEXEC, found_ei_pax, 'X', 'x');
+ SPRINT(HF_PAX_SEGMEXEC, found_ei_pax, 's', 'S');
+ printf("\n\n");
+ }
+ }
+
+ if( flag_ei_pax )
+ {
+ if(!quiet)
+ printf("Disabling EI_PAX\n\n");
+ ehdr.e_ident[EI_PAX] = 0xFF;
+ ehdr.e_ident[EI_PAX + 1] = 0xFF;
+ if(!gelf_update_ehdr(elf, &ehdr))
+ error(EXIT_FAILURE, 0, "gelf_update_ehdr(): %s", elf_errmsg(elf_errno()));
+ }
+
+ if(!quiet)
+ printf("==== PHRDs ====\n") ;
+ elf_getphdrnum(elf, &phnum);
+ for(i=0; i<phnum; ++i)
+ {
+ if(gelf_getphdr(elf, i, &phdr) != &phdr)
+ error(EXIT_FAILURE, 0, "gelf_getphdr(): %s", elf_errmsg(elf_errno()));
+
+ if(!quiet)
+ {
+ if(verbose)
+ {
+ switch(phdr.p_type)
+ {
+ CPRINT(i,PT_NULL);
+ CPRINT(i,PT_LOAD);
+ CPRINT(i,PT_DYNAMIC);
+ CPRINT(i,PT_INTERP);
+ CPRINT(i,PT_NOTE);
+ CPRINT(i,PT_SHLIB);
+ CPRINT(i,PT_PHDR);
+ CPRINT(i,PT_TLS);
+ CPRINT(i,PT_NUM);
+ CPRINT(i,PT_LOOS);
+ CPRINT(i,PT_GNU_EH_FRAME);
+ CPRINT(i,PT_GNU_STACK);
+ CPRINT(i,PT_GNU_RELRO);
+ CPRINT(i,PT_PAX_FLAGS);
+ CPRINT(i,PT_LOSUNW);
+ //CPRINT(i,PT_SUNWBSS);
+ CPRINT(i,PT_SUNWSTACK);
+ CPRINT(i,PT_HISUNW);
+ //CPRINT(i,PT_HIOS);
+ CPRINT(i,PT_LOPROC);
+ CPRINT(i,PT_HIPROC);
+ }
+ }
+
+ if(phdr.p_type == PT_PAX_FLAGS)
+ {
+ if(verbose)
+ {
+ PRINT(PF_PAGEEXEC, phdr.p_flags, 1);
+ PRINT(PF_NOPAGEEXEC, phdr.p_flags, 1);
+ PRINT(PF_SEGMEXEC, phdr.p_flags, 1);
+ PRINT(PF_NOSEGMEXEC, phdr.p_flags, 1);
+ PRINT(PF_MPROTECT, phdr.p_flags, 1);
+ PRINT(PF_NOMPROTECT, phdr.p_flags, 1);
+ PRINT(PF_RANDEXEC, phdr.p_flags, 1);
+ PRINT(PF_NORANDEXEC, phdr.p_flags, 1);
+ PRINT(PF_EMUTRAMP, phdr.p_flags, 1);
+ PRINT(PF_NOEMUTRAMP, phdr.p_flags, 1);
+ PRINT(PF_RANDMMAP, phdr.p_flags, 1);
+ PRINT(PF_NORANDMMAP, phdr.p_flags, 1);
+ }
+ else
+ {
+ printf("%d: PT_PAX_FLAGS\n", (int)i);
+ FPRINT(PF_PAGEEXEC, PF_NOPAGEEXEC, phdr.p_flags, 'p', 'P');
+ FPRINT(PF_EMUTRAMP, PF_NOEMUTRAMP, phdr.p_flags, 'e', 'E');
+ FPRINT(PF_MPROTECT, PF_NOMPROTECT, phdr.p_flags, 'm', 'M');
+ FPRINT(PF_RANDMMAP, PF_NORANDMMAP, phdr.p_flags, 'r', 'R');
+ FPRINT(PF_RANDEXEC, PF_NORANDEXEC, phdr.p_flags, 'x', 'X');
+ FPRINT(PF_SEGMEXEC, PF_NOSEGMEXEC, phdr.p_flags, 's', 'S');
+ }
+ }
+ }
+
+ if((phdr.p_type == PT_PAX_FLAGS) && flag_pt_pax_flags )
+ {
+ if(!quiet)
+ printf("CONVERTED -> PT_NULL\n\n");
+ phdr.p_type = PT_NULL;
+ if(!gelf_update_phdr(elf, i, &phdr))
+ error(EXIT_FAILURE, 0, "gelf_update_phdr(): %s", elf_errmsg(elf_errno()));
+ }
+ }
+ if(!quiet)
+ printf("\n\n");
+
+ elf_end(elf);
+ close(fd);
+}
diff --git a/pocs/mangle-paxflags/poc.sh b/pocs/mangle-paxflags/poc.sh
new file mode 100755
index 0000000..f268f33
--- /dev/null
+++ b/pocs/mangle-paxflags/poc.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+echo "================================================================================"
+echo
+./mangle-paxflags bad-mmap
+./bad-mmap
+echo
+echo "========================================"
+echo
+./mangle-paxflags -p bad-mmap
+./mangle-paxflags bad-mmap
+./bad-mmap
+echo
+echo "========================================"
+echo
+./mangle-paxflags -e bad-mmap
+./mangle-paxflags bad-mmap
+./bad-mmap
+echo
+echo "================================================================================"
diff --git a/pocs/paxmark-libs/Makefile.am b/pocs/paxmark-libs/Makefile.am
new file mode 100644
index 0000000..3e87910
--- /dev/null
+++ b/pocs/paxmark-libs/Makefile.am
@@ -0,0 +1,94 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CPPFLAGS = -DPLUGIN='"$(libdir)/libmypax.so"'
+
+bin_PROGRAMS = testpax testdlpax
+testpax_SOURCES = testpax.c
+testpax_LDFLAGS = -lmypax
+testdlpax_SOURCES = testdlpax.c
+testdlpax_LDFLAGS = -ldl
+
+lib_LTLIBRARIES = libmypax.la
+libmypax_la_SOURCES = libmypax.c
+
+check_SCRIPTS = poc.sh
+
+poc.sh:
+ @/sbin/ldconfig
+ @echo "================================================================================"
+ @echo "= TESTING DYNAMIC LINKING ======================================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testpax
+ @/sbin/paxctl -M $(libdir)/libmypax.so
+ @/sbin/paxctl -M $(bindir)/testpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testpax 2>/dev/null
+ @echo
+ $(bindir)/testpax
+ @echo
+ @echo "========================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testpax
+ @/sbin/paxctl -m $(libdir)/libmypax.so
+ @/sbin/paxctl -M $(bindir)/testpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testpax 2>/dev/null
+ @echo
+ $(bindir)/testpax
+ @echo
+ @echo "========================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testpax
+ @/sbin/paxctl -M $(libdir)/libmypax.so
+ @/sbin/paxctl -m $(bindir)/testpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testpax 2>/dev/null
+ @echo
+ $(bindir)/testpax
+ @echo
+ @echo "========================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testpax
+ @/sbin/paxctl -m $(libdir)/libmypax.so
+ @/sbin/paxctl -m $(bindir)/testpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testpax 2>/dev/null
+ @echo
+ $(bindir)/testpax
+ @echo
+ @echo
+ @echo "================================================================================"
+ @echo "= TESTING DLOPENING ============================================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testdlpax
+ @/sbin/paxctl -M $(libdir)/libmypax.so
+ @/sbin/paxctl -M $(bindir)/testdlpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testdlpax 2>/dev/null
+ @echo
+ $(bindir)/testdlpax
+ @echo
+ @echo "========================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testdlpax
+ @/sbin/paxctl -m $(libdir)/libmypax.so
+ @/sbin/paxctl -M $(bindir)/testdlpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testdlpax 2>/dev/null
+ @echo
+ $(bindir)/testdlpax
+ @echo
+ @echo "========================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testdlpax
+ @/sbin/paxctl -M $(libdir)/libmypax.so
+ @/sbin/paxctl -m $(bindir)/testdlpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testdlpax 2>/dev/null
+ @echo
+ $(bindir)/testdlpax
+ @echo
+ @echo "========================================"
+ @echo
+ @/sbin/paxctl -z $(libdir)/libmypax.so $(bindir)/testdlpax
+ @/sbin/paxctl -m $(libdir)/libmypax.so
+ @/sbin/paxctl -m $(bindir)/testdlpax
+ @/sbin/paxctl -Qv $(libdir)/libmypax.so $(bindir)/testdlpax 2>/dev/null
+ @echo
+ $(bindir)/testdlpax
+ @echo
+ @echo "================================================================================"
+
diff --git a/pocs/paxmark-libs/autogen.sh b/pocs/paxmark-libs/autogen.sh
new file mode 100755
index 0000000..917d1a7
--- /dev/null
+++ b/pocs/paxmark-libs/autogen.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+aclocal && \
+autoheader && \
+autoconf && \
+libtoolize --copy && \
+automake --add-missing --copy
diff --git a/pocs/paxmark-libs/configure.ac b/pocs/paxmark-libs/configure.ac
new file mode 100644
index 0000000..bedcbbb
--- /dev/null
+++ b/pocs/paxmark-libs/configure.ac
@@ -0,0 +1,27 @@
+
+AC_PREREQ([2.68])
+AC_INIT([testpax],[0.1])
+AC_CONFIG_SRCDIR([testpax.c])
+AC_CONFIG_HEADERS([config.h])
+
+AM_INIT_AUTOMAKE([1.11 foreign])
+AM_SILENT_RULES([yes])
+
+LT_PREREQ([2.4])
+LT_INIT([dlopen])
+
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_CC
+
+# Checks for libraries.
+
+# Checks for header files.
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/pocs/paxmark-libs/libmypax.c b/pocs/paxmark-libs/libmypax.c
new file mode 100644
index 0000000..a53b62e
--- /dev/null
+++ b/pocs/paxmark-libs/libmypax.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+
+void
+doit() {
+ size_t m = (size_t) mmap( NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 );
+ if( m == (size_t) MAP_FAILED )
+ printf("%s\n", strerror(errno));
+}
diff --git a/pocs/paxmark-libs/testdlpax.c b/pocs/paxmark-libs/testdlpax.c
new file mode 100644
index 0000000..fde3245
--- /dev/null
+++ b/pocs/paxmark-libs/testdlpax.c
@@ -0,0 +1,17 @@
+#include <dlfcn.h>
+
+#ifndef PLUGIN
+#define PLUGIN "/usr/local/lib/libmypax.so"
+#endif
+
+int
+main() {
+ void *handle;
+ void (*doit)();
+
+ handle = dlopen(PLUGIN, RTLD_LAZY);
+ doit = dlsym(handle, "doit");
+ (*doit)();
+ dlclose(handle);
+ return 0;
+}
diff --git a/pocs/paxmark-libs/testpax.c b/pocs/paxmark-libs/testpax.c
new file mode 100644
index 0000000..dd1c0b7
--- /dev/null
+++ b/pocs/paxmark-libs/testpax.c
@@ -0,0 +1,6 @@
+
+int
+main() {
+ doit();
+ return 0;
+}
diff --git a/pocs/revdep-pax-ng/revdep-pax-ng b/pocs/revdep-pax-ng/revdep-pax-ng
new file mode 100755
index 0000000..7767563
--- /dev/null
+++ b/pocs/revdep-pax-ng/revdep-pax-ng
@@ -0,0 +1,500 @@
+#!/usr/bin/env python
+#
+# revdep-pax-ng: this file is part of the elfix package
+# Copyright (C) 2011, 2012 Anthony G. Basile
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+
+import sys
+import getopt
+import os
+import subprocess
+import re
+import pax
+
+
+#python2/3 compat input
+def get_input(prompt):
+ if sys.hexversion > 0x03000000:
+ return input(prompt)
+ else:
+ return raw_input(prompt)
+
+
+def get_ldd_linkings(binary):
+ ldd_output = subprocess.Popen(['/usr/bin/ldd', binary], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ ldd_lines = ldd_output.stdout.read().decode().split('\n')
+
+ linkings = []
+ mappings = {}
+ for m in range(0,len(ldd_lines)):
+ if not re.search('=>', ldd_lines[m]):
+ continue
+ ldd_lines[m] = ldd_lines[m].strip()
+ mapp = re.split('=>', ldd_lines[m] )
+ soname = mapp[0].strip()
+ soname = os.path.basename(soname) # This is for ./libSDL-1.2.so.0
+ library = re.sub('\(.*$', '', mapp[1]).strip()
+ if library == '':
+ continue
+ library = os.path.realpath(library)
+ linkings.append(soname)
+ mappings[soname] = library
+
+ return ( linkings, mappings )
+
+
+def get_forward_linkings():
+ #TODO: I'm still not sure we want to use /var/db/pkg vs some path of binaries
+ var_db_pkg = '/var/db/pkg'
+
+ forward_linkings = {}
+ so2library_mappings = {}
+ for cat in os.listdir(var_db_pkg):
+ catdir = '%s/%s' % (var_db_pkg, cat)
+ for pkg in os.listdir(catdir):
+ pkgdir = '%s/%s' % (catdir, pkg)
+ need = '%s/%s' % (pkgdir, 'NEEDED')
+ try:
+ g = open(need, 'r')
+ needs = g.readlines()
+ for line in needs:
+ line = line.strip()
+ link = re.split('\s', line)
+ binary = link[0]
+ ( linkings, mappings ) = get_ldd_linkings(binary)
+ forward_linkings[binary] = linkings
+ so2library_mappings.update(mappings)
+ except IOError:
+ continue #File probably doesn't exist, which is okay
+
+ return ( forward_linkings, so2library_mappings )
+
+
+def invert_linkings( forward_linkings ):
+ reverse_linkings = {}
+
+ for binary in forward_linkings:
+ for library in forward_linkings[binary]:
+ reverse_linkings.setdefault(library,[]).append(binary)
+
+ return reverse_linkings
+
+
+def print_forward_linkings( forward_linkings, so2library_mappings, verbose ):
+ missing_binaries = []
+ missing_links = []
+ for binary in forward_linkings:
+
+ try:
+ ( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+ sv = '%s ( %s )\n' % ( binary, binary_str_flags )
+ s = sv
+ except pax.PaxError:
+ missing_binaries.append(binary)
+ continue
+
+ count = 0
+ for soname in forward_linkings[binary]:
+ try:
+ library = so2library_mappings[soname]
+ ( library_str_flags, library_bin_flags ) = pax.getflags(library)
+ sv = '%s\n\t%s\t%s ( %s )' % ( sv, soname, library, library_str_flags )
+ if binary_str_flags != library_str_flags:
+ s = '%s\n\t%s\t%s ( %s )' % ( s, soname, library, library_str_flags )
+ count = count + 1
+ except pax.PaxError:
+ missing_links.append(soname)
+
+ if verbose:
+ print('%s\n' % sv)
+ if count == 0:
+ print('\tNo mismatches\n\n')
+ else:
+ print('\tMismatches\n\n')
+ else:
+ if count != 0:
+ print('%s\n\n' % s)
+
+ missing_binaries = set(missing_binaries)
+ print('\n**** Missing binaries ****\n')
+ for m in missing_binaries:
+ print('\t%s\n' % m)
+
+ missing_links = set(missing_links)
+ print('\n**** Missing forward linkings ****\n')
+ for m in missing_links:
+ print('\t%s\n' % m)
+
+
+def print_reverse_linkings( reverse_linkings, so2library_mappings, verbose, executable_only ):
+ shell_path = path = os.getenv('PATH').split(':')
+ missing_sonames = []
+ missing_links = []
+
+ for soname in reverse_linkings:
+ try:
+ library = so2library_mappings[soname]
+ ( library_str_flags, library_bin_flags ) = pax.getflags(library)
+ sv = '%s\t%s ( %s )\n' % ( soname, library, library_str_flags )
+ s = sv
+ except pax.PaxError:
+ missing_sonames.append(soname)
+ continue
+
+ count = 0
+ for binary in reverse_linkings[soname]:
+ try:
+ ( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+ if executable_only:
+ if os.path.dirname(binary) in shell_path:
+ sv = '%s\n\t%s ( %s )' % ( sv, binary, binary_str_flags )
+ if library_str_flags != binary_str_flags:
+ s = '%s\n\t%s ( %s )' % ( s, binary, binary_str_flags )
+ count = count + 1
+ else:
+ sv = '%s\n\t%s ( %s )' % ( sv, binary, binary_str_flags )
+ if library_str_flags != binary_str_flags:
+ s = '%s\n\t%s ( %s )' % ( s, binary, binary_str_flags )
+ count = count + 1
+ except pax.PaxError:
+ missing_links.append(binary)
+
+ if verbose:
+ print('%s\n' % sv)
+ if count == 0:
+ print('\tNo mismatches\n\n')
+ else:
+ print('\tMismatches\n\n')
+ else:
+ if count != 0:
+ print('%s\n\n' % s)
+
+ missing_sonames = set(missing_sonames)
+ print('\n**** Missing sonames ****\n')
+ for m in missing_sonames:
+ print('\t%s\n' % m)
+
+ missing_links = set(missing_links)
+ print('\n**** Missing reverse linkings ****\n')
+ for m in missing_links:
+ print('\t%s\n' % m)
+
+
+def run_forward(verbose):
+ ( forward_linkings, so2library_mappings ) = get_forward_linkings()
+ print_forward_linkings( forward_linkings, so2library_mappings, verbose)
+
+
+def run_reverse(verbose, executable_only):
+ ( forward_linkings, so2library_mappings ) = get_forward_linkings()
+ reverse_linkings = invert_linkings( forward_linkings )
+ print_reverse_linkings( reverse_linkings, so2library_mappings, verbose, executable_only)
+
+
+def migrate_flags(importer, exporter_str_flags, exporter_bin_flags):
+ # We implement the following logic for setting the pax flags
+ # on the target elf object, the IMPORTER, given that the flags
+ # from the elf object we want it to match to, the EXPORTER.
+ #
+ # EXPORTER IMPORTER RESULT
+ # On On On
+ # On Off On + Warn
+ # On - On
+ # Off On On + Warn
+ # Off Off Off
+ # Off - Off
+ # - On On
+ # - Off Off
+ # - - -
+
+ #See /usr/include/elf.h for these values
+ pf_flags = {
+ 'P':1<<4, 'p':1<<5,
+ 'S':1<<6, 's':1<<7,
+ 'M':1<<8, 'm':1<<9,
+ 'X':1<<10, 'x':1<<11,
+ 'E':1<<12, 'e':1<<13,
+ 'R':1<<14, 'r':1<<15
+ }
+
+ ( importer_str_flags, importer_bin_flags ) = pax.getflags(importer)
+
+ # Start with the exporter's flags
+ result_bin_flags = exporter_bin_flags
+
+ for i in range(len(importer_str_flags)):
+
+ # The exporter's flag contradicts the importer's flag, so do nothing
+ if (exporter_str_flags[i].isupper() and importer_str_flags[i].islower()) or \
+ (exporter_str_flags[i].islower() and importer_str_flags[i].isupper()):
+
+ # Revert the exporter's flag, use the importer's flag and warn
+ result_bin_flags = result_bin_flags ^ pf_flags[exporter_str_flags[i]]
+ result_bin_flags = result_bin_flags | pf_flags[importer_str_flags[i]]
+ print('\t\tWarning: %s has %s, refusing to set to %s' % (
+ importer, importer_str_flags[i], exporter_str_flags[i] )),
+
+ # The exporter's flags is off, so use the importer's flag
+ if (exporter_str_flags[i] == '-' and importer_str_flags[i] != '-'):
+ result_bin_flags = result_bin_flags | pf_flags[importer_str_flags[i]]
+
+ pax.setbinflags(importer, result_bin_flags)
+
+
+def run_binary(binary, verbose, mark, allyes):
+ if not os.path.exists(binary):
+ print('%s\tNo such OBJECT' % binary)
+ return
+ ( linkings, mappings ) = get_ldd_linkings(binary)
+ ( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+ print('%s (%s)\n' % ( binary, binary_str_flags ))
+
+ mismatched_libraries = []
+
+ for soname in linkings:
+ try:
+ library = mappings[soname]
+ ( library_str_flags, library_bin_flags ) = pax.getflags(library)
+ if verbose:
+ print('\t%s\t%s ( %s )' % ( soname, library, library_str_flags ))
+ if binary_str_flags != library_str_flags:
+ mismatched_libraries.append(library)
+ if not verbose:
+ print('\t%s\t%s ( %s )' % ( soname, library, library_str_flags ))
+ except pax.PaxError:
+ print('file for soname %s not found' % soname)
+
+ if len(mismatched_libraries) == 0:
+ if not verbose:
+ print('\tNo mismatches\n')
+ else:
+ print('\n'),
+ if mark:
+ print('\tWill mark libraries with %s\n' % binary_str_flags)
+ for library in mismatched_libraries:
+ do_marking = False
+ while True:
+ if allyes:
+ ans = 'y'
+ else:
+ ans = get_input('\tSet flags for %s (y/n): ' % library)
+ if ans == 'y':
+ do_marking = True
+ break
+ elif ans == 'n':
+ do_marking = False
+ break
+ else:
+ print('\t\tPlease enter y or n')
+
+ if do_marking:
+ try:
+ migrate_flags(library, binary_str_flags, binary_bin_flags)
+ except pax.PaxError:
+ print("\n\tCould not set pax flags on %s, file is probably busy" % library)
+ print("\tShut down all processes that use it and try again")
+ ( library_str_flags, library_bin_flags ) = pax.getflags(library)
+ print('\n\t\t%s ( %s )\n' % ( library, library_str_flags ))
+
+
+def invert_so2library_mappings( so2library_mappings ):
+ library2soname_mappings = {}
+ for soname, library in so2library_mappings.items():
+ library2soname_mappings[library] = soname
+ return library2soname_mappings
+
+
+def run_soname(name, verbose, use_soname, mark, allyes, executable_only):
+ shell_path = path = os.getenv('PATH').split(':')
+
+ ( forward_linkings, so2library_mappings ) = get_forward_linkings()
+ reverse_linkings = invert_linkings( forward_linkings )
+
+ if use_soname:
+ soname = name
+ else:
+ library2soname_mappings = invert_so2library_mappings(so2library_mappings)
+ try:
+ soname = library2soname_mappings[name]
+ except KeyError:
+ print('%s\tNo such LIBRARY' % name)
+ return
+
+ try:
+ linkings = reverse_linkings[soname]
+ except KeyError:
+ print('%s\tNo such SONAME' % soname)
+ return
+
+ library = so2library_mappings[soname]
+
+ ( library_str_flags, library_bin_flags ) = pax.getflags(library)
+ print('%s\t%s (%s)\n' % ( soname, library, library_str_flags ))
+
+ mismatched_binaries = []
+ for binary in linkings:
+ try:
+ ( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+ if verbose:
+ if executable_only:
+ if os.path.dirname(binary) in shell_path:
+ print('\t%s ( %s )' % ( binary, binary_str_flags ))
+ else:
+ print('\t%s ( %s )' % ( binary, binary_str_flags ))
+ if library_str_flags != binary_str_flags:
+ if executable_only:
+ if os.path.dirname(binary) in shell_path:
+ mismatched_binaries.append(binary)
+ if not verbose:
+ print('\t%s ( %s )' % ( binary, binary_str_flags ))
+ else:
+ mismatched_binaries.append(binary)
+ if not verbose:
+ print('\t%s ( %s )' % ( binary, binary_str_flags ))
+ except pax.PaxError:
+ print('cannot obtain pax flags for %s' % binary)
+
+ if len(mismatched_binaries) == 0:
+ if not verbose:
+ print('\tNo mismatches\n')
+ else:
+ print('\n'),
+ if mark:
+ print('\tWill mark binaries with %s\n' % library_str_flags)
+ for binary in mismatched_binaries:
+ if executable_only:
+ if not os.path.dirname(binary) in shell_path:
+ continue
+ do_marking = False
+ while True:
+ if allyes:
+ ans = 'y'
+ else:
+ ans = get_input('\tSet flags for %s (y/n): ' % binary)
+ if ans == 'y':
+ do_marking = True
+ break
+ elif ans == 'n':
+ do_marking = False
+ break
+ else:
+ print('\t\tPlease enter y or n')
+ if do_marking:
+ try:
+ migrate_flags(binary, library_str_flags, library_bin_flags)
+ except pax.PaxError:
+ print('\n\tCould not set pax flags on %s, file is probably busy' % binary)
+ print('\tShut down all processes that use it and try again')
+ ( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+ print('\n\t\t%s ( %s )\n' % ( binary, binary_str_flags ))
+
+
+def run_usage():
+ print('Package Name : elfix')
+ print('Bug Reports : http://bugs.gentoo.org/')
+ print('Program Name : revdep-pax')
+ print('Description : Get or set pax flags on an ELF object')
+ print('')
+ print('Usage : revdep-pax -f [-v] print out all forward mappings for all system binaries')
+ print(' : revdep-pax -r [-ve] print out all reverse mappings for all system sonames')
+ print(' : revdep-pax -b OBJECT [-myv] print all forward mappings only for OBJECT')
+ print(' : revdep-pax -s SONAME [-myve] print all reverse mappings only for SONAME')
+ print(' : revdep-pax -l LIBRARY [-myve] print all reverse mappings only for LIBRARY file')
+ print(' : revdep-pax [-h] print out this help')
+ print(' : -v verbose, otherwise just print mismatching objects')
+ print(' : -e only print out executables in shell $PATH')
+ print(' : -m don\'t just report, but mark the mismatching objects')
+ print(' : -y assume "yes" to all prompts for marking (USE CAREFULLY!)')
+ print('')
+
+
+def main():
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'hfrb:s:l:vemy')
+ except getopt.GetoptError as err:
+ print(str(err)) # will print something like 'option -a not recognized'
+ run_usage()
+ sys.exit(1)
+
+ if len(opts) == 0:
+ run_usage()
+ sys.exit(1)
+
+ do_usage = False
+ do_forward = False
+ do_reverse = False
+
+ binary = None
+ soname = None
+ library = None
+
+ verbose = False
+ executable_only = False
+ mark = False
+ allyes = False
+
+ opt_count = 0
+
+ for o, a in opts:
+ if o == '-h':
+ do_usage = True
+ opt_count += 1
+ elif o == '-f':
+ do_forward = True
+ opt_count += 1
+ elif o == '-r':
+ do_reverse = True
+ opt_count += 1
+ elif o == '-b':
+ binary = a
+ opt_count += 1
+ elif o == '-s':
+ soname = a
+ opt_count += 1
+ elif o == '-l':
+ library = a
+ opt_count += 1
+ elif o == '-v':
+ verbose = True
+ elif o == '-e':
+ executable_only = True
+ elif o == '-m':
+ mark = True
+ elif o == '-y':
+ allyes = True
+ else:
+ print('Option included in getopt but not handled here!')
+ print('Please file a bug')
+ sys.exit(1)
+
+ # Only allow one of -h, -f -r -b -s
+ if opt_count > 1 or do_usage:
+ run_usage()
+ elif do_forward:
+ run_forward(verbose)
+ elif do_reverse:
+ run_reverse(verbose, executable_only)
+ elif binary != None:
+ run_binary(binary, verbose, mark, allyes)
+ elif soname != None:
+ run_soname(soname, verbose, True, mark, allyes, executable_only)
+ elif library != None:
+ library = os.path.realpath(library)
+ run_soname(library, verbose, False, mark, allyes, executable_only)
+
+if __name__ == '__main__':
+ main()