diff --git a/tests/Sanity/fhardened/files/hello.c b/tests/Sanity/fhardened/files/hello.c new file mode 100644 index 0000000..5d17831 --- /dev/null +++ b/tests/Sanity/fhardened/files/hello.c @@ -0,0 +1,5 @@ +#include + +int hello() { + return printf("hello world\n"); +} diff --git a/tests/Sanity/fhardened/files/just_the-fhardened_option.awk b/tests/Sanity/fhardened/files/just_the-fhardened_option.awk new file mode 100644 index 0000000..42a7c19 --- /dev/null +++ b/tests/Sanity/fhardened/files/just_the-fhardened_option.awk @@ -0,0 +1,6 @@ +/^ -fhardened$/ { + do { + print; + getline; + } while ($0 !~ " -f") +} diff --git a/tests/Sanity/fhardened/files/main.c b/tests/Sanity/fhardened/files/main.c new file mode 100644 index 0000000..982629f --- /dev/null +++ b/tests/Sanity/fhardened/files/main.c @@ -0,0 +1,6 @@ +extern int hello(); + +int main(void) { + hello(); + return 0; +} diff --git a/tests/Sanity/fhardened/files/main.cc b/tests/Sanity/fhardened/files/main.cc new file mode 100644 index 0000000..494d28a --- /dev/null +++ b/tests/Sanity/fhardened/files/main.cc @@ -0,0 +1,8 @@ +#include +using namespace std; + +int main(void) { + cout << "hello world" << endl; + return 0; +} + diff --git a/tests/Sanity/fhardened/main.fmf b/tests/Sanity/fhardened/main.fmf new file mode 100644 index 0000000..a7f6922 --- /dev/null +++ b/tests/Sanity/fhardened/main.fmf @@ -0,0 +1,36 @@ +summary: Test -fhardened +contact: Vaclav Kadlcik +component: + - gcc +enabled: true +test: ${WITH_SCL:-bash} ./runtest.sh +framework: beakerlib +require+: + - gcc + - gcc-c++ + - annobin-annocheck +recommend: + - annobin-plugin-gcc + - annobin +duration: 30m +adjust: + - enabled: false + when: arch != x86_64 + continue: false + because: Implemented on x86_64 only + - enabled: false + when: distro < fedora-40 + continue: false + because: GCC 14+ needed + - enabled: false + when: collection is not defined and distro < rhel-10 + continue: false + because: GCC 14+ needed + - enabled: false + when: collection is defined and collection < gcc-toolset-14 + continue: false + because: GCC 14+ needed +# TODO extra-nitrate: TC# +extra-summary: /tools/gcc/Sanity/fhardened +extra-task: /tools/gcc/Sanity/fhardened +# TODO id: diff --git a/tests/Sanity/fhardened/runtest.sh b/tests/Sanity/fhardened/runtest.sh new file mode 100755 index 0000000..8ba5888 --- /dev/null +++ b/tests/Sanity/fhardened/runtest.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash + +# Load libraries +. /usr/share/beakerlib/beakerlib.sh || exit 1 +. "${0%/*}"/../../lib/common.sh || exit 1 + +GCC="${GCC:-$(type -P gcc)}" +GCC_RPM_NAME=$(rpm --qf '%{name}' -qf "$GCC") +PACKAGES="$GCC_RPM_NAME ${GCC_RPM_NAME}-c++" + +rlJournalStart + rlPhaseStartSetup + rlLogInfo "PACKAGES=$PACKAGES" + rlLogInfo "COLLECTIONS=$COLLECTIONS" + rlLogInfo "GCC=$GCC" + rlLogInfo "SKIP_COLLECTION_METAPACKAGE_CHECK=$SKIP_COLLECTION_METAPACKAGE_CHECK" + + # We optionally need to skip checking for the presence of the metapackage + # because that would pull in all the dependent toolset subrpms. We do not + # always want that, especially in CI. + _COLLECTIONS="$COLLECTIONS" + if ! test -z "$SKIP_COLLECTION_METAPACKAGE_CHECK"; then + for c in $SKIP_COLLECTION_METAPACKAGE_CHECK; do + rlLogInfo "ignoring metapackage check for collection $c" + COLLECTIONS=$(shopt -s extglob && echo "${COLLECTIONS//$c/}"); export COLLECTIONS + done + fi + rlLogInfo "(without skipped) COLLECTIONS=$COLLECTIONS" + rlAssertRpm --all + export COLLECTIONS="$_COLLECTIONS" + + rlRun "TmpDir=\$(mktemp --directory)" + # shellcheck disable=SC2154 + rlRun "cp files/* $TmpDir" + rlRun "pushd $TmpDir" + rlPhaseEnd + + rlPhaseStartTest DOCUMENTATION + rlRun 'MANWIDTH=4096 man gcc >man.out' + rlRun 'awk -f just_the-fhardened_option.awk man-fhardened.out' + rlRun 'gcc --help=hardened >help_hardened.out' + + rlAssertGrep ' -Whardened$' man.out + rlAssertGrep ' -fhardened$' man.out + + # Later, this may need to be split into specifics per "gcc -dumpversion" + for i in \ + -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS \ + -ftrivial-auto-var-init=zero -fPIE -pie \ + '-Wl,[^ ]*-z,relro' '-Wl,[^ ]*-z,now' \ + -fstack-protector-strong -fstack-clash-protection \ + -fcf-protection=full + do + rlAssertGrep " ${i}\W" man-fhardened.out -Pzq + rlAssertGrep " ${i}\W" help_hardened.out -Pzq + done + rlPhaseEnd + + rlPhaseStartTest SHOULD_NOT_CONFLICT + # Let's check at least some most often used switches + for i in \ + -fasynchronous-unwind-tables -fexceptions -ffat-lto-objects \ + -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer \ + -g -grecord-gcc-switches \ + -m64 -march=native -march=x86-64 -march=x86-64-v2 \ + -mtune=generic -mtune=native + do + rlRun "gcc -fhardened -O2 $i -o c_hello.exe main.c hello.c &>outerr" + rlAssertNotDiffer outerr /dev/null + done + for i in -O -O1 -O2 -O3 -Os -Ofast -Og -Oz; do + rlRun "gcc -fhardened $i -o c_hello.exe main.c hello.c &>outerr" + rlAssertNotDiffer outerr /dev/null + done + rlPhaseEnd + + rlPhaseStartTest NOTICED_BY_ANNOBIN + # When used, built-by should see it + rlRun 'g++ -g -fplugin=annobin -fhardened -O2 -o cxx_hello.exe main.cc' + rlRun 'annocheck --disable-hardened --enable-built-by cxx_hello.exe >annocheck.out' + rlAssertGrep 'built by.*-fhardened' annocheck.out + + # And the other way around + rlRun 'gcc -g -fplugin=annobin -o c_hello.exe main.c hello.c' + rlRun 'annocheck --disable-hardened --enable-built-by c_hello.exe >annocheck.out' + rlAssertNotGrep 'fhardened' annocheck.out + rlPhaseEnd + + rlPhaseStartTest NOT_ENABLED_BY_DEFAULT + rlRun 'gcc -O2 -o c_hello.exe main.c hello.c &>verbose' + rlAssertNotGrep fhardened verbose + rlPhaseEnd + + rlPhaseStartTest WARN_WHEN_LOWERED + # -Whardened should be enabled by default + rlRun 'g++ -fhardened -fstack-protector -O -o cxx_hello.exe main.cc 2>err' + rlAssertGrep '-fstack-protector-strong.*not enabled.*-Whardened' err + + # Lowering some of the hardening components should produce a warning + for i in '' -all -explicit; do + rlRun "g++ -fhardened -fstack-protector${i} -Whardened -O2 -o cxx_hello.exe main.cc 2>err" + rlAssertGrep '-fstack-protector-strong.*not enabled.*-Whardened' err + done + for i in branch return check none; do + rlRun "g++ -fhardened -fcf-protection=$i -Whardened -O3 -o cxx_hello.exe main.cc 2>err" + rlAssertGrep '-fcf-protection=full.*not enabled.*-Whardened' err + done + for i in '' -all -explicit; do + for j in branch return check none; do + rlRun "g++ -fhardened -fstack-protector${i} -fcf-protection=$j -Whardened -O3 -o cxx_hello.exe main.cc 2>err" + rlAssertGrep '-fstack-protector-strong.*not enabled.*-Whardened' err + rlAssertGrep '-fcf-protection=full.*not enabled.*-Whardened' err + done + done + + # _FORTIFY_SOURCE is not enabled without optimization, + # therefore a warning should come here as well + rlRun 'gcc -fhardened -o c_hello.exe main.c hello.c 2>err' + rlAssertGrep '_FORTIFY_SOURCE.*not enabled.*-Whardened' err + rlPhaseEnd + + rlPhaseStartCleanup + rlRun popd + rlRun "rm -r $TmpDir" + rlPhaseEnd +rlJournalPrintText +rlJournalEnd