Skip to content
Snippets Groups Projects
Unverified Commit f15882e6 authored by loqs's avatar loqs Committed by Caleb Maclennan
Browse files

feat(rules): Check for shadow stack support.

As Linux Extensions to gABI [1] has not been updated for
GNU_PROPERTY_X86_FEATURE_1_SHSTK implementation is based on the
binutils implementation [2] and tested against current packages.

[1]: https://gitlab.com/x86-psABIs/Linux-ABI
[2]: https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=48580982ef41907a45cda259a63d9e6878cbbea3



Co-authored-by: default avatarClaudia Pellegrino <auerhuhn@cpellegrino.de>
Co-authored-by: default avatarloqs <2227-loqs@users.noreply.gitlab.archlinux.org>
parent f9e29aae
Branches SHSTK
No related tags found
No related merge requests found
......@@ -3,7 +3,8 @@
from elftools.elf.elffile import ELFFile
from elftools.elf.dynamic import DynamicSection
from elftools.elf.sections import SymbolTableSection
from elftools.elf.enums import ENUM_GNU_PROPERTY_X86_FEATURE_1_FLAGS
from elftools.elf.sections import NoteSection, SymbolTableSection
from Namcap.util import is_elf
from Namcap.ruleclass import TarballRule
......@@ -205,3 +206,43 @@ class NoPIERule(TarballRule):
if nopie_binaries:
self.warnings = [("elffile-nopie %s", i) for i in nopie_binaries]
def _note_props(elffile, note_type, prop_type):
for section in elffile.iter_sections():
if not isinstance(section, NoteSection):
continue
for note in section.iter_notes():
if note["n_type"] != note_type:
continue
for prop in note["n_desc"]:
if prop["pr_type"] == prop_type:
yield prop
class ELFSHSTKRule(TarballRule):
"""
Check shadow stack support in ELF files.
"""
name = "elfnoshstk"
description = "Check for shadow stack support in ELF files."
def analyze(self, pkginfo, tar):
noshstk_binaries = []
for elffile, entry_name in elf_files_from_tar(tar):
if ".debug" in entry_name:
continue
for prop in _note_props(
elffile,
note_type="NT_GNU_PROPERTY_TYPE_0",
prop_type="GNU_PROPERTY_X86_FEATURE_1_AND",
):
if prop["pr_data"] & ENUM_GNU_PROPERTY_X86_FEATURE_1_FLAGS["GNU_PROPERTY_X86_FEATURE_1_SHSTK"]:
break
else:
noshstk_binaries.append(entry_name)
if noshstk_binaries:
self.warnings = [("elffile-noshstk %s", i) for i in noshstk_binaries]
......@@ -101,3 +101,51 @@ package() {
self.assertEqual(r.errors, [])
self.assertEqual(r.warnings, [("elffile-nopie %s", "usr/bin/nopie")])
self.assertEqual(r.infos, [])
class TestNoShadowStack(MakepkgTest):
pkgbuild = """
pkgname=__namcap_test_noshstk
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 fcf-protection-branch main.c -fcf-protection=branch
/usr/bin/gcc -o fcf-protection-full main.c -fcf-protection=full
/usr/bin/gcc -o fcf-protection-none main.c -fcf-protection=none
/usr/bin/gcc -o fcf-protection-return main.c -fcf-protection=return
/usr/bin/objcopy --remove-section=.note.gnu.property fcf-protection-full no-.note.gnu.property
}
package() {
install -D -m 644 "${srcdir}/fcf-protection-branch" "${pkgdir}/usr/bin/fcf-protection-branch"
install -D -m 644 "${srcdir}/fcf-protection-full" "${pkgdir}/usr/bin/fcf-protection-full"
install -D -m 644 "${srcdir}/fcf-protection-none" "${pkgdir}/usr/bin/fcf-protection-none"
install -D -m 644 "${srcdir}/fcf-protection-return" "${pkgdir}/usr/bin/fcf-protection-return"
install -D -m 644 "${srcdir}/no-.note.gnu.property" "${pkgdir}/usr/bin/no-.note.gnu.property"
}
"""
def test_noshstk(self):
pkgfile = "__namcap_test_noshstk-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.ELFSHSTKRule)
self.assertEqual(r.errors, [])
self.assertEqual(
r.warnings,
[
("elffile-noshstk %s", "usr/bin/fcf-protection-branch"),
("elffile-noshstk %s", "usr/bin/fcf-protection-none"),
("elffile-noshstk %s", "usr/bin/no-.note.gnu.property"),
],
)
self.assertEqual(r.infos, [])
......@@ -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-in-questionable-dirs %s :: ELF files outside of a valid path ('%s').
elffile-nopie %s :: ELF file ('%s') lacks PIE.
elffile-noshstk %s :: ELF file ('%s') lacks GNU_PROPERTY_X86_FEATURE_1_SHSTK.
elffile-not-in-allowed-dirs %s :: ELF file ('%s') outside of a valid path.
elffile-unstripped %s :: ELF file ('%s') is unstripped.
elffile-with-execstack %s :: ELF file ('%s') has executable stack.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment