[namcap] elffiles: Add rule for no PIE binaries
diff mbox

Message ID 20180114165919.15474-1-jelle@vdwaa.nl
State Accepted
Headers show

Commit Message

Jelle van der Waa Jan. 14, 2018, 4:59 p.m. UTC
Verify if packages where build with PIE enabled by checking if it's
an EY_DYN file with a DT_DEBUG entry.
---
 Namcap/rules/elffiles.py              | 33 ++++++++++++++++++++++++++++++
 Namcap/tests/package/test_elffiles.py | 38 ++++++++++++++++++++++++++++++++++-
 namcap-tags                           |  1 +
 3 files changed, 71 insertions(+), 1 deletion(-)

Patch
diff mbox

diff --git a/Namcap/rules/elffiles.py b/Namcap/rules/elffiles.py
index e2dd7f5..a87c0db 100644
--- a/Namcap/rules/elffiles.py
+++ b/Namcap/rules/elffiles.py
@@ -194,4 +194,37 @@  class ELFUnstrippedRule(TarballRule):
 			self.warnings = [("elffile-unstripped %s", i)
 					for i in unstripped_binaries]
 
+class NoPIERule(TarballRule):
+	"""
+	Checks for no PIE ELF files.
+	"""
+
+	name = "elfnopie"
+	description = "Check for no PIE ELF files."
+
+	def has_dt_debug(self, elffile):
+		for section in elffile.iter_sections():
+			if not isinstance(section, DynamicSection):
+				continue
+			if any(tag.entry.d_tag == 'DT_DEBUG' for tag in section.iter_tags()):
+				return True
+		return False
+
+	def analyze(self, pkginfo, tar):
+		nopie_binaries = []
+
+		for entry in tar:
+			if not entry.isfile():
+				continue
+			fp = tar.extractfile(entry)
+			if not is_elf(fp):
+				continue
+			elffile = ELFFile(fp)
+			if elffile.header['e_type'] != 'ET_DYN' or not self.has_dt_debug(elffile):
+				nopie_binaries.append(entry.name)
+
+		if nopie_binaries:
+			self.warnings = [("elffile-nopie %s", i) for i in nopie_binaries]
+
+
 # vim: set ts=4 sw=4 noet:
diff --git a/Namcap/tests/package/test_elffiles.py b/Namcap/tests/package/test_elffiles.py
index 6362a58..b11fa13 100644
--- a/Namcap/tests/package/test_elffiles.py
+++ b/Namcap/tests/package/test_elffiles.py
@@ -95,5 +95,41 @@  package() {
 		])
 		self.assertEqual(r.infos, [])
 
-# vim: set ts=4 sw=4 noet:
+class TestNoPieStack(MakepkgTest):
+	pkgbuild = """
+pkgname=__namcap_test_nopie
+pkgver=1.0
+pkgrel=1
+pkgdesc="A package"
+arch=('i686' 'x86_64')
+url="http://www.example.com/"
+license=('GPL')
+depends=('glibc')
+source=()
+options=(!purge !zipman)
+build() {
+  cd "${srcdir}"
+  echo "int main() { return 0; }" > main.c
+  /usr/bin/gcc -o main main.c -no-pie
+}
+package() {
+  install -D -m 644 "${srcdir}/main" "${pkgdir}/usr/bin/nopie"
+}
+"""
+	def test_nopie(self):
+		pkgfile = "__namcap_test_nopie-1.0-1-%(arch)s.pkg.tar" % { "arch": self.arch }
+		with open(os.path.join(self.tmpdir, "PKGBUILD"), "w") as f:
+			f.write(self.pkgbuild)
+		self.run_makepkg()
+		pkg, r = self.run_rule_on_tarball(
+				os.path.join(self.tmpdir, pkgfile),
+				Namcap.rules.elffiles.NoPIERule
+				)
+		self.assertEqual(r.errors, [])
+		self.assertEqual(r.warnings, [
+			("elffile-nopie %s",
+				"usr/bin/nopie")
+		])
+		self.assertEqual(r.infos, [])
 
+# vim: set ts=4 sw=4 noet:
diff --git a/namcap-tags b/namcap-tags
index f967724..420ad5c 100644
--- a/namcap-tags
+++ b/namcap-tags
@@ -17,6 +17,7 @@  directory-not-world-executable %s :: Directory (%s) does not have the world exec
 elffile-in-any-package %s :: ELF file ('%s') found in an 'any' package.
 elffile-not-in-allowed-dirs %s :: ELF file ('%s') outside of a valid path.
 elffile-in-questionable-dirs %s :: ELF files outside of a valid path ('%s').
+elffile-nopie %s :: ELF file ('%s') lacks PIE.
 elffile-with-textrel %s :: ELF file ('%s') has text relocations.
 elffile-with-execstack %s :: ELF file ('%s') has executable stack.
 elffile-without-relro %s :: ELF file ('%s') lacks RELRO, check LDFLAGS.