Skip to content

Commit 3c19b59

Browse files
committed
merge main into amd-staging
2 parents 21e9d4d + 3757ecf commit 3c19b59

File tree

585 files changed

+11094
-21965
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

585 files changed

+11094
-21965
lines changed

.github/workflows/build-ci-container.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ jobs:
2727
# The arch names should match the names used on dockerhub.
2828
# See https://github.com/docker-library/official-images#architectures-other-than-amd64
2929
- arch: amd64
30-
runs-on: depot-ubuntu-22.04-16
30+
runs-on: depot-ubuntu-24.04-16
3131
- arch: arm64v8
32-
runs-on: depot-ubuntu-22.04-arm-16
32+
runs-on: depot-ubuntu-24.04-arm-16
3333
steps:
3434
- name: Checkout LLVM
3535
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

.github/workflows/commit-access-greeter.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
if: >-
1616
github.repository_owner == 'llvm' &&
1717
github.event.label.name == 'infra:commit-access-request'
18-
runs-on: ubuntu-22.04
18+
runs-on: ubuntu-24.04
1919
steps:
2020
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
2121
with:

.github/workflows/commit-access-review.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ permissions:
1212
jobs:
1313
commit-access-review:
1414
if: github.repository_owner == 'llvm'
15-
runs-on: ubuntu-22.04
15+
runs-on: ubuntu-24.04
1616
steps:
1717
- name: Fetch LLVM sources
1818
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

.github/workflows/release-asset-audit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ permissions:
1919
jobs:
2020
audit:
2121
name: "Release Asset Audit"
22-
runs-on: ubuntu-22.04
22+
runs-on: ubuntu-24.04
2323
if: github.repository == 'llvm/llvm-project'
2424
steps:
2525
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6

.github/workflows/release-binaries-all.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
setup-variables:
5858
if: >-
5959
(github.event_name != 'pull_request' || github.event.action != 'closed')
60-
runs-on: ubuntu-22.04
60+
runs-on: ubuntu-24.04
6161
outputs:
6262
release-version: ${{ steps.vars.outputs.release-version }}
6363
upload: ${{ steps.vars.outputs.upload }}
@@ -85,6 +85,8 @@ jobs:
8585
strategy:
8686
fail-fast: false
8787
matrix:
88+
# We use ubuntu-22.04 rather than the latest version to make the built
89+
# binaries more portable (eg functional aginast older glibc).
8890
runs-on:
8991
- ubuntu-22.04
9092
- ubuntu-22.04-arm

.github/workflows/release-binaries.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ on:
1616
description: "Runner to use for the build"
1717
required: true
1818
type: choice
19+
# We use ubuntu-22.04 rather than the latest version to make the built
20+
# binaries more portable (eg functional aginast older glibc).
1921
options:
2022
- ubuntu-22.04
2123
- ubuntu-22.04-arm
@@ -276,7 +278,7 @@ jobs:
276278
if: >-
277279
github.event_name != 'pull_request' &&
278280
needs.prepare.outputs.upload == 'true'
279-
runs-on: ubuntu-22.04
281+
runs-on: ubuntu-24.04
280282
permissions:
281283
contents: write # For release uploads
282284
id-token: write # For artifact attestations

.github/workflows/scorecard.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ jobs:
3131

3232
steps:
3333
- name: "Checkout code"
34-
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
34+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3535
with:
3636
persist-credentials: false
3737

3838
- name: "Run analysis"
39-
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
39+
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
4040
with:
4141
results_file: results.sarif
4242
results_format: sarif
@@ -49,14 +49,14 @@ jobs:
4949
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
5050
# format to the repository Actions tab.
5151
- name: "Upload artifact"
52-
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
52+
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
5353
with:
5454
name: SARIF file
5555
path: results.sarif
5656
retention-days: 5
5757

5858
# Upload the results to GitHub's code scanning dashboard.
5959
- name: "Upload to code-scanning"
60-
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
60+
uses: github/codeql-action/upload-sarif@80f993039571a6de66594ecaa432875a6942e8e0 # v2.20.6
6161
with:
6262
sarif_file: results.sarif

bolt/include/bolt/Passes/PAuthGadgetScanner.h

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,19 +199,40 @@ struct Report {
199199
virtual void generateReport(raw_ostream &OS,
200200
const BinaryContext &BC) const = 0;
201201

202+
// The two methods below are called by Analysis::computeDetailedInfo when
203+
// iterating over the reports.
204+
virtual const ArrayRef<MCPhysReg> getAffectedRegisters() const { return {}; }
205+
virtual void setOverwritingInstrs(const ArrayRef<MCInstReference> Instrs) {}
206+
202207
void printBasicInfo(raw_ostream &OS, const BinaryContext &BC,
203208
StringRef IssueKind) const;
204209
};
205210

206211
struct GadgetReport : public Report {
212+
// The particular kind of gadget that is detected.
207213
const GadgetKind &Kind;
208-
std::vector<MCInstReference> OverwritingInstrs;
214+
// The set of registers related to this gadget report (possibly empty).
215+
SmallVector<MCPhysReg> AffectedRegisters;
216+
// The instructions that clobber the affected registers.
217+
// There is no one-to-one correspondence with AffectedRegisters: for example,
218+
// the same register can be overwritten by different instructions in different
219+
// preceding basic blocks.
220+
SmallVector<MCInstReference> OverwritingInstrs;
209221

210222
GadgetReport(const GadgetKind &Kind, MCInstReference Location,
211-
std::vector<MCInstReference> OverwritingInstrs)
212-
: Report(Location), Kind(Kind), OverwritingInstrs(OverwritingInstrs) {}
223+
const BitVector &AffectedRegisters)
224+
: Report(Location), Kind(Kind),
225+
AffectedRegisters(AffectedRegisters.set_bits()) {}
213226

214227
void generateReport(raw_ostream &OS, const BinaryContext &BC) const override;
228+
229+
const ArrayRef<MCPhysReg> getAffectedRegisters() const override {
230+
return AffectedRegisters;
231+
}
232+
233+
void setOverwritingInstrs(const ArrayRef<MCInstReference> Instrs) override {
234+
OverwritingInstrs.assign(Instrs.begin(), Instrs.end());
235+
}
215236
};
216237

217238
/// Report with a free-form message attached.
@@ -224,16 +245,18 @@ struct GenericReport : public Report {
224245
};
225246

226247
struct FunctionAnalysisResult {
227-
SmallSet<MCPhysReg, 1> RegistersAffected;
228248
std::vector<std::shared_ptr<Report>> Diagnostics;
229249
};
230250

231251
class Analysis : public BinaryFunctionPass {
232252
void runOnFunction(BinaryFunction &Function,
233253
MCPlusBuilder::AllocatorIdTy AllocatorId);
234-
FunctionAnalysisResult
235-
computeDfState(PacRetAnalysis &PRA, BinaryFunction &BF,
236-
MCPlusBuilder::AllocatorIdTy AllocatorId);
254+
FunctionAnalysisResult findGadgets(BinaryFunction &BF,
255+
MCPlusBuilder::AllocatorIdTy AllocatorId);
256+
257+
void computeDetailedInfo(BinaryFunction &BF,
258+
MCPlusBuilder::AllocatorIdTy AllocatorId,
259+
FunctionAnalysisResult &Result);
237260

238261
std::map<const BinaryFunction *, FunctionAnalysisResult> AnalysisResults;
239262
std::mutex AnalysisResultsMutex;

bolt/include/bolt/Utils/CommandLineOpts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ extern llvm::cl::opt<unsigned> BucketsPerLine;
3737
extern llvm::cl::opt<bool> DiffOnly;
3838
extern llvm::cl::opt<bool> EnableBAT;
3939
extern llvm::cl::opt<bool> EqualizeBBCounts;
40+
extern llvm::cl::opt<bool> ForcePatch;
4041
extern llvm::cl::opt<bool> RemoveSymtab;
4142
extern llvm::cl::opt<unsigned> ExecutionCountThreshold;
4243
extern llvm::cl::opt<unsigned> HeatmapBlock;

bolt/lib/Passes/PAuthGadgetScanner.cpp

Lines changed: 92 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ class PacRetAnalysis
353353
public:
354354
std::vector<MCInstReference>
355355
getLastClobberingInsts(const MCInst Ret, BinaryFunction &BF,
356-
const BitVector &UsedDirtyRegs) const {
356+
const ArrayRef<MCPhysReg> UsedDirtyRegs) const {
357357
if (RegsToTrackInstsFor.empty())
358358
return {};
359359
auto MaybeState = getStateAt(Ret);
@@ -362,7 +362,7 @@ class PacRetAnalysis
362362
const State &S = *MaybeState;
363363
// Due to aliasing registers, multiple registers may have been tracked.
364364
std::set<const MCInst *> LastWritingInsts;
365-
for (MCPhysReg TrackedReg : UsedDirtyRegs.set_bits()) {
365+
for (MCPhysReg TrackedReg : UsedDirtyRegs) {
366366
for (const MCInst *Inst : lastWritingInsts(S, TrackedReg))
367367
LastWritingInsts.insert(Inst);
368368
}
@@ -376,60 +376,91 @@ class PacRetAnalysis
376376
}
377377
};
378378

379+
static std::shared_ptr<Report>
380+
shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
381+
const State &S) {
382+
static const GadgetKind RetKind("non-protected ret found");
383+
if (!BC.MIB->isReturn(Inst))
384+
return nullptr;
385+
386+
ErrorOr<MCPhysReg> MaybeRetReg = BC.MIB->getRegUsedAsRetDest(Inst);
387+
if (MaybeRetReg.getError()) {
388+
return std::make_shared<GenericReport>(
389+
Inst, "Warning: pac-ret analysis could not analyze this return "
390+
"instruction");
391+
}
392+
MCPhysReg RetReg = *MaybeRetReg;
393+
LLVM_DEBUG({
394+
traceInst(BC, "Found RET inst", Inst);
395+
traceReg(BC, "RetReg", RetReg);
396+
traceReg(BC, "Authenticated reg", BC.MIB->getAuthenticatedReg(Inst));
397+
});
398+
if (BC.MIB->isAuthenticationOfReg(Inst, RetReg))
399+
return nullptr;
400+
BitVector UsedDirtyRegs = S.NonAutClobRegs;
401+
LLVM_DEBUG({ traceRegMask(BC, "NonAutClobRegs at Ret", UsedDirtyRegs); });
402+
UsedDirtyRegs &= BC.MIB->getAliases(RetReg, /*OnlySmaller=*/true);
403+
LLVM_DEBUG({ traceRegMask(BC, "Intersection with RetReg", UsedDirtyRegs); });
404+
if (!UsedDirtyRegs.any())
405+
return nullptr;
406+
407+
return std::make_shared<GadgetReport>(RetKind, Inst, UsedDirtyRegs);
408+
}
409+
379410
FunctionAnalysisResult
380-
Analysis::computeDfState(PacRetAnalysis &PRA, BinaryFunction &BF,
381-
MCPlusBuilder::AllocatorIdTy AllocatorId) {
411+
Analysis::findGadgets(BinaryFunction &BF,
412+
MCPlusBuilder::AllocatorIdTy AllocatorId) {
413+
FunctionAnalysisResult Result;
414+
415+
PacRetAnalysis PRA(BF, AllocatorId, {});
382416
PRA.run();
383417
LLVM_DEBUG({
384418
dbgs() << " After PacRetAnalysis:\n";
385419
BF.dump();
386420
});
387421

388-
FunctionAnalysisResult Result;
389-
// Now scan the CFG for non-authenticating return instructions that use an
390-
// overwritten, non-authenticated register as return address.
391422
BinaryContext &BC = BF.getBinaryContext();
392423
for (BinaryBasicBlock &BB : BF) {
393-
for (int64_t I = BB.size() - 1; I >= 0; --I) {
394-
MCInst &Inst = BB.getInstructionAtIndex(I);
395-
if (BC.MIB->isReturn(Inst)) {
396-
ErrorOr<MCPhysReg> MaybeRetReg = BC.MIB->getRegUsedAsRetDest(Inst);
397-
if (MaybeRetReg.getError()) {
398-
Result.Diagnostics.push_back(std::make_shared<GenericReport>(
399-
MCInstInBBReference(&BB, I),
400-
"Warning: pac-ret analysis could not analyze this return "
401-
"instruction"));
402-
continue;
403-
}
404-
MCPhysReg RetReg = *MaybeRetReg;
405-
LLVM_DEBUG({
406-
traceInst(BC, "Found RET inst", Inst);
407-
traceReg(BC, "RetReg", RetReg);
408-
traceReg(BC, "Authenticated reg", BC.MIB->getAuthenticatedReg(Inst));
409-
});
410-
if (BC.MIB->isAuthenticationOfReg(Inst, RetReg))
411-
break;
412-
BitVector UsedDirtyRegs = PRA.getStateAt(Inst)->NonAutClobRegs;
413-
LLVM_DEBUG(
414-
{ traceRegMask(BC, "NonAutClobRegs at Ret", UsedDirtyRegs); });
415-
UsedDirtyRegs &= BC.MIB->getAliases(RetReg, /*OnlySmaller=*/true);
416-
LLVM_DEBUG(
417-
{ traceRegMask(BC, "Intersection with RetReg", UsedDirtyRegs); });
418-
if (UsedDirtyRegs.any()) {
419-
static const GadgetKind RetKind("non-protected ret found");
420-
// This return instruction needs to be reported
421-
Result.Diagnostics.push_back(std::make_shared<GadgetReport>(
422-
RetKind, MCInstInBBReference(&BB, I),
423-
PRA.getLastClobberingInsts(Inst, BF, UsedDirtyRegs)));
424-
for (MCPhysReg RetRegWithGadget : UsedDirtyRegs.set_bits())
425-
Result.RegistersAffected.insert(RetRegWithGadget);
426-
}
427-
}
424+
for (int64_t I = 0, E = BB.size(); I < E; ++I) {
425+
MCInstReference Inst(&BB, I);
426+
const State &S = *PRA.getStateAt(Inst);
427+
428+
if (auto Report = shouldReportReturnGadget(BC, Inst, S))
429+
Result.Diagnostics.push_back(Report);
428430
}
429431
}
430432
return Result;
431433
}
432434

435+
void Analysis::computeDetailedInfo(BinaryFunction &BF,
436+
MCPlusBuilder::AllocatorIdTy AllocatorId,
437+
FunctionAnalysisResult &Result) {
438+
BinaryContext &BC = BF.getBinaryContext();
439+
440+
// Collect the affected registers across all gadgets found in this function.
441+
SmallSet<MCPhysReg, 4> RegsToTrack;
442+
for (auto Report : Result.Diagnostics)
443+
RegsToTrack.insert_range(Report->getAffectedRegisters());
444+
std::vector<MCPhysReg> RegsToTrackVec(RegsToTrack.begin(), RegsToTrack.end());
445+
446+
// Re-compute the analysis with register tracking.
447+
PacRetAnalysis PRWIA(BF, AllocatorId, RegsToTrackVec);
448+
PRWIA.run();
449+
LLVM_DEBUG({
450+
dbgs() << " After detailed PacRetAnalysis:\n";
451+
BF.dump();
452+
});
453+
454+
// Augment gadget reports.
455+
for (auto Report : Result.Diagnostics) {
456+
LLVM_DEBUG(
457+
{ traceInst(BC, "Attaching clobbering info to", Report->Location); });
458+
(void)BC;
459+
Report->setOverwritingInstrs(PRWIA.getLastClobberingInsts(
460+
Report->Location, BF, Report->getAffectedRegisters()));
461+
}
462+
}
463+
433464
void Analysis::runOnFunction(BinaryFunction &BF,
434465
MCPlusBuilder::AllocatorIdTy AllocatorId) {
435466
LLVM_DEBUG({
@@ -438,27 +469,25 @@ void Analysis::runOnFunction(BinaryFunction &BF,
438469
BF.dump();
439470
});
440471

441-
if (BF.hasCFG()) {
442-
PacRetAnalysis PRA(BF, AllocatorId, {});
443-
FunctionAnalysisResult FAR = computeDfState(PRA, BF, AllocatorId);
444-
if (!FAR.RegistersAffected.empty()) {
445-
// Redo the analysis, but now also track which instructions last wrote
446-
// to any of the registers in RetRegsWithGadgets, so that better
447-
// diagnostics can be produced.
448-
std::vector<MCPhysReg> RegsToTrack;
449-
for (MCPhysReg R : FAR.RegistersAffected)
450-
RegsToTrack.push_back(R);
451-
PacRetAnalysis PRWIA(BF, AllocatorId, RegsToTrack);
452-
FAR = computeDfState(PRWIA, BF, AllocatorId);
453-
}
472+
if (!BF.hasCFG())
473+
return;
454474

455-
// `runOnFunction` is typically getting called from multiple threads in
456-
// parallel. Therefore, use a lock to avoid data races when storing the
457-
// result of the analysis in the `AnalysisResults` map.
458-
{
459-
std::lock_guard<std::mutex> Lock(AnalysisResultsMutex);
460-
AnalysisResults[&BF] = FAR;
461-
}
475+
FunctionAnalysisResult FAR = findGadgets(BF, AllocatorId);
476+
if (FAR.Diagnostics.empty())
477+
return;
478+
479+
// Redo the analysis, but now also track which instructions last wrote
480+
// to any of the registers in RetRegsWithGadgets, so that better
481+
// diagnostics can be produced.
482+
483+
computeDetailedInfo(BF, AllocatorId, FAR);
484+
485+
// `runOnFunction` is typically getting called from multiple threads in
486+
// parallel. Therefore, use a lock to avoid data races when storing the
487+
// result of the analysis in the `AnalysisResults` map.
488+
{
489+
std::lock_guard<std::mutex> Lock(AnalysisResultsMutex);
490+
AnalysisResults[&BF] = FAR;
462491
}
463492
}
464493

@@ -517,7 +546,7 @@ void GadgetReport::generateReport(raw_ostream &OS,
517546
<< " instructions that write to the affected registers after any "
518547
"authentication are:\n";
519548
// Sort by address to ensure output is deterministic.
520-
std::vector<MCInstReference> OI = OverwritingInstrs;
549+
SmallVector<MCInstReference> OI = OverwritingInstrs;
521550
llvm::sort(OI, [](const MCInstReference &A, const MCInstReference &B) {
522551
return A.getAddress() < B.getAddress();
523552
});

0 commit comments

Comments
 (0)