Skip to content

Commit

Permalink
[lld] Add cet-report and bti-report flags
Browse files Browse the repository at this point in the history
Implement cet-report as supported in binutils.
bti-report has the same behaviour for AArch64-BTI.

Fixes #44828

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D113901
  • Loading branch information
DanielKristofKiss committed Dec 16, 2021
1 parent dd073e0 commit 2b4e605
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 7 deletions.
2 changes: 2 additions & 0 deletions lld/ELF/Config.h
Expand Up @@ -128,6 +128,8 @@ struct Configuration {
llvm::StringRef thinLTOCacheDir;
llvm::StringRef thinLTOIndexOnlyArg;
llvm::StringRef whyExtract;
StringRef zBtiReport = "none";
StringRef zCetReport = "none";
llvm::StringRef ltoBasicBlockSections;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOPrefixReplace;
Expand Down
65 changes: 61 additions & 4 deletions lld/ELF/Driver.cpp
Expand Up @@ -368,7 +368,13 @@ static void checkOptions() {
error("-z pac-plt only supported on AArch64");
if (config->zForceBti)
error("-z force-bti only supported on AArch64");
if (config->zBtiReport != "none")
error("-z bti-report only supported on AArch64");
}

if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
config->zCetReport != "none")
error("-z cet-report only supported on X86 and X86_64");
}

static const char *getReproduceOption(opt::InputArgList &args) {
Expand Down Expand Up @@ -455,6 +461,7 @@ static bool isKnownZFlag(StringRef s) {
s == "rela" || s == "relro" || s == "retpolineplt" ||
s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" ||
s == "wxneeded" || s.startswith("common-page-size=") ||
s.startswith("bti-report=") || s.startswith("cet-report=") ||
s.startswith("dead-reloc-in-nonalloc=") ||
s.startswith("max-page-size=") || s.startswith("stack-size=") ||
s.startswith("start-stop-visibility=");
Expand Down Expand Up @@ -970,6 +977,11 @@ static void parseClangOption(StringRef opt, const Twine &msg) {
error(msg + ": " + StringRef(err).trim());
}

// Checks the parameter of the bti-report and cet-report options.
static bool isValidReportString(StringRef arg) {
return arg == "none" || arg == "warning" || arg == "error";
}

// Initializes Config members by the command line options.
static void readConfigs(opt::InputArgList &args) {
errorHandler().verbose = args.hasArg(OPT_verbose);
Expand Down Expand Up @@ -1203,6 +1215,23 @@ static void readConfigs(opt::InputArgList &args) {
error(errPrefix + toString(pat.takeError()));
}

auto reports = {std::make_pair("bti-report", &config->zBtiReport),
std::make_pair("cet-report", &config->zCetReport)};
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
for (auto reportArg : reports) {
if (option.first != reportArg.first)
continue;
if (!isValidReportString(option.second)) {
error(Twine("-z ") + reportArg.first + "= parameter " + option.second +
" is not recognized");
continue;
}
*reportArg.second = option.second;
}
}

for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
Expand Down Expand Up @@ -2103,6 +2132,16 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
symtab->wrap(w.sym, w.real, w.wrap);
}

static void checkAndReportMissingFeature(StringRef config, uint32_t features,
uint32_t mask, const Twine &report) {
if (!(features & mask)) {
if (config == "error")
error(report);
else if (config == "warning")
warn(report);
}
}

// To enable CET (x86's hardware-assited control flow enforcement), each
// source file must be compiled with -fcf-protection. Object files compiled
// with the flag contain feature flags indicating that they are compatible
Expand All @@ -2119,14 +2158,32 @@ template <class ELFT> static uint32_t getAndFeatures() {
uint32_t ret = -1;
for (InputFile *f : objectFiles) {
uint32_t features = cast<ObjFile<ELFT>>(f)->andFeatures;

checkAndReportMissingFeature(
config->zBtiReport, features, GNU_PROPERTY_AARCH64_FEATURE_1_BTI,
toString(f) + ": -z bti-report: file does not have "
"GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");

checkAndReportMissingFeature(
config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_IBT,
toString(f) + ": -z cet-report: file does not have "
"GNU_PROPERTY_X86_FEATURE_1_IBT property");

checkAndReportMissingFeature(
config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_SHSTK,
toString(f) + ": -z cet-report: file does not have "
"GNU_PROPERTY_X86_FEATURE_1_SHSTK property");

if (config->zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
warn(toString(f) + ": -z force-bti: file does not have "
"GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
if (config->zBtiReport == "none")
warn(toString(f) + ": -z force-bti: file does not have "
"GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
} else if (config->zForceIbt &&
!(features & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
warn(toString(f) + ": -z force-ibt: file does not have "
"GNU_PROPERTY_X86_FEATURE_1_IBT property");
if (config->zCetReport == "none")
warn(toString(f) + ": -z force-ibt: file does not have "
"GNU_PROPERTY_X86_FEATURE_1_IBT property");
features |= GNU_PROPERTY_X86_FEATURE_1_IBT;
}
if (config->zPacPlt && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) {
Expand Down
10 changes: 10 additions & 0 deletions lld/docs/ld.lld.1
Expand Up @@ -702,6 +702,16 @@ Stack permissions are recorded in the
.Dv PT_GNU_STACK
segment.
.Pp
.It Cm bti-report Ns = Ns Ar [none|warning|error]
Specify how to report the missing GNU_PROPERTY_AARCH64_FEATURE_1_BTI property.
.Cm none
is the default, linker will not report the missing property otherwise will be reported as a warning or an error.
.Pp
.It Cm cet-report Ns = Ns Ar [none|warning|error]
Specify how to report the missing GNU_PROPERTY_X86_FEATURE_1_IBT or GNU_PROPERTY_X86_FEATURE_1_SHSTK properties.
.Cm none
is the default, linker will not report the missing property otherwise will be reported as a warning or an error.
.Pp
.It Cm force-bti
Force enable AArch64 BTI instruction in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property.
.Pp
Expand Down
10 changes: 8 additions & 2 deletions lld/test/ELF/aarch64-bti-pac-cli-error.s
@@ -1,12 +1,18 @@
# REQUIRES: x86
# RUN: llvm-mc --triple=x86_64-pc-linux --filetype=obj -o %t.o %s
# RUN: not ld.lld -z pac-plt -z force-bti %t.o -o /dev/null 2>&1 | FileCheck %s
# RUN: not ld.lld -z pac-plt -z force-bti -z bti-report=error %t.o -o /dev/null 2>&1 | FileCheck %s
#
## Check that we error if -z pac-plt and -z force-bti are used when target is not
## Check that we error if -z pac-plt, -z force-bti and -z bti-report=error are used when target is not
## aarch64

# CHECK: error: -z pac-plt only supported on AArch64
# CHECK-NEXT: error: -z force-bti only supported on AArch64
# CHECK-NEXT: error: -z bti-report only supported on AArch64

# RUN: not ld.lld -z bti-report=something %t.o -o /dev/null 2>&1 | \
# RUN: FileCheck --check-prefix=REPORT_INVALID %s
# REPORT_INVALID: error: -z bti-report= parameter something is not recognized
# REPORT_INVALID-EMPTY:

.globl start
start: ret
4 changes: 3 additions & 1 deletion lld/test/ELF/aarch64-feature-bti.s
Expand Up @@ -187,9 +187,11 @@
## from the file without the .note.gnu.property.

# RUN: ld.lld %t.o %t2.o -z force-bti %t.so -o %tforcebti.exe 2>&1 | FileCheck --check-prefix=FORCE-WARN %s
# RUN: not ld.lld %t.o %t2.o -z force-bti -z bti-report=error %t.so -o %tfailifnotbti.exe 2>&1 | FileCheck --check-prefix=BTI_REPORT-ERROR %s

# FORCE-WARN: aarch64-feature-bti.s.tmp2.o: -z force-bti: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property

# BTI_REPORT-ERROR: aarch64-feature-bti.s.tmp2.o: -z bti-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property
# BTI_REPORT-ERROR-EMPTY:

# RUN: llvm-readelf -n %tforcebti.exe | FileCheck --check-prefix=BTIPROP %s
# RUN: llvm-readelf --dynamic-table %tforcebti.exe | FileCheck --check-prefix BTIDYN %s
Expand Down
17 changes: 17 additions & 0 deletions lld/test/ELF/i386-feature-cet.s
Expand Up @@ -23,6 +23,23 @@
# RUN: | FileCheck --check-prefix=WARN %s
# WARN: {{.*}}.o: -z force-ibt: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property

# RUN: not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=something 2>&1 \
# RUN: | FileCheck --check-prefix=REPORT_INVALID %s
# REPORT_INVALID: error: -z cet-report= parameter something is not recognized
# REPORT_INVALID-EMPTY:

# RUN: ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=warning 2>&1 \
# RUN: | FileCheck --check-prefix=CET_REPORT_WARN %s
# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property
# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property
# CET_REPORT_WARN-EMPTY:

# RUN: not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=error 2>&1 \
# RUN: | FileCheck --check-prefix=CET_REPORT_ERROR %s
# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property
# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property
# CET_REPORT_ERROR-EMPTY:

# RUN: ld.lld -e func1 %t.o %t4.o -o %t
# RUN: llvm-readelf -n %t | FileCheck --check-prefix=NOSHSTK %s

Expand Down
23 changes: 23 additions & 0 deletions lld/test/ELF/x86-64-feature-cet.s
Expand Up @@ -23,6 +23,29 @@
# RUN: | FileCheck --check-prefix=WARN %s
# WARN: {{.*}}.o: -z force-ibt: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property

# RUN:not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=something 2>&1 \
# RUN: | FileCheck --check-prefix=REPORT_INVALID %s
# REPORT_INVALID: error: -z cet-report= parameter something is not recognized
# REPORT_INVALID-EMPTY:

# RUN: ld.lld -e func1 %t.o %t3.o -o /dev/null -z force-ibt -z cet-report=warning 2>&1 \
# RUN: | FileCheck --check-prefix=REPORT_FORCE %s
# REPORT_FORCE: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property
# REPORT_FORCE: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property
# REPORT_FORCE-EMPTY:

# RUN: ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=warning 2>&1 \
# RUN: | FileCheck --check-prefix=CET_REPORT_WARN %s
# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property
# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property
# CET_REPORT_WARN-EMPTY:

# RUN: not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=error 2>&1 \
# RUN: | FileCheck --check-prefix=CET_REPORT_ERROR %s
# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property
# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property
# CET_REPORT_ERROR-EMPTY:

# RUN: ld.lld -e func1 %t.o %t4.o -o %t
# RUN: llvm-readelf -n %t | FileCheck --check-prefix=NOSHSTK %s

Expand Down

0 comments on commit 2b4e605

Please sign in to comment.