Skip to content

Commit 7ae4ec3

Browse files
committed
[SBOM] Add option to switch output information
Updated Linker Flag: - Previous linker flag only enabled toggling analysis pass to output per-function mitigation information. - New version of flag can output a summary over the entire linkage unit or a per-function output. General: - Fixed incorrect CFI_ICALL mitigation metadata assignment - Changed how output file is created/named
1 parent 1adb897 commit 7ae4ec3

File tree

4 files changed

+178
-21
lines changed

4 files changed

+178
-21
lines changed

clang/lib/CodeGen/CGClass.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2849,7 +2849,8 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
28492849
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
28502850
}
28512851

2852-
AttachMitigationMetadataToFunction(*this, MitigationKey::CFI_VCALL, false);
2852+
AttachMitigationMetadataToFunction(*this, MitigationKey::CFI_VCALL,
2853+
SanOpts.has(SanitizerKind::CFIVCall));
28532854
}
28542855

28552856
void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,

llvm/include/llvm/Analysis/MitigationAnalysis.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010

1111
namespace llvm {
1212

13+
enum class MitigationAnalysisSummary {
14+
NONE = 0,
15+
SHORT = 1 << 0,
16+
FUNCTION = 1 << 1,
17+
};
18+
1319
class MitigationAnalysis : public AnalysisInfoMixin<MitigationAnalysis> {
1420
friend AnalysisInfoMixin<MitigationAnalysis>;
1521
static AnalysisKey Key;
@@ -18,8 +24,14 @@ class MitigationAnalysis : public AnalysisInfoMixin<MitigationAnalysis> {
1824
"mitigation_analysis";
1925

2026
public:
27+
MitigationAnalysis(
28+
MitigationAnalysisSummary Summary = MitigationAnalysisSummary::NONE);
29+
2130
using Result = PreservedAnalyses;
2231
Result run(Module &M, ModuleAnalysisManager &AM);
32+
33+
private:
34+
MitigationAnalysisSummary summary_;
2335
};
2436

2537
} // end namespace llvm

llvm/lib/Analysis/MitigationAnalysis.cpp

Lines changed: 150 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
#include "llvm/Support/FileSystem.h"
99
#include "llvm/Support/JSON.h"
1010
#include "llvm/Support/raw_ostream.h"
11-
#include <string>
12-
#include <unordered_map>
1311

1412
using namespace llvm;
1513

@@ -18,8 +16,7 @@ AnalysisKey MitigationAnalysis::Key;
1816
// Add a command line flag for the module name
1917
static cl::opt<std::string>
2018
ClOutputModuleName("mitigation-analysis-dso-name", cl::Optional,
21-
cl::desc("DSO name for the module"),
22-
cl::init("unknown"));
19+
cl::desc("DSO name for the module"), cl::init(""));
2320

2421
enum class MitigationState { Ineligible, EligibleDisabled, EligibleEnabled };
2522

@@ -30,6 +27,37 @@ static const std::unordered_map<MitigationState, std::string> mapStateToString =
3027
{MitigationState::EligibleEnabled, "Enabled"},
3128
};
3229

30+
struct ModuleMitigationInfo {
31+
std::size_t eligable_auto_var_init = 0;
32+
std::size_t enabled_auto_var_init = 0;
33+
34+
std::size_t eligable_cfi_icall = 0;
35+
std::size_t enabled_cfi_icall = 0;
36+
37+
std::size_t eligable_cfi_vcall = 0;
38+
std::size_t enabled_cfi_vcall = 0;
39+
40+
std::size_t eligable_cfi_nvcall = 0;
41+
std::size_t enabled_cfi_nvcall = 0;
42+
43+
std::size_t eligable_stack_clash_protection = 0;
44+
std::size_t enabled_stack_clash_protection = 0;
45+
46+
std::size_t eligable_stack_protector = 0;
47+
std::size_t enabled_stack_protector = 0;
48+
49+
std::size_t eligable_stack_protector_strong = 0;
50+
std::size_t enabled_stack_protector_strong = 0;
51+
52+
std::size_t eligable_stack_protector_all = 0;
53+
std::size_t enabled_stack_protector_all = 0;
54+
55+
std::size_t eligable_libcpp_hardening_mode = 0;
56+
std::size_t enabled_libcpp_hardening_mode = 0;
57+
58+
std::size_t total_functions = 0;
59+
};
60+
3361
struct MitigationInfo {
3462
MitigationState auto_var_init = MitigationState::Ineligible;
3563
MitigationState cfi_icall = MitigationState::Ineligible;
@@ -59,6 +87,56 @@ static inline MitigationState valToState(int value) {
5987
}
6088
}
6189

90+
static void updateModuleInfo(ModuleMitigationInfo &moduleInfo,
91+
const MitigationInfo &info) {
92+
moduleInfo.total_functions++;
93+
94+
moduleInfo.eligable_auto_var_init +=
95+
(info.auto_var_init != MitigationState::Ineligible);
96+
moduleInfo.enabled_auto_var_init +=
97+
(info.auto_var_init == MitigationState::EligibleEnabled);
98+
99+
moduleInfo.eligable_cfi_icall +=
100+
(info.cfi_icall != MitigationState::Ineligible);
101+
moduleInfo.enabled_cfi_icall +=
102+
(info.cfi_icall == MitigationState::EligibleEnabled);
103+
104+
moduleInfo.eligable_cfi_vcall +=
105+
(info.cfi_vcall != MitigationState::Ineligible);
106+
moduleInfo.enabled_cfi_vcall +=
107+
(info.cfi_vcall == MitigationState::EligibleEnabled);
108+
109+
moduleInfo.eligable_cfi_nvcall +=
110+
(info.cfi_nvcall != MitigationState::Ineligible);
111+
moduleInfo.enabled_cfi_nvcall +=
112+
(info.cfi_nvcall == MitigationState::EligibleEnabled);
113+
114+
moduleInfo.eligable_stack_clash_protection +=
115+
(info.stack_clash_protection != MitigationState::Ineligible);
116+
moduleInfo.enabled_stack_clash_protection +=
117+
(info.stack_clash_protection == MitigationState::EligibleEnabled);
118+
119+
moduleInfo.eligable_stack_protector +=
120+
(info.stack_protector != MitigationState::Ineligible);
121+
moduleInfo.enabled_stack_protector +=
122+
(info.stack_protector == MitigationState::EligibleEnabled);
123+
124+
moduleInfo.eligable_stack_protector_strong +=
125+
(info.stack_protector_strong != MitigationState::Ineligible);
126+
moduleInfo.enabled_stack_protector_strong +=
127+
(info.stack_protector_strong == MitigationState::EligibleEnabled);
128+
129+
moduleInfo.eligable_stack_protector_all +=
130+
(info.stack_protector_all != MitigationState::Ineligible);
131+
moduleInfo.enabled_stack_protector_all +=
132+
(info.stack_protector_all == MitigationState::EligibleEnabled);
133+
134+
moduleInfo.eligable_libcpp_hardening_mode +=
135+
(info.libcpp_hardening_mode != MitigationState::Ineligible);
136+
moduleInfo.enabled_libcpp_hardening_mode +=
137+
(info.libcpp_hardening_mode == MitigationState::EligibleEnabled);
138+
}
139+
62140
/// Print out fields in MitigationInfo for debugging/verification purposes.
63141
#ifndef NDEBUG
64142
static void printInfo(const MitigationInfo &info) {
@@ -131,9 +209,10 @@ static void writeJsonToFile(const std::string &jsonString,
131209
const std::string &fileName,
132210
const std::string &errorMsg) {
133211
std::error_code errCode;
134-
raw_fd_ostream OutputStream(fileName, errCode, sys::fs::CD_CreateAlways,
212+
raw_fd_ostream OutputStream(fileName, errCode, sys::fs::CD_OpenAlways,
135213
sys::fs::FA_Read | sys::fs::FA_Write,
136-
sys::fs::OF_Text | sys::fs::OF_UpdateAtime);
214+
sys::fs::OF_Text | sys::fs::OF_UpdateAtime |
215+
sys::fs::OF_Append);
137216
if (errCode) {
138217
errs() << errorMsg << "\n";
139218
errs() << errCode.message() << "\n";
@@ -175,6 +254,42 @@ static json::Object infoToJson(const MitigationInfo &info) {
175254
return object;
176255
}
177256

257+
/// Convert a ModuleMitigationInfo struct to a JSON object.
258+
static json::Object moduleInfoToJson(const ModuleMitigationInfo &moduleInfo) {
259+
json::Object object;
260+
261+
object["enabled_auto_var_init"] = moduleInfo.enabled_auto_var_init;
262+
object["eligable_cfi_icall"] = moduleInfo.eligable_cfi_icall;
263+
object["enabled_cfi_icall"] = moduleInfo.enabled_cfi_icall;
264+
object["eligable_cfi_vcall"] = moduleInfo.eligable_cfi_vcall;
265+
object["enabled_cfi_vcall"] = moduleInfo.enabled_cfi_vcall;
266+
object["eligable_cfi_nvcall"] = moduleInfo.eligable_cfi_nvcall;
267+
object["enabled_cfi_nvcall"] = moduleInfo.enabled_cfi_nvcall;
268+
object["eligable_stack_clash_protection"] =
269+
moduleInfo.eligable_stack_clash_protection;
270+
object["enabled_stack_clash_protection"] =
271+
moduleInfo.enabled_stack_clash_protection;
272+
object["eligable_stack_protector"] = moduleInfo.eligable_stack_protector;
273+
object["enabled_stack_protector"] = moduleInfo.enabled_stack_protector;
274+
object["eligable_stack_protector_strong"] =
275+
moduleInfo.eligable_stack_protector_strong;
276+
object["enabled_stack_protector_strong"] =
277+
moduleInfo.enabled_stack_protector_strong;
278+
object["eligable_stack_protector_all"] =
279+
moduleInfo.eligable_stack_protector_all;
280+
object["enabled_stack_protector_all"] =
281+
moduleInfo.enabled_stack_protector_all;
282+
object["eligable_libcpp_hardening_mode"] =
283+
moduleInfo.eligable_libcpp_hardening_mode;
284+
object["enabled_libcpp_hardening_mode"] =
285+
moduleInfo.enabled_libcpp_hardening_mode;
286+
287+
object["total_functions"] = moduleInfo.total_functions;
288+
object["module"] =
289+
ClOutputModuleName.empty() ? std::string("unknown") : ClOutputModuleName;
290+
return object;
291+
}
292+
178293
/// Return true if function F calls a function whose name contains
179294
/// targetFunctionName.
180295
static bool functionCallsFunctionWithName(Function &F,
@@ -250,9 +365,13 @@ static MitigationState detectLibcppHardeningMode(Function &F) {
250365
return MitigationState::Ineligible;
251366
}
252367

368+
MitigationAnalysis::MitigationAnalysis(MitigationAnalysisSummary Summary)
369+
: summary_(std::move(Summary)) {}
370+
253371
PreservedAnalyses MitigationAnalysis::run(Module &M,
254372
ModuleAnalysisManager &AM) {
255373
json::Array jsonArray;
374+
ModuleMitigationInfo moduleInfo;
256375

257376
for (Function &F : M) {
258377
LLVMContext &Context = F.getContext();
@@ -262,7 +381,8 @@ PreservedAnalyses MitigationAnalysis::run(Module &M,
262381
continue;
263382

264383
MitigationInfo info;
265-
info.gmodule = ClOutputModuleName;
384+
info.gmodule = ClOutputModuleName.empty() ? std::string("unknown")
385+
: ClOutputModuleName;
266386
info.function = F.getName();
267387

268388
for (unsigned i = 0; i < ExistingMD->getNumOperands(); ++i) {
@@ -283,20 +403,36 @@ PreservedAnalyses MitigationAnalysis::run(Module &M,
283403

284404
info.libcpp_hardening_mode = detectLibcppHardeningMode(F);
285405

286-
info.source_mapping = getFunctionSourcePath(F);
287-
info.type_signature = getFirstFunctionTypeSignature(F);
288-
info.type_id = getFunctionTypeId(F);
406+
if (summary_ == MitigationAnalysisSummary::FUNCTION) {
407+
info.source_mapping = getFunctionSourcePath(F);
408+
info.type_signature = getFirstFunctionTypeSignature(F);
409+
info.type_id = getFunctionTypeId(F);
289410

290-
DEBUG_WITH_TYPE(kMitigationAnalysisDebugType, printInfo(info));
291-
jsonArray.push_back(infoToJson(info));
411+
DEBUG_WITH_TYPE(kMitigationAnalysisDebugType, printInfo(info));
412+
jsonArray.push_back(infoToJson(info));
413+
} else {
414+
// Start aggregating mitigations for entire module
415+
updateModuleInfo(moduleInfo, info);
416+
}
292417
}
293418

419+
std::string fileName =
420+
ClOutputModuleName.empty()
421+
? std::string("mitigation_info.json")
422+
: formatv("mitigation_info-{0}.json", ClOutputModuleName);
294423
if (!jsonArray.empty()) {
295424
std::string jsonString =
296425
formatv("{0}", json::Value(std::move(jsonArray))).str();
297426
if (!jsonString.empty()) {
298-
writeJsonToFile(jsonString, "mitigation_info.json",
299-
"Couldn't write to mitigation_info.json!");
427+
writeJsonToFile(jsonString, fileName,
428+
formatv("Couldn't write to {0}!", fileName));
429+
}
430+
} else if (moduleInfo.total_functions > 0) {
431+
std::string jsonString =
432+
formatv("{0}", json::Value(moduleInfoToJson(moduleInfo))).str();
433+
if (!jsonString.empty()) {
434+
writeJsonToFile(jsonString, fileName,
435+
formatv("Couldn't write to {0}!", fileName));
300436
}
301437
}
302438

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,18 @@ static cl::opt<std::string> InstrumentColdFuncOnlyPath(
306306
"with --pgo-instrument-cold-function-only)"),
307307
cl::Hidden);
308308

309-
static cl::opt<bool>
310-
EnableMitigationAnalysis("enable-mitigation-analysis", cl::init(false),
311-
cl::Hidden,
312-
cl::desc("Enable the MitigationAnalysis Pass"));
309+
static cl::opt<MitigationAnalysisSummary> EnableMitigationSummary(
310+
"mitigation-summary", cl::Hidden,
311+
cl::init(MitigationAnalysisSummary::SHORT),
312+
cl::desc("Enable the MitigationAnalysis Pass"),
313+
cl::values(
314+
clEnumValN(MitigationAnalysisSummary::NONE, "none",
315+
"Disable generating mitigation analysis information"),
316+
clEnumValN(
317+
MitigationAnalysisSummary::SHORT, "short",
318+
"Generate summary of mitigation coverage for the current module"),
319+
clEnumValN(MitigationAnalysisSummary::FUNCTION, "function",
320+
"Generate per-function mitigation coverage information")));
313321

314322
extern cl::opt<std::string> UseCtxProfile;
315323
extern cl::opt<bool> PGOInstrumentColdFunctionOnly;
@@ -1858,8 +1866,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
18581866
// in the current module.
18591867
MPM.addPass(CrossDSOCFIPass());
18601868

1861-
if (EnableMitigationAnalysis)
1862-
MPM.addPass(MitigationAnalysis());
1869+
if (EnableMitigationSummary != llvm::MitigationAnalysisSummary::NONE)
1870+
MPM.addPass(MitigationAnalysis(EnableMitigationSummary));
18631871

18641872
if (Level == OptimizationLevel::O0) {
18651873
// The WPD and LowerTypeTest passes need to run at -O0 to lower type

0 commit comments

Comments
 (0)